Last active
September 12, 2023 01:49
-
-
Save subnomo/019e987492e10bfcd27e586e9b8f7f1c to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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