Skip to content

Instantly share code, notes, and snippets.

@subnomo
Last active September 12, 2023 01:49
Show Gist options
  • Save subnomo/019e987492e10bfcd27e586e9b8f7f1c to your computer and use it in GitHub Desktop.
Save subnomo/019e987492e10bfcd27e586e9b8f7f1c to your computer and use it in GitHub Desktop.
TITLE Combinations Calculator (final.asm)
; Author: Alexander Taylor
; CS 271 Sec. 1 / Program 6B Date: 12/04/16
; Description: This program generates practice combinations problems.
; It takes user input for each problem, and tells the user
; the answer, as well as if they were right or wrong. Finally,
; it implements extra credit #1 by keeping track of each answer,
; and tallying up the number of right and wrong at the end.
INCLUDE Irvine32.inc
; Constants
lo_n = 3
hi_n = 12
lo_r = 1
.data
intromsg BYTE "Welcome to the Combinations Calculator",0
authormsg BYTE "Programmed by Alexander Taylor",0
instructions BYTE "I'll give you a combinations problem. You enter ",
"your answer,",13,10,"and I'll let you know if you're right.",0
ec BYTE "**EC: Each problem is numbered and a score is kept to be",13,10,
"shown at the end.",0
n DWORD ?
r DWORD ?
nmsg BYTE "Number of elements in the set: ",0
rmsg BYTE "Number of elements to choose from the set: ",0
answer DWORD ?
ansprompt BYTE "Number of combinations: ",0
anstemp BYTE 100 DUP(?)
badinput BYTE "Invalid input. Try again.",0
result DWORD ?
problem BYTE "Problem #",0
results1 BYTE "There is a total of ",0
results2 BYTE " combinations of ",0
results3 BYTE " items from a set of ",0
correct BYTE "You are correct!",0
incorrect BYTE "Wrong answer, better luck next time!",0
againprompt BYTE "Try another problem? (y/n): ",0
againtemp BYTE 100 DUP(?)
bye BYTE "Goodbye!",0
score DWORD 0
scorearr DWORD 100 DUP(?)
scoreoffset DWORD 0
problemtext1 BYTE "Problems you got right: ",0
problemtext2 BYTE "Problems you got wrong: ",0
totalcorrect BYTE "Total correct: ",0
totalincorrect BYTE "Total incorrect: ",0
finalscore BYTE "Final score: ",0
.code
print MACRO buffer
; Prints string `buffer` to screen
; preconditions: `buffer` contains string to print
; postconditions: none
push edx
mov edx, OFFSET buffer
call WriteString
pop edx
ENDM
println MACRO buffer
; Prints string `buffer` to screen, moves cursor to next line
; preconditions: `buffer` contains string to print
; postconditions: none
print buffer
call Crlf
ENDM
read MACRO buffer
; Reads user input into `buffer`
; preconditions: `buffer` contains string to read input into
; postconditions: `buffer` contains user input
push ecx
push edx
mov edx, OFFSET buffer
mov ecx, SIZEOF buffer
dec ecx
call ReadString
pop edx
pop ecx
ENDM
main PROC
; The entry and exit point of the program, calls each procedure.
; preconditions: none
; postconditions: none
; Seed random number generator
call Randomize
call intro
entry:
push scoreoffset
push OFFSET n
push OFFSET r
call showProblem
push OFFSET answer
call getData
push n
push r
push OFFSET result
call combinations
push OFFSET scorearr
push OFFSET scoreoffset
push OFFSET score
push n
push r
push answer
push result
call showResults
; Restarts with another problem if user wants to try again
call tryAgain
call Crlf
cmp eax, 1
je entry
push OFFSET scorearr
push score
call goodbye
exit
main ENDP
intro PROC
; Prints program title and author name.
; preconditions: none
; postconditions: none
println intromsg
println authormsg
call Crlf
println ec
call Crlf
println instructions
call Crlf
ret
intro ENDP
showProblem PROC
; Generates and prints each practice problem
; preconditions: Stack contains @r, @n, scoreoffset
; postconditions: none
push ebp
mov ebp, esp
push eax
push ebx
push ecx
push edx
mov ecx, [ebp+16]
xor edx, edx
; Problem number
mov eax, ecx
cmp eax, 0
je skipdiv
mov ebx, 4
div ebx
skipdiv:
inc eax
print problem
call WriteDec
call Crlf
; n and r
mov ebx, [ebp+12]
mov ecx, [ebp+8]
; Generate n between lo and hi
mov eax, hi_n
sub eax, lo_n
inc eax
call RandomRange
add eax, lo_n
mov [ebx], eax
print nmsg
call WriteDec
call Crlf
; Generate r between lo and n
sub eax, lo_r
inc eax
call RandomRange
add eax, lo_r
mov [ecx], eax
print rmsg
call WriteDec
call Crlf
pop edx
pop ecx
pop ebx
pop eax
pop ebp
ret 12
showProblem ENDP
len MACRO string
; Counts characters of a null-terminated string
; preconditions: `string` is the string to iterate over
; postconditions: eax contains the array length
LOCAL count
LOCAL break
push ebx
push ecx
; Max length 100
mov ecx, 100
xor ebx, ebx
count:
mov al, string[ebx]
cmp al, 0
je break
inc ebx
loop count
break:
mov eax, ebx
pop ecx
pop ebx
ENDM
toInt PROC
; Converts a string to an integer
; preconditions: Stack contains @stringtoconvert
; postconditions: Stack contains integer version of string
push ebp
mov ebp, esp
push eax
push ebx
push ecx
push edx
push edi
mov edx, [ebp+8] ; String to convert
; eax = strlen
len [edx]
mov ecx, eax
xor eax, eax
xor ebx, ebx
xor edi, edi ; result
start:
mov al, [edx][ebx]
; Validate as number
cmp al, 48
jl bad
cmp al, 57
jg bad
sub al, 48
; Multiply result by 10
push eax
push edx
mov eax, edi
mov edi, 10
mul edi
mov edi, eax
pop edx
pop eax
; Add to result
add edi, eax
inc ebx
cmp ebx, ecx
jl start
mov [ebp+8], edi
b:
pop edi
pop edx
pop ecx
pop ebx
pop eax
pop ebp
ret
bad:
; If there's a validation error, return -1
mov eax, -1
mov [ebp+8], eax
jmp b
toInt ENDP
getData PROC
; Gets the user's answer
; preconditions: Stack contains @answer
; postconditions: User's answer stored in global `answer`
push ebp
mov ebp, esp
push eax
push ebx
mov ebx, [ebp+8]
input:
print ansprompt
read anstemp
call Crlf
; Convert to number
push OFFSET anstemp
call toInt
pop eax
cmp eax, 0
jl bad
mov [ebx], eax
pop ebx
pop eax
pop ebp
ret 4
bad:
println badinput
jmp input
getData ENDP
factorial PROC
; Computes the factorial of an integer
; preconditions: Stack contains number to factorialize
; postconditions: eax contains factorialized number
push ebp
mov ebp, esp
push ebx
push edx
mov eax, [ebp+8]
cmp eax, 0
jg cont
mov eax, 1
jmp done
cont:
dec eax
push eax
call factorial
; After recursion
mov ebx, [ebp+8]
mul ebx
done:
pop edx
pop ebx
pop ebp
ret 4
factorial ENDP
combinations PROC
; Does the combination calculations
; preconditions: Stack contains @result, r, n
; postconditions: Calculated result stored in global `result`
push ebp
mov ebp, esp
push eax
push ebx
push ecx
push edx
push edi
mov ebx, [ebp+12] ; r
mov ecx, [ebp+16] ; n
; n! / r!(n - r)!
mov edi, ecx
sub edi, ebx
push edi
call factorial
mov edi, eax ; (n - r)!
push ebx
call factorial
mul edi
mov edi, eax ; r!(n - r)!
push ecx
call factorial
div edi
mov ebx, [ebp+8] ; @result
mov [ebx], eax
pop edi
pop edx
pop ecx
pop ebx
pop eax
pop ebp
ret 12
combinations ENDP
showResults PROC
; Shows the answer to each problem and whether the user was right
; preconditions: Stack contains result, answer, r, n, @score, @scoreoffset, @scorearr
; postconditions: Score updated +1 for correct, -1 for incorrect
push ebp
mov ebp, esp
push eax
push ebx
push ecx
push edx
push edi
; Print results
mov ebx, [ebp+8] ; result
mov eax, ebx
print results1
call WriteDec
mov eax, [ebp+16] ; r
print results2
call WriteDec
mov eax, [ebp+20] ; n
print results3
call WriteDec
mov al, "."
call WriteChar
call Crlf
mov eax, [ebp+12] ; answer
cmp eax, ebx
jne wrong
print correct
mov eax, 2
mov edi, 1
cont:
; Update score array, 1's = incorrect, 2's = correct
mov ebx, [ebp+28] ; offset
mov edx, [ebp+32] ; scorearr array
mov ecx, [ebx]
mov [edx][ecx], eax
add ecx, 4
mov [ebx], ecx
mov ebx, [ebp+24] ; score
mov eax, [ebx]
add eax, edi
mov [ebx], eax
call Crlf
pop edi
pop edx
pop ecx
pop ebx
pop eax
pop ebp
ret 28
wrong:
print incorrect
mov eax, 1
mov edi, -1
jmp cont
showResults ENDP
tryAgain PROC
; Asks the user if they want to try another problem
; preconditions: none
; postconditions: eax contains 0 if no, 1 if yes
entry:
print againprompt
read againtemp
; Length is now stored in eax
; Invalidate if longer than 1 char
cmp eax, 1
jg bad
mov al, againtemp
cmp al, "y"
je yes
cmp al, "Y"
je yes
cmp al, "n"
je no
cmp al, "N"
je no
bad:
; Validation error
println badinput
jmp entry
no:
mov eax, 0
jmp done
yes:
mov eax, 1
done:
ret
tryAgain ENDP
lenArr MACRO arr
; Gets the length of a DWORD array
; preconditions: arr is the array to iterate over
; postconditions: eax contains the array length
LOCAL count
LOCAL break
push ebx
push ecx
push edx
; Max length 100
mov ecx, 100
xor eax, eax
xor ebx, ebx
count:
mov eax, arr[ebx]
cmp eax, 0
je break
add ebx, 4
loop count
break:
xor edx, edx
mov eax, ebx
mov ebx, 4
div ebx
pop edx
pop ecx
pop ebx
ENDM
goodbye PROC
; Shows user's stats (# of right, wrong), says goodbye
; preconditions: Stack contains score, @scorearr
; postconditions: none
push ebp
mov ebp, esp
push eax
push ebx
push ecx
push edx
push edi
push esi
mov edx, [ebp+12]
lenArr [edx]
mov ecx, eax
push ecx
xor ebx, ebx ; offset
mov edi, 1 ; index
xor esi, esi ; # found
print problemtext1
start1:
mov eax, [edx][ebx]
push 1
cmp eax, 2
je printval
pop eax
resume1:
add ebx, 4
inc edi
loop start1
call Crlf
pop ecx
xor ebx, ebx
mov edi, 1
push esi
xor esi, esi
print problemtext2
start2:
mov eax, [edx][ebx]
push 2
cmp eax, 1
je printval
pop eax
resume2:
add ebx, 4
inc edi
loop start2
call Crlf
pop eax ; num correct
print totalcorrect
call WriteDec
call Crlf
print totalincorrect
mov eax, esi ; num incorrect
call WriteDec
call Crlf
print finalscore
mov eax, [ebp+8]
call WriteInt
call Crlf
call Crlf
println bye
pop esi
pop edi
pop edx
pop ecx
pop ebx
pop eax
pop ebp
ret 8
printval:
inc esi
cmp esi, 1
je nocomma
mov al, ","
call WriteChar
mov al, " "
call WriteChar
nocomma:
mov al, "#"
call WriteChar
mov eax, edi
call WriteDec
pop eax
cmp eax, 1
je resume1
jmp resume2
goodbye ENDP
end main
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment