# Drivers: SortDrivers

```       Name: SortDrivers                                             [Show more]
Type: Subroutine
Category: Drivers
Summary: Create a sorted list of driver numbers, ordered as specified
Context: See this subroutine in context in the source code
References: This subroutine is called as follows:
* MainLoop (Part 3 of 6) calls SortDrivers
* MainLoop (Part 4 of 6) calls SortDrivers
* MainLoop (Part 6 of 6) calls SortDrivers

This routine sorts the driver list in driversInOrder according to the value
specified by argument A. It also populates carStatus with the position
numbers for the sorted driver list, which will typically run from 0 to 19,
but may also contain repeated numbers in the case of a tie.

The routine uses a basic bubble sort algorithm, swapping neighbouring drivers
repeatedly until the whole list is sorted. This is not very efficient, but as
this is only done when showing the driver table between races, that doesn't
matter.

Arguments:

A                    Determines the order of the sorted list to create:

* 0 = best lap times

* Bit 6 set = accumulated points

* Bit 7 set = total race times

Returns:

positionNumber       A list of position numbers, from 0 to 19, ready to print
in the first column of the driver table (with 1 added),
with drivers who are tied in the same position sharing
the same number

driversInOrder       A list of driver numbers, sorted according to the value
specified by argument A

.SortDrivers

STA G                  \ Store A in G

SED                    \ Set the D flag to switch arithmetic to Binary Coded
\ Decimal (BCD)

.sort1

LDX #0                 \ Set V = 0, which we will use to indicate whether the
STX V                  \ driversInOrder list is sorted
\
\ We start at 0 to indicate it is sorted, and change it
\ if we have to reorder the list

STX positionNumber     \ Set the first entry in positionNumber to 0, as the
\ winning driver will always be in position 0

INX                    \ Set X = 1 as a position counter, counting through 1 to
\ 19, which denotes the position number that we are
\ processing in this iteration of the loop (we skip the
\ first position as we already set it)

.sort2

STX W                  \ Store the position counter in W

LDY driversInOrder,X   \ Set Y to the number of the driver at position X in the
\ driversInOrder list ("this driver")

TXA                    \ Set the X-th entry in positionNumber to the position
STA positionNumber,X   \ counter (as the X-th driver is in position X)

LDA driversInOrder-1,X \ Set X to the number of the driver at position X - 1 in
TAX                    \ the driversInOrder list ("the driver ahead")

SEC                    \ Set the C flag for the subtractions below

BIT G                  \ If bit 6 of G is set, jump to sort5 to compare total
BVS sort5              \ points

BMI sort6              \ If bit 7 of G is set, jump to sort6 to compare best
\ lap times

\ If we get here then bit 6 and 7 of G are clear, so we
\ compare most recent lap times

LDA bestLapTenths,Y    \ Set (A H U) =   this driver's best lap time
SBC bestLapTenths,X    \               - best lap time of the driver ahead
STA U                  \
\ starting with the tenths of a second

LDA bestLapSeconds,Y   \ Then the seconds
SBC bestLapSeconds,X
STA H

LDA bestLapMinutes,Y   \ And then the minutes
SBC bestLapMinutes,X

BCC sort7              \ If the subtraction underflowed, then this driver's
\ lap time is quicker than the lap time of the driver
\ ahead, which is the wrong way round if we are trying
\ to create a list where the winner has the fastest lap
\ time, so jump to sort7 to swap them around in the
\ driversInOrder list

.sort3

ORA U                  \ At this point (A H U) contains the difference between
ORA H                  \ the two drivers' times/points, so this jumps to sort4
BNE sort4              \ if any of the bytes in (A U H) are non-zero, i.e. if
\ the two drivers have different times/points

LDX W                  \ The two drivers have identical times/points, so set
DEX                    \ we need to set the current driver's position number to
LDA positionNumber,X   \ be the same as the position number of the driver ahead
STA positionNumber+1,X \ as there is a tie

.sort4

\ If we get here then we move on to the next position

LDX W                  \ Fetch the position counter that we stored in W above

INX                    \ Increment the position counter to the next position

CPX #20                \ Loop back until we have gone through the whole table
BCC sort2              \ of 20 positions

LDA V                  \ If V <> 0 then we had to alter the order of the
BNE sort1              \ driversInOrder list, as it wasn't fully sorted, so
\ we jump back to sort1 to repeat the whole process as
\ we don't yet know that the list is fully sorted

CLD                    \ Otherwise the driversInOrder list is sorted, so clear
\ the D flag to switch arithmetic to normal

JSR SetPlayerPositions \ Set the current player's position, plus the position
\ ahead and the position behind

RTS                    \ Return from the subroutine

.sort5

LDA totalPointsLo,X    \ Set (A H U) =   total points of the driver ahead
SBC totalPointsLo,Y    \               - this driver's total points
STA U                  \
\ starting with the low bytes

LDA totalPointsHi,X    \ Then the high bytes
SBC totalPointsHi,Y
STA H

LDA totalPointsTop,X   \ And then the top bytes
SBC totalPointsTop,Y

BCC sort7              \ If the subtraction underflowed, then this driver has
\ more points than the driver ahead, which is the wrong
\ way round if we are trying to create a list where the
\ winner has the most points, so jump to sort7 to swap
\ them around in the driversInOrder list

BCS sort3              \ Jump to sort3 to check for a tie and move on to the
\ next position (this BCS is effectively a JMP as we
\ just passed through a BCC)

.sort6

LDA totalRaceTenths,Y  \ Set (A H U) =   this driver's total race time
SBC totalRaceTenths,X  \               - total race time of the driver ahead
STA U                  \
\ starting with the tenths of a second

LDA totalRaceSeconds,Y \ Then the seconds
SBC totalRaceSeconds,X
STA H

LDA totalRaceMinutes,Y \ And then the minutes
SBC totalRaceMinutes,X

BCS sort4              \ If the subtraction didn't underflow then the drivers
\ are in the correct order, so jump to sort4 to move on
\ to the next position

\ Otherwise the subtraction underflowed, so this
\ driver's total race time is quicker than the total
\ race time of the driver ahead, which is the wrong way
\ round if we are trying to create a list where the
\ winner has the fastest time, so fall through into
\ sort7 to swap them around in the driversInOrder list

.sort7

\ If we get here then the two drivers we are comparing
\ are in the wrong order in the driversInOrder list, so
\ we need to swap them round
\
\ At this point X contains the number of the driver
\ ahead and Y contains the number of this driver

STX T                  \ Store the number of the driver ahead in T

LDX W                  \ Set X to the position counter

TYA                    \ Set A to the number of this driver

STA driversInOrder-1,X \ Set the number of the driver ahead (i.e. the position
\ before the one we are processing) to A (i.e. the
\ number of this driver)

LDA T                  \ Set the number of this driver (i.e. the current
STA driversInOrder,X   \ position) to T (i.e. the number of the driver ahead)

DEC V                  \ Decrement V so that is it non-zero, to indicate that
\ we had to swap an entry in the driversInOrder list

JMP sort4              \ Jump to sort4 to move on to the next position
```