-
Notifications
You must be signed in to change notification settings - Fork 2
/
test.asm
381 lines (338 loc) · 13.1 KB
/
test.asm
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
;===========================================================|
; Basic ASCII Tic-Tac-Toe game, by Matthew Rease. |
; Created 9/22/2019, updated on file modification date. |
; My first program in a new language is almost always a |
; tictactoe game... |
;===========================================================|
.286
INCLUDE basic.mac ; Load in basic macro library
;-------------------|
; BEGIN STACK |
;-------------------|
DemoStack SEGMENT STACK
TheStack DB 32 DUP ('(C) Matthew R. ') ; Reserves 512 bytes of memory for Stack, containing 'STACK!!!' repeated 64 times
DemoStack ENDS
;-------------------|
; END STACK |
;-------------------|
;-------------------|
; BEGIN DATA |
;-------------------|
MyData SEGMENT PUBLIC
PUBLIC CRLF
moveText DB "Your move, ",'$'
; 9D06 = 10011 10100 00011 0
; D6B4 = 11010 11010 11010 0
gameVars DW 94C6h ; lsb is the current player (0 = x, 1 = y), bits 1-15 are board layout (5 bits per row)
board DB " ³ ³ ÄÄÄÅÄÄÄÅÄÄÄ ! ³ ! ³ ! " ; building blocks of the game board
pieces DB " XO" ; possible pieces to place on board
pattern DB 88h ; takes the binary form of 10001000, which, if shifted right, will let me draw board chunk 0,0,0,1,0,0,0,1,0,0,0 while only using 1 byte for the pattern
CRLF DB 0Dh,0Ah,'$' ; EOL String
Adapter DB "X",'$'
Numbers DB "0123456789"
MyData ENDS
;-------------------|
; END DATA |
;-------------------|
;-------------------|
; BEGIN CODE |
;-------------------|
MyCode SEGMENT PUBLIC
assume CS:MyCode,DS:MyData
EXTRN Write:PROC
EXTRN WriteLn:PROC
;------------------------|
; Main Procedure |
;------------------------|
main PROC ; Define Main procedure
;
; Start of Program
;
start::
; ---------- set data location
mov AX,MyData ; Moves Data segment address to AX register
mov DS,AX ; Allowing us to move that address to the intended data segment register, DS
InitGame:
; ---------- initialize game
mov AX,0 ; set AX to 0, for use in "refreshing" variables in memory
mov BX,OFFSET gameVars ; load memory offset of gameVars into BX
mov [BX],AX ; sets word at DS:BX to 0
mov AX,3 ; video function 0 set video mode, mode 3
int 10h ; call BIOS video
startGameLoop:
; ---------- clear screen
mov AH,2 ; BIOS video function 2, set cursor position
mov BH,0 ; page 0
mov DX,0 ; Row 0, Column 0
int 10h ; call BIOS video
; ---------- say whose turn it is, and draw the board
lea DX,moveText ; Loads the address of the 'words' string, into the DX register
call Write ; Ouputs moveText to console, followed by CRLF
mov AX,[gameVars] ; load gameVars in AX
mov AH,0Eh ; function 0E, output char to screen
and AL,1 ; remove all but LSB
add AL,30h ; add 30h (ascii numbers begin at 30h)
mov BX,0 ; set BX to 0
int 10h ; call BIOS function 0E
lea DX,CRLF ; load address of CRLF in DX
call WriteLn ; new line
call drawBoard
; ---------- get user input
mov AH,7 ; DOS function 07, get single character from keyboard (no echo)
int 21h ; Call DOS
cmp AL,1Bh ; compare AL to 1B which corresponds to the escape key
jz endGameLoop ; drop out of loop to end game
cmp AL,71h ; compare AL to 71 which corresponds to lowercase 'q'
jz endGameLoop ; gotta give people options :)
cmp AL,72h ; compare AL to 72 which corresponds to lowercase 'r'
jz InitGame ; restarts game
sub AL,31h ; ascii for 1 is 31h, so turn that into a 0
sub AL,9 ; now subtract 9, that way if it is 0-8 we will trigger the carry flag
jnc noTryMove ; if they did not input 1-9, then don't try anything (continue)
call tryMove ;attempt the requested move, if it is valid, the board will be updated, and the player will change
noTryMove:
;mov [Adapter],AL ; store input in Adapter
;lea DX,Adapter ; load address of Adapter into DX
;call WriteLn ; then print it
jmp startGameLoop ; refresh screen
endGameLoop:
;call DispID
;add AL,[Adapter]
;add AL,[Numbers]
;mov Adapter,AL
;lea DX,Adapter
;call WriteLn
EXIT 0 ; Calls macro to terminate program and sets ERRORLEVEL to 0
main ENDP
;------------------------|
; Main Procedure Ends |
;------------------------|
;-------------------------|
; Try Move Procedure |
;-------------------------|
tryMove PROC ; AL should contain a value from 0-8
mov CX,0003 ; row = 0, and CL is 3 (for dividing later)
add AL,9 ; restore request to original value before carry test
mov DL,AL ; temporarily store request
sub AL,6 ; if request is 6-8, we won't carry
jnc continueTryMove ; row is 0
add CH,1 ; row = 1
mov AL,DL ; restore request
sub AL,3 ; if request is 3-5, we won't carry
jnc continueTryMove ; row is 1
add CH,1 ; row is 2
continueTryMove:
mov AH,0 ; zero out upper register
mov AL,DL ; restore request
div CL ; divide request by 3
mov CL,AH ; place request % 3 in CL
mov AX,1 ; set AX to 1 (_ _ X)
tmColumn:
sub CL,1 ; decrement column
jc tmRow ; if we underflow, our work is done
mov DX,AX ; save AX in DX
shl AX,1 ; multiply AX by 2
add AX,DX ; add DX to AX (thus multiplying by 3)
jmp tmColumn ; try again
tmRow:
sub CH,1 ; decrement row
jc tmDoneAlign ; if we underflow, our work is done
mov DX,AX ; save AX in DX
shl AX,5 ; shift to next row (5 bits)
jmp tmRow ; try again
tmDoneAlign:
mov DX,gameVars ; copy gameVars to DX
and DX,1 ; remove all but LSB
mov CL,DL ; get current player
shl AX,CL ; if player is 1, then double the value that we'll add
xor DX,1 ; alternate LSB of DX (toggle player turn)
shl AX,1 ; shift our board addition left, so we don't modify current player
add AX,gameVars ; add board data to temp board data
and AX,0FFFEh ; zero out LSB
add AX,DX ; if it's player 0's turn, nothing changes (we still add X) but if it's player 1's turn we add 1 (change to O)
mov gameVars,AX ; commit to memory (update board data)
ret
tryMove ENDP
;-------------------------|
; Try Move Procedure |
;-------------------------|
;---------------------------|
; Display ID Procedure |
;---------------------------|
DispID PROC
mov AH,1Ah
xor AL,AL
int 10h
cmp AL,1Ah
jne TryEGA
mov AL,BL
ret
TryEGA: mov AH,12h
mov BX,10h
int 10h
cmp BX,10h
int 10h
cmp BX,10h
je OldBords
cmp BH,0
je EGAColor
mov AL,5
ret
EGAColor: mov AL,4
ret
OldBords: int 11h
and AL,30h
cmp AL,30h
jne CGA
mov AL,1
ret
CGA: mov AL,2
ret
DispID ENDP
;---------------------------|
; Display ID Procedure ENDS |
;---------------------------|
;---------------------------|
; Draw Board Procedure |
;---------------------------|
drawBoard PROC ; Define board drawing procedure
mov CL,0Bh ; set count to 11
mov AH,pattern ; place board pattern in AH
drawBLoop:
mov BX,0 ; set register where string offset goes to 0
mov AL,AH ; place remaining board pattern in AL
and AL,1 ; 0 out all but LSB
; [shouldn't need, as AND should set Zero Flag] cmp 1,AL ; subtracts AL from 1, and sets flags
jz drawBFinish ; if LSB is 0, skips following command (which would end up making the string output routine print the second board design)
mov BX,0Bh ; set register where string offset goes to 0Bh (11)
drawBFinish:
;-----------------------------------------|
; determine if we should draw play pieces |
;-----------------------------------------|
mov DL,CL ; clone count into DL
and DL,3 ; eliminate bits 2-7
cmp DL,2 ; make sure it starts with 10
jnz determineFinish ; if DL doesn't equal 10, stop testing
; ---- This should be enough, assuming CL is never greater than 11 (base 10)
; mov DL,CL
; shr DL
; shr DL ; DL = 000000??
; cmp DL,3 ; if DL is 11, ZF will now eqaul 0
; draw letters if zero flag is false
push AX ;\
push BX ; |- Save
push CX ;/
mov DL,CL ; clone count into DL
sub DL,2 ; subract 2 (this code SHOULD only run if CL is 2 6 or 10)
shr DX,1
shr DX,1 ; DL has now been divided by 4
and DL,3 ; remove first 2 bits (in case there was anything in DH)
call extractRow ; will place play pieces for this row
pop CX ;\
pop BX ; |- Restore
pop AX ;/
add BX,16h ; add 22 to address so we draw 3rd board design
;-----------------------------------------|
; play piece row determination finished |
;-----------------------------------------|
determineFinish:
add BX,OFFSET board; add OFFSET BOARD to register where string offset goes
mov DX,0Bh ; mov 0Bh to a register (11), to represent the length of the strings
push CX ; save count to stack (cannot push byte register), using CL
push AX ; save remaining pattern to stack, using AH
call writeText ; call string output proc
mov DX,OFFSET CRLF ; load offset address of CRLF into DX
call Write ; will output CRLF to the console
pop AX ; get pattern back! (AH)
pop CX ; get count back; (CL)
shr AH,1 ; shift pattern right, to get rid of previous pattern, and to see the next
dec CL ; decrease count by one, since part of the board has now been drawn
jnz drawBLoop ; draw another part of the board if count isn't 0, otherwise stop doing that!
ret
drawBoard ENDP
;---------------------------|
; Draw Board Procedure ENDS |
;---------------------------|
;----------------------------|
; Extract Row Procedure |
;----------------------------|
extractRow PROC
mov DH,DL ; copy row (DL) to DH
shl DH,1 ; multiply row by 2
shl DH,1 ; multiply row by 2 (4)
add DH,DL ; add DL to DH
mov CL,DH ; place DH in CL, thus multiplying DL by 5 (CL = DL * 5)
mov AX,gameVars ; retrieve game variables
shl AX,CL ; move to correct row of piece data
shr AX,0Bh ; move the 5 bits we need to the front
and AX,1Fh ; remove bits 5-15, we only want 0-4
mov CH,0 ; set iteration 0
exRowIt:
inc CH ; next iteration
mov CL,3 ; set CX to 3, so we can divide by 3
div CL ; divide AX by 3 (store in AL, remainder in AH)
mov BX,OFFSET pieces ; get possible play pieces (address)
mov DX,0 ; zero out DX
mov DL,AH ; get remainder (modulus) into DL
add BX,DX ; add result of division
mov DL,[BX] ; DL should now have a space, an X, or an O
mov BX,OFFSET board ; get board address
add BX,13h ; move to 3rd layout + 1 for first column, but we subtract 4 so the following loop works correctly
push CX ; save iteration (we only need CH)
exRowItColumn:
add BX,4 ; next column
dec CH ; iteration - 1
jnz exRowItColumn ; if this is zero, we're in the correct column
pop CX ; load iteration (from CH)
cmp CH,3 ; check if we're on iteration 3
mov [BX],DL ; and now we place the character in DL, into the board area
mov AH,0 ; get rid of remainder, (so AX is divided by 3)
jnz exRowIt ; if CH is anything other than 3, we reiterate
ret
extractRow ENDP
;----------------------------|
; Extract Row Procedure |
;----------------------------|
;---------------------------|
; Write Text Prodecure |
; |
; Requires BX to be address |
; of first character, and DX|
; to be length of string. |
; |
; This procedure was written|
; in 60-90 minutes, on a |
; school day in college, |
; after I'd taken a long |
; break. |
;---------------------------|
writeText PROC ; Define text writing procedure
mov CX,0 ; set CX to 0
writeLoop:
push BX ; save string address
mov AH,0Eh ; function 0E, output char to screen
add BX,CX ; add char offset to BX
mov AL,[BX] ; place character at DS:BX in AL
push DX ; save length
push CX ; save current char
mov BX,0 ; set BX to 0
int 10h ; call BIOS function 0E
pop CX ; restore current char
pop DX ; restore length
pop BX ; restore string address
inc CX ; increment char by 1
cmp DX,CX ; compare length to current char
jnz writeLoop ; continue writing if current char hasn't reached length
ret
writeText ENDP
;---------------------------|
; Write Text Prodecure ENDS |
;---------------------------|
MyCode ENDS
;-------------------|
; END CODE |
;-------------------|
END start
;
; End of program
;