+1 (315) 557-6473 

Contrived Version "Mastermind" Game Armv8 Assembly Language Assignment Solution.


Instructions

Objective

Write a program in ARMv8 assembly language to create a contrived version of the “Mastermind” game.

Requirements and Specifications

Write a assembly language assignment where game is a contrived version of Mastermind: the computer hides a NxM color code chosen fromC colors. The user tries to crack the hidden code by taking several steps. The first step is for the user to make a guess. The computer responds by providing feedback hints. The game ends when the user: 

  1. cracks the game,
  2. reaches a maximum number of trials R without cracking the hidden code, or
  3. choses to quit the game. The game will also end if the timer is exhausted before cracking the code.

Screenshots of output

program to make contrived version of mastermind game in assembly language

Source Code

define(argvr,x19)

define(N,x20)

define(M,x21)

define(C,x22)

define(R,x23)

define(remaining,x24)

define(duration,x25)

define(playerName,x26)

define(guess,x27)

define(try,x28)

define(code,x19)

define(S, d8)

.equ lasttime, 0

.equ win, 8

.equ mode, 12

.equ trhead, 16

.equ transFilename, 24

.equ buffer, 56

.text

helloMsg:     .string "Hello %s!\n"

testGameMsg:     .string "Running Mastermind in test `mode'\n"

playGameMsg:     .string "Running Mastermind in play `mode'\n"

hiddenMsg:      .string "Hidden `code' is: "

startMsg:     .string "\nStart cracking...\n"

usageMsg:      .string "Usage:\n %s name `N' `M' `C' `R' `mode' [`duration']\n" 

invArgsMsg:      .string "Invalid command line argument.\n"

colorFmt:     .string "%c "

hiddenFmt:      .string "- "

hintHeader:     .string "B W `R' `S' T\n"

hintBW:     .string "%-2d %-2d "

hintRST:     .string "%-2d %.2f %d:%02d\n"

newline:     .string "\n"

badInputMsg:     .string "Invalid input. Please `try' again\n"

wonMsg:     .string "Cracked!\n" 

lostMsg:     .string "You lost!\n"

scoreMsg:     .string "Final score: %.2f\n"

showTopMsg:     .string "Show bottom/top scores (B/T/`N')? "

askAgainMsg:     .string "Play again (Y/`N')? "

logFilename:     .string "scores.log"

logWMode:     .string "a"

logRMode:      .string "r"

logFmt:     .string "%-20s %-12.2f %d:%02d\n"

logInf:      .string "%-20s %-12.2f %-12.2f\n"

intFmt:      .string "%d"

promptN:     .string "Number of scores to print?: "

topScoresMsg:     .string "\nTop %d Scores:\n"

botScoresMsg:     .string "\nBottom %d Scores:\n"

scoresHeader:     .string "Name Score Time (s)\n"

transFileFmt:     .string "%s-%d.txt"

transWMode:      .string "wt"

infinity:     .dword 0x7FF0000000000000

.balign 4

.global main

.type main, %function

main:

    stp fp, lr, [sp, -16]!     // save registers in stack

    mov fp, sp

    sub sp, sp, 256      // allocate space for variables

 mov argvr, x1     // save argv pointer in register

    mov duration, 0      // clear duration

    cmp x0, 7      // if n arguments < 7

    blt badArguments      // exit with error

    cmp x0, 8     // compare number of arguments with 8

    blt grabInputs      // if < 8, read inputs

    ldr x0, [argvr, 56]      // load time string from arguments

    bl atoi      // convert to integer

    mov duration,x0      // save in time register

grabInputs:

    ldr playerName, [argvr, 8]      // load player name pointer in register

 ldr x0, [argvr, 16]     // load N string from arguments

 bl atoi      // convert to integer

    uxtw x0, w0      // extend to x0

    mov N, x0      // save in N register

    ldr x0, [argvr, 24]      // load M string from arguments

    bl atoi      // convert to integer

    uxtw x0, w0      // extend to x0

    mov M, x0      // save in M register

    ldr x0, [argvr, 32]     // load C string from arguments

    bl atoi      // convert to integer

    uxtw x0, w0      // extend to x0

    mov C, x0      // save in M register

    ldr x0, [argvr, 40]     // load R string from arguments

    bl atoi      // convert to integer

    uxtw x0, w0      // extend to x0

    mov R, x0      // save in R register

    ldr x0, [argvr, 48]     // load mode string from arguments

    bl atoi     // convert to integer

    str w0, [sp, mode]     // save in mode variable

    cmp C,5      // check if C >= 5

    blt invalidArguments      // if not, print error

    cmp R,1      // check if R >= 1

    blt invalidArguments      // if not, print error

    cmp M,C     // check if M<=C

    bgt invalidArguments     // if not, print error

    ldr w0, [sp, mode]      // load mode

    cmp w0, 0      // check if mode is 0

    blt invalidArguments      // if <0, print error

    cmp w0, 1     // check if mode is 1

    bgt invalidArguments      // if >1, print error

    mov x0,0

    bl time      // Set the time seed for the random number generator

    bl srand     // Call the srand function to initialize seed

    cmp duration, 0     // if no duration was given

    bne continue     // if duration is set, continue

    mov x0, 5     // multiply N by 5

    mul duration, N, x0     // set duration = N*5

continue:

    mul x0, N, M      // multiply n*m

    bl malloc     // allocate space for code

    mov code, x0      // save in code

    mul x0, N, M     // multiply n*m

    bl malloc      // allocate space for guess

    mov guess, x0     // save in guess

gameStart:

    str xzr, [sp, trhead]     // initialize history list to zero

    mov x0, code      // save in code

    mov x1, N     // use N

    mov x2, M     // use M

    mov x3, C     // use colors

    mov x4, guess     // use guess

    bl initializeGame      // generate initial game

    ldr x0, =helloMsg     // load hello message address

    mov x1, playerName     // load player name address

    bl printf      // print the hello message

    ldr w0, [sp, mode]      // load mode

    cmp w0, 0      // check if mode is play

    beq startPlay      // if play, start

    ldr x0, =testGameMsg      // else, print it's a test game

    bl printf

    ldr x0, =hiddenMsg     // print hidden message

    bl printf

    mov x0, code     // load code

    mov x1, N      // use N

    mov x2, M      // use M

    bl printCode      // print initial code

    ldr x0, =newline     // print newline

    bl printf

startPlay:

    bl showScores      // ask if scores should be shown

    ldr x0, =startMsg      // load address of start message

    bl printf     // print start message

    mov x0, 60      // 60 seconds per minute

    mul remaining, duration, x0     // remaining = duration*60

    mov try, 1      // current try

    ucvtf S, xzr      // clear score

    str wzr, [sp, win]      // not winning yet

    mov x0, code     // load code

    mov x1, N     // use N

    mov x2, M      // use M

    add x3, sp, trhead

    bl printHidden      // print hidden hint

gameLoop:

    mov x0, guess     // save in guess

    mov x1, N      // use N

    mov x2, M      // use M

    mov x3, C      // use C

    bl readInput     // read guess from user

    cmp w0, -1     // if exit

    beq dropGame      // drop the game

    cmp w0, 0      // if error

    bne checkGuess      // if no error, check guess

    ldr x0, =badInputMsg      // load address of error message

    bl printf      // print error message

    b gameLoop     // read again

checkGuess:

    mov x0, guess     // load guess

    mov x1, N     // use N

    mov x2, M     // use M

    add x3, sp, trhead

    bl printGuess     // print guess

    mov x0, guess     // pass guess

    mov x1, code     // pass code

    mov x2, N      // pass N

    mov x3, M      // pass M

    add x4, sp, trhead

    bl displayHints      // display the hints

    mul x2, N, M

    cmp x0, x2      // see if guess it's exact

    bne addScore     // if not, add score

    mov w2, 1

    str w2, [sp, win]     // else, set win to 1

addScore:

    ucvtf d0, x0      // convert B to float

    ucvtf d1, x1     // convert W to float

    ucvtf d2, try     // convert R to float

    fmov d3, 2.0     // divide by 2

    fdiv d1, d1, d3     // W/2

    fadd d0, d0, d1      // B+W/2

    fdiv d0, d0, d2     // (B+W/2)/R

    fadd S, S, d0      // add to score

    mov x0, 100     // load 100.0

    ucvtf d1, x0

    fmul S, S, d1      // round to 100

    frinta S, S

    fdiv S, S, d1

    mov x0, xzr

    bl time      // get current time

    uxtw x0, w0

    cmp try, 1      // check if it's the first try

    beq skip      // if so, don't update remaining time

    ldr x1, [sp, lasttime]      // load last time

    sub x1, x0, x1     // time difference

    sub remaining, remaining, x1      // get new remaining time

skip:

    str x0, [sp, lasttime]     // save time as last time

    cmp remaining, 0     // check if remaining is above zero

    bgt getMinSec      // if so, get min :sec

    mov remaining, 0      // else, clear remaining time

getMinSec:

    mov x0, 60     // 60 seconds per minute

    udiv x3, remaining, x0      // remaining/60

    msub x4, x3, x0, remaining     // calculate remainder

    mov x2, try      // load R

    fmov d0, S      // load current score

    add x0, sp, buffer

    ldr x1, =hintRST      // load format to print R, S and T

    bl sprintf      // print R, S and T

    add x0, sp, buffer

    add x1, sp, trhead

    bl saveString     // print R, S, T

    ldr w0, [sp, win]      // load win status

    cmp w0, 1      // if win

    beq gameCracked      // end game

    cmp remaining, 0     // if no time

    beq gameLost      // end game

    add try, try, 1      // increment number of tries

    cmp try, R     // compare with maximum tries

    ble gameLoop     // repeat game loop if <= max tries

gameLost:

    ldr x0, =lostMsg     // print lost message

    bl printf

    fmov d0, S      // get current score

    mov x0, try      // get try

    mov x1, remaining      // get remaining time

    bl calculateScore      // get last score

    fneg d8, d0      // convert to negative

    b printScore

gameCracked:

    ldr x0, =wonMsg      // print won message

    bl printf

    fmov d0, S      // get current score

    mov x0, try     // get try

    mov x1, remaining     // get remaining time

    bl calculateScore     // get last score

    fmov d8, d0      // save score

printScore:

    ldr x0, =scoreMsg     // print score message

    fmov d0, d8

    bl printf

    mov x0, playerName     // load player name

    fmov d0, d8      // load score

    ucvtf d1, remaining     // convert remaining to float

    bl logScore

    mov x0, xzr

    bl time      // get current time

    mov w3, w0

    add x0, sp, transFilename

    ldr x1, =transFileFmt     //  mov x2, playerName

    bl sprintf

    add x0, sp, transFilename

    add x1, sp, trhead

    bl transcriptGame     // save the transcript

    add x0, sp, trhead

    bl freeTranscript      // free the transcript

    bl showScores     // show scores

    ldr x0, =askAgainMsg     // ask if new game should be started

    bl printf

    bl readChar     // read input

    cmp w0, 'Y'      // if new game

    beq gameStart     // restart

    cmp w0, 'y'      // if new game

    beq gameStart     // restart

    b endGame     // end game

dropGame:

    mov x0, playerName      // load player name

    ldr x1, =infinity

    ldr d1, [x1]      // load time +inf

    fmov d0, d1      // load score -inf

    fneg d0, d0

    bl logScore

endGame:

    mov x0, code     // free allocated space for code

    mov x1, guess     // free allocated space for guess

    bl exitGame      // exit game

badArguments:

    ldr x0, =usageMsg      // print usage message

    ldr x1, [argvr]     // load first argument (program name)

    bl printf

    b terminate     // terminate program

invalidArguments:

    ldr x0, =invArgsMsg      // print error message

    bl printf

terminate:

    mov sp, fp     // restore stack pointer

    ldp fp, lr, [sp], 16      // restore registers from stack

    ret      // return to os

// Initialize the game

// void initializeGame (*code, N, M, C, *guess)

.type initializeGame, %function

initializeGame:

    stp fp, lr, [sp, -16]!     // save registers in stack

    stp x19, x20, [sp, -16]!     // save registers in stack

    stp x21, x22, [sp, -16]!     // save registers in stack

    stp x23, x24, [sp, -16]!     // save registers in stack

    mov x19, x0      // save code pointer

    mov x22, x4     // save guess pointer

    sub x20, x3, 1     // save C - 1

    mul w21, w1, w2     // get number of characters= n*m

    mov w23, w21

initLoop:

    mov w0, 0      // generate number between 0

    mov w1, w20      // and C - 1

    mov w2, 0     // positive

    bl randomNum     // generate random number

    bl Color     // convert to color

    strb w0, [x19], 1      // save in color array

    subs w21, w21, 1     // decrement number of chars to generate

    bne initLoop      // repeat while not zero

    mov w21, w23      // get number of characters

clrLoop:

    mov w0, 32     // save space

    strb w0, [x22], 1     // save in color array

    subs w21, w21, 1      // decrement number of chars

    bne clrLoop      // repeat while not zero

    ldp x23, x24, [sp], 16     // restore registers from stack

    ldp x21, x22, [sp], 16     // restore registers from stack

    ldp x19, x20, [sp], 16     // restore registers from stack

    ldp fp, lr, [sp], 16      // restore registers from stack

    ret      // return to calling function

// Generate a random number between n and m, the number is negative if neg is 1

// int randomNum(n, m, neg)

.type randomNum, %function

randomNum:

    stp fp, lr, [sp, -16]!      // save registers in stack

    stp x19, x20, [sp, -16]!      // save registers in stack

    stp x21, x22, [sp, -16]!     // save registers in stack

    mov x19, x0      // save n

    mov x20, x1     // save m

    mov x21, x2      // save neg

    bl rand     // generate a random number

    sub w1, w20, w19     // calculate m-n

    add w1, w1, 1     // calculate m-n+1

    udiv w2, w0, w1     // divide random number / (m-n+1)

    msub w3, w2, w1, w0     // calculate remainder

    add w0, w3, w19     // add n to get number between n and m (including n and m)

    cmp x21, 0     // check if need a negative

    beq rndReturn      // if not negative, return

    neg w0, w0     // else, negate

rndReturn:

    ldp x21, x22, [sp], 16     // restore registers from stack

    ldp x19, x20, [sp], 16     // restore registers from stack

    ldp fp, lr, [sp], 16      // restore registers from stack

    ret      // return to calling function

// Convert number to letter color

// char Color(n)

.type Color, %function

Color:

    add w0, w0, 65      // convert 0... to 'A'...

    ret      // return to calling function

// Print code

// void printCode(*code, n, m)

.type printCode, %function

printCode:

    stp fp, lr, [sp, -16]!      // save registers in stack

    stp x19, x20, [sp, -16]!     // save registers in stack

    mov x19, x0      // save code pointer

    mul w20, w1, w2     // get number of characters= n*m

prLoop:

    ldrb w1, [x19], 1     // load char from color array

    ldr x0, =colorFmt     // print color

    bl printf

    subs w20, w20, 1      // decrement number of chars to print

    bne prLoop     // repeat while not zero

    ldp x19, x20, [sp], 16     // restore registers from stack

    ldp fp, lr, [sp], 16      // restore registers from stack

    ret      // return to calling function

// Print guess

// void printGuess(*code, n, m, transcript)

.type printGuess, %function

printGuess:

    stp fp, lr, [sp, -16]!      // save registers in stack

    stp x19, x20, [sp, -16]!      // save registers in stack

    stp x21, x22, [sp, -16]!     // save registers in stack

    mov fp, sp

    sub sp, sp, 256     // allocate buffer

    mov x19, x0     // save code pointer

    mov x21, x3     // save transcript

    mov x22, sp

    mul w20, w1, w2 // get number of characters= n*m

prgLoop:

    ldrb w1, [x19], 1      // load char from color array

    //ldr x0, =colorFmt      // print color

    //bl printf

    strb w1, [x22], 1

    mov w1, 32

    strb w1, [x22], 1

    subs w20, w20, 1     // decrement number of chars to print

    bne prgLoop      // repeat while not zero

    strb wzr, [x22], 1

    mov x0, sp

    mov x1, x21

    bl saveString      // save in transcript

    mov sp, fp

    ldp x21, x22, [sp], 16      // restore registers from stack

    ldp x19, x20, [sp], 16      // restore registers from stack

    ldp fp, lr, [sp], 16     // restore registers from stack

    ret // return to calling function

// Print hidden code

// void printHidden(*code, n, m, *transcript)

.type printHidden, %function

printHidden:

    stp fp, lr, [sp, -16]!      // save registers in stack

    stp x19, x20, [sp, -16]!      // save registers in stack

    stp x21, x22, [sp, -16]! // save registers in stack

    mov fp, sp

    sub sp, sp, 256     // allocate buffer

    strb wzr, [sp]

    mov x19, x0      // save code pointer

    mov x21, x3      // save transcript

    mul w20, w1, w2      // get number of characters= n*m

phLoop:

    mov x0, sp

    ldr x1, =hiddenFmt     // print hidden char

    bl strcat

    subs w20, w20, 1     // decrement number of chars to print

    bne phLoop      // repeat while not zero

    mov x0, sp

    ldr x1, =hintHeader      // print hint header

    bl strcat

    mov x0, sp

    mov x1, x21

    bl saveString      // save in transcript

    mov sp, fp

    ldp x21, x22, [sp], 16      // restore registers from stack

    ldp x19, x20, [sp], 16     // restore registers from stack

    ldp fp, lr, [sp], 16     // restore registers from stack

    ret // return to calling function

// Read the input from the user, returns 1 if no errors, -1 if user wants to exit

// bool readInput(*input, N, M, C)

.type readInput, %function

readInput:

    stp fp, lr, [sp, -16]!      // save registers in stack

    stp x19, x20, [sp, -16]!      // save registers in stack

    stp x21, x22, [sp, -16]!     // save registers in stack

    mov x19, x0      // save input array pointer

    mul w20, w1, w2     // get number of characters= n*m

    add w21, w3, 64      // last color char

    mov x22, 1     // no errors

rdLoop:

    bl getchar     // read character

    cmp w0, 10     // if enter

    beq readEnd

    cmp w0, '$'      // if exit

    beq exitChar

    cmp w0, 32     // if space

    beq rdLoop      // read again

    cmp w0, 'A'      // if not a letter

    blt badChar      //

    cmp w0, w21     // if not a letter

    bgt badChar //

    cmp w20, 0      // if we input all chars

    beq badChar

    strb w0, [x19], 1     // save in array

    sub w20, w20, 1      // decrement number of chars to save

    b rdLoop      // read again

exitChar:

    mov x22, -1

    b rdLoop      // repeat

badChar:

    cmp x22, -1     // if exit

    beq rdLoop      // ignore error

    mov x22, 0      // input error

    b rdLoop     // repeat

readEnd:

    cmp x22, -1      // if exit

    beq readRet      // ignore errors

    cmp w20, 0      // else, check if all chars were given

    beq readRet      // if so, return

    mov x22, 0      // else, error

readRet:

    mov x0, x22     // return error status

    ldp x21, x22, [sp], 16      // restore registers from stack

    ldp x19, x20, [sp], 16     // restore registers from stack

    ldp fp, lr, [sp], 16     // restore registers from stack

    ret // return to calling function

// display hints and returns B,W

// int displayHints(guess, code, n, m, transcript)

.type displayHints, %function

displayHints:

    stp fp, lr, [sp, -16]!      // save registers in stack

    stp x19, x20, [sp, -16]!      // save registers in stack

    stp x21, x22, [sp, -16]!     // save registers in stack

    stp x23, x24, [sp, -16]!      // save registers in stack

    mov fp, sp

    mov x19, 0      // no exact matches

    mov x20, 0      // no approx matches

    mov x23, x4     // save transcript

    mul x4, x2, x3     // get number of characters= n*m

    sub sp, sp, x4      // allocate first array

    mov x21, sp     // point to stack

    sub sp, sp, x4     // allocate second array

    mov x22, sp      // point to stack

    mov x5, 0      // index = 0

comp1:

    ldrb w6, [x0, x5]      // load guess character

    ldrb w7, [x1, x5]      // load code character

    cmp w6, w7      // compare chars

    bne notEq

    add x19, x19, 1      // increment exact matches

    mov w6, 1

    strb w6, [x21, x5]     // save guess character used

    strb w6, [x22, x5]      // save code character used

    b nxtComp1

notEq:

    strb wzr, [x21, x5]      // save guess character not used

    strb wzr, [x22, x5]      // save code character not used

nxtComp1:

    add x5, x5, 1      // increment index

    cmp x5, x4      // if not end

    blt comp1     // keep comparing

    mov x5, 0      // index guess = 0

comp2:

    ldrb w6, [x21, x5]      // check if guess character was used

    cmp w6, 0     // if used,

    bne nxtComp2     // try next

    ldrb w6, [x0, x5]      // load guess character

    mov x7, 0      // index code = 0

comp3:

    ldrb w9, [x22, x7]      // check if code character was used

    cmp w9, 0     // if used,

    bne nxtComp3      // try next

    ldrb w9, [x1, x7]      // load code character

    cmp w6, w9      // compare chars

    bne nxtComp3     // if not equal, try next code char

    add x20, x20, 1     // increment approx matches

    mov w6, 1

    strb w6, [x21, x5]     // save guess character used

    strb w6, [x22, x7]     // save code character used

    b nxtComp2

nxtComp3:

    add x7, x7, 1     // increment index

    cmp x7, x4      // if not end

    bne comp3     // keep comparing

nxtComp2:

    add x5, x5, 1     // increment index

    cmp x5, x4      // if not end

    bne comp2     // keep comparing

endit:

    add sp, sp, x4, lsl 1     // remove allocated space in stack

    sub sp, sp, 16

    mov x0, sp

    ldr x1, =hintBW      // load hint b w format

    mov w2, w19     // load exact matches

    mov w3, w20      // load approximate matches

    bl sprintf      // print result

    mov x0, sp

    mov x1, x23

    bl saveString     // save hints

    add sp, sp, 16

    mov x0, x19      // return exact matches

    mov x1, x20     // return approximate matches

    ldp x23, x24, [sp], 16     // restore registers from stack

    ldp x21, x22, [sp], 16     // restore registers from stack

    ldp x19, x20, [sp], 16     // restore registers from stack

    ldp fp, lr, [sp], 16     // restore registers from stack

    ret // return to calling function

// Calculate overall score

// double calculateScore(S, R, T)

.type calculateScore, %function

calculateScore:

    ucvtf d1, x0     // convert tries to float

    fdiv d0, d0, d1      // S/R

    mov x2, 1000     // multiply remaining time T * 1000

    mul x1, x1, x2

    ucvtf d2, x1      // convert remaining seconds to float

    fmul d0, d0, d2     // (S/R)*T*1000

    mov x0, 100     // load 100

    ucvtf d1, x0      // counvert to float

    fmul d0, d0, d1     // round to 100

    frinta d0, d0

    fdiv d0, d0, d1

    ret // return to calling function

// Exit the game

// void exitGame(*code, *game)

.type exitGame, %function

exitGame:

    stp fp, lr, [sp, -16]!      // save registers in stack

    stp x19, x20, [sp, -16]!      // save registers in stack

    mov x19, x1

    bl free      // free allocated space for code

    mov x0, x19      // free allocated space for guess

    bl free

    ldp x19, x20, [sp], 16      // restore registers from stack

    ldp fp, lr, [sp], 16     // restore registers from stack

    mov x0, xzr      // exit (0)

    bl exit

// Log the score

// void logScore(name, score, T)

.type logScore, %function

logScore:

    stp fp, lr, [sp, -16]!      // save registers in stack

    stp x19, x20, [sp, -16]!      // save registers in stack

    stp d8, d9, [sp, -16]!      // save registers in stack

    sub sp, sp, 32

    mov x19, x0     // save name pointer

    fmov d8, d0      // save score

    fmov d9, d1      // save T

    ldr x0, =logFilename      // open file

    ldr x1, =logWMode      // mode to append

    bl fopen

    mov x20, x0      // save file pointer

    mov x0, sp      // clear buffer

    mov x1, xzr

    mov x2, 16

    bl memset

    mov x0, sp

    mov x1, x19      // copy name

    mov x2, 16

    bl strncpy

    mov x0, sp      // save name

    mov x1, 1

    mov x2, 16

    mov x3, x20

    bl fwrite

    stp d8, d9, [sp, -16]!     // save registers in stack

    mov x0, sp     // save score

    mov x1, 1

    mov x2, 8

    mov x3, x20

    bl fwrite

    add x0, sp, 8      // save time

    mov x1, 1

    mov x2, 8

    mov x3, x20

    bl fwrite

    ldp d8, d9, [sp], 16      // restore registers from stack

    mov x0, x20     // close file

    bl fclose

    add sp, sp, 32

    ldp d8, d9, [sp], 16     // restore registers from stack

    ldp x19, x20, [sp], 16      // restore registers from stack

    ldp fp, lr, [sp], 16     // restore registers from stack

    ret

// Load score file and returns array and array size

// scores* loadScores()

.type loadScores, %function

loadScores:

    stp fp, lr, [sp, -16]!     // save registers in stack

    stp x19, x20, [sp, -16]!     // save registers in stack

    stp x21, x22, [sp, -16]!     // save registers in stack

    ldr x0, =logFilename     // open file

    ldr x1, =logRMode     // mode to read

    bl fopen

    mov x19, x0     // save file pointer

    mov x1, 0      // move to end of file

    mov x2, 2

    bl fseek

    mov x0, x19     // get file size

    bl ftell

    uxtw x0, w0

    mov x20, x0      // save size

    mov x0, x20

    bl malloc     // allocate space for whole file

    mov x21, x0

    mov x0, x19      // move to start of file

    mov x1, xzr

    mov x2, xzr

    bl fseek

    mov x0, x21     // load all scores

    mov x1, 1

    mov x2, x20

    mov x3, x19

    bl fread

    mov x0, x19      // close the file

    bl fclose

    mov x0, x21      // return array

    lsr x1, x20, 5     // return number of scores

    ldp x21, x22, [sp], 16      // restore registers from stack

    ldp x19, x20, [sp], 16      // restore registers from stack

    ldp fp, lr, [sp], 16      // restore registers from stack

    ret

// Display the top n scores on score file

.type displayTop, %function

displayTop:

    stp fp, lr, [sp, -16]!      // save registers in stack

    stp x19, x20, [sp, -16]!     // save registers in stack

    stp x21, x22, [sp, -16]!      // save registers in stack

    mov x19, x0      // save n

    ldr x0, =topScoresMsg     // print top scores message

    mov x1, x19

    bl printf

    ldr x0, =scoresHeader      // print header

    bl printf

    bl loadScores      // load all scores

    mov x20, x0      // save array

    mov x21, x1      // save size

    mov x22, x0

    mov x0, x20

    mov x1, x21

    mov x2, 1     // sort inverted (top at bottom)

    bl sortScores      // sort scores

printTop:

    ldr d0, [x20, 24]      // load time

    bl isinf     // check if it's infinite

    cmp w0, 0     // if not infinite

    beq prScore      // print score

    ldr x0, =logInf

    mov x1, x20      // print name

    ldr d0, [x20, 16]      // load score

    ldr d1, [x20, 24]     // load time

    bl printf     // print entry

    b nextTop

prScore:

    ldr d0, [x20, 24]     // load time

    fcvtas x1, d0     // convert to integer

    mov x0, 60      // 60 seconds per minute

    udiv x2, x1, x0      // t/60

    msub x3, x2, x0, x1      // calculate remainder

    ldr x0, =logFmt

    mov x1, x20      // print name

    ldr d0, [x20, 16]      // load score

    bl printf      // print entry

nextTop:

    add x20, x20, 32      // advance to next entry

    subs x19, x19, 1     // decrement n

    beq endTop

    subs x21, x21, 1      // decrement size

    bne printTop

endTop:

    mov x0, x22 // free array

    bl free

    ldp x21, x22, [sp], 16     // restore registers from stack

    ldp x19, x20, [sp], 16      // restore registers from stack

    ldp fp, lr, [sp], 16      // restore registers from stack

    ret

// Display the bottom n scores on score file

.type displayBottom, %function

displayBottom:

    stp fp, lr, [sp, -16]!      // save registers in stack

    stp x19, x20, [sp, -16]!      // save registers in stack

    stp x21, x22, [sp, -16]!      // save registers in stack

    mov x19, x0     // save n

    ldr x0, =botScoresMsg

    mov x1, x19

    bl printf

    ldr x0, =scoresHeader     // print header

    bl printf

    bl loadScores      // load all scores

    mov x20, x0      // save array

    mov x21, x1      // save size

    mov x22, x0

    mov x0, x20

    mov x1, x21

    mov x2, 0     // sort normally (smallest at bottom)

    bl sortScores     // sort scores

printBot:

    ldr d0, [x20, 24]     // load time

    bl isinf      // check if it's infinite

    cmp w0, 0      // if infinite

    bne nextBot     // go to next value

    ldr d0, [x20, 24]     // load time

    fcvtas x1, d0      // convert to integer

    mov x0, 60     // 60 seconds per minute

    udiv x2, x1, x0      // t/60

    msub x3, x2, x0, x1      // calculate remainder

    ldr x0, =logFmt

    mov x1, x20      // print name

    ldr d0, [x20, 16]      // load score

    bl printf     // print entry

    subs x19, x19, 1      // decrement n

    beq endBot

nextBot:

    add x20, x20, 32      // advance to next entry

    subs x21, x21, 1      // decrement size

    bne printBot

endBot:

    mov x0, x22      // free array

    bl free

    ldp x21, x22, [sp], 16     // restore registers from stack

    ldp x19, x20, [sp], 16     // restore registers from stack

    ldp fp, lr, [sp], 16      // restore registers from stack

    ret

// Sort the score array in the given direction

// void sortScores(*scores, N, direction)

.type sortScores, %function

sortScores:

    stp fp, lr, [sp, -16]!     // save registers in stack

    sub x1, x1, 1      // decrement to N-1

    mov x7, 0     // i = 0

for1:

    cmp x7, x1      // for (i = 0; i < N - 1; i++)

    beq endfor1

    add x5, x0, x7, lsl 5      // array entry i

    ldr d0, [x5, 16]     // load array[i].score

    mov x3, x7      // min = i

    add x4, x7, 1     // j = i + 1;

for2:

    cmp x4, x1     // for (j = i + 1; j <= N - 1; j++)

    bgt endfor2

    add x6, x0, x4, lsl 5     // array entry j

    ldr d1, [x6, 16]     // load array[j].score

    cmp x2, 0     // if normal direction

    bne invert

    fcmp d1, d0     // if (score j < score min)

    bge nextj

    fmov d0, d1      // set score as new minimum

    mov x3, x4      // save j as min

    b nextj

invert:

    fcmp d1, d0      // if (score j > score min)

    ble nextj

    fmov d0, d1     // set score as new maximum

    mov x3, x4      // save j as max

nextj:

    add x4, x4, 1     // j++

    b for2      // repeat for

endfor2:

    add x5, x0, x7, lsl 5     // array entry i

    add x6, x0, x3, lsl 5     // array entry min

    ldr x3, [x5]      // load array[i].name

    ldr x4, [x6]     // load array[min].name

    str x4, [x5]      // swap

    str x3, [x6]

    ldr x3, [x5, 8]     // load array[i].name

    ldr x4, [x6, 8]     // load array[min].name

    str x4, [x5, 8]      // swap

    str x3, [x6, 8]

    ldr x3, [x5, 16]     // load array[i].score

    ldr x4, [x6, 16]      // load array[min].score

    str x4, [x5, 16]     // swap

    str x3, [x6, 16]

    ldr x3, [x5, 24]     // load array[i].time

    ldr x4, [x6, 24]      // load array[min].time

    str x4, [x5, 24]      // swap

    str x3, [x6, 24]

    add x7, x7, 1      // i++

    b for1      // repeat for

endfor1:

    ldp fp, lr, [sp], 16      // restore registers from stack

    ret

// Read N from user

.type readN, %function

readN:

    stp fp, lr, [sp, -16]!     // save registers in stack

    sub sp, sp, 16      // allocate space in stack

    ldr x0, =promptN      // prompt for n

    bl printf

    ldr x0, =intFmt      // read an integer

    mov x1, sp

    bl scanf

lN:

    bl getchar      // read until enter is pressed

    cmp w0, 10

    bne lN

    ldr w0, [sp]      // get read value

    uxtw x0, w0     // extend to x0

    add sp, sp, 16     // remove allocated space

    ldp fp, lr, [sp], 16      // restore registers from stack

    ret // return to caller

// Reads a character from input

// char readChar()

.type readChar, %function

readChar:

    stp fp, lr, [sp, -16]!      // save registers in stack

    stp x19, x20, [sp, -16]!      // save registers in stack

    bl getchar     // read input

    mov w19, w0      // save char

l0:

    cmp w0, 10      // if enter, end input

    beq rdChrEnd

    bl getchar     // read until enter is pressed

    b l0

rdChrEnd:

    mov w0, w19      // return read char

    uxtb x0, w0     // extend to x0

    ldp x19, x20, [sp], 16     // restore registers from stack

    ldp fp, lr, [sp], 16     // restore registers from stack

    ret

// Show the scores depending on user input

// void showScores()

.type showScores, %function

showScores:

    stp fp, lr, [sp, -16]!      // save registers in stack

    ldr x0, =showTopMsg      // ask if top/bottom should be printed

    bl printf

    bl readChar      // read input

    cmp w0, 'B'      // if bottom

    beq showBottom     // print bottom

    cmp w0, 'b'      // if bottom

    beq showBottom      // print bottom

    cmp w0, 'T'      // if top

    beq showTop     // print top

    cmp w0, 't'      // if top

    beq showTop     // print top

    b showEnd     // else, end

showBottom:

    bl readN      // read N value

    bl displayBottom     // displayBotton(n)

    b showEnd

showTop:

    bl readN      // read N value

    bl displayTop      // displayTop(n)

showEnd:

    ldp fp, lr, [sp], 16      // restore registers from stack

    ret

// Save transcript file

// void transcriptGame(*filename, *transcript)

.type transcriptGame, %function

transcriptGame:

    stp fp, lr, [sp, -16]!      // save registers in stack

    stp x19, x20, [sp, -16]!     // save registers in stack

    mov x19, x1 // save transcript pointer

    ldr x1, =transWMode      // create transcript file

    bl fopen

    mov x20, x0     // save file pointer

    ldr x19, [x19]      // load transcript head

saveLoop:

    cmp x19, 0      // if end of transcript

    beq endTrans      // end loop

    mov x0, x20      // load file pointer

    ldr x1, [x19]      // pass string pointer

    bl fprintf      // print to file

    ldr x19, [x19, 8]      // load next transcript

    b saveLoop

endTrans:

    mov x0, x20      // close file

    bl fclose

    ldp x19, x20, [sp], 16     // restore registers from stack

    ldp fp, lr, [sp], 16      // restore registers from stack

    ret

// Free transcript

// void freeTranscript(*transcript)

.type freeTranscript, %function

freeTranscript:

    stp fp, lr, [sp, -16]!     // save registers in stack

    stp x19, x20, [sp, -16]!     // save registers in stack

    ldr x20, [x0]     // load transcript head

freeLoop:

    cmp x20, 0      // if end of transcript

    beq endFree     // end loop

    ldr x0, [x20]     // pass string pointer

    bl free      // free string

    ldr x19, [x20, 8]      // load next transcript

    mov x0, x20      // pass node pointer

    bl free     // free node

    mov x20, x19     // use next node for iteration

    b freeLoop

endFree:

    ldp x19, x20, [sp], 16     // restore registers from stack

    ldp fp, lr, [sp], 16     // restore registers from stack

    ret

// Insert string to end of transcript and prints it:

// void saveString(*string, *transcript)

saveString:

    stp fp, lr, [sp, -16]!      // save registers in stack

    stp x19, x20, [sp, -16]!      // save registers in stack

    stp x21, x22, [sp, -16]!      // save registers in stack

    mov x19, x0     // save string pointer

    mov x20, x1      // save transcript pointer

    mov x0, x19      // print string

    bl printf

    mov x0, 16      // node size

    bl malloc      // allocate node

    mov x21, x0      // save node pointer

    mov x0, x19     // pass string

    bl strlen      // get length

    add x0, x0, 1

    bl malloc      // allocate string

    mov x22, x0      // save pointer

    mov x0, x22      // copy string

    mov x1, x19

    bl strcpy

    str x22, [x21]      // save string pointer in node

    str xzr, [x21, 8]      // save next as null

    ldr x0, [x20]      // load transcript head

    cmp x0, 0      // if empty list

    bne findLast      // if not, insert at last

    str x21, [x20]      // save new node as head

    b insertEnd

findLast:

    ldr x1, [x0, 8]      // load next transcript

    cmp x1, 0     // if null

    beq saveNode     // end loop

    mov x0, x1     // go to next

    b findLast

saveNode:

    str x21, [x0, 8]      // save new node as last

insertEnd:

    ldp x21, x22, [sp], 16      // restore registers from stack

    ldp x19, x20, [sp], 16     // restore registers from stack

    ldp fp, lr, [sp], 16      // restore registers from stack

    ret

define(code,x19)