-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy path2048_main.asm
More file actions
269 lines (203 loc) · 7.24 KB
/
2048_main.asm
File metadata and controls
269 lines (203 loc) · 7.24 KB
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
extern _CRT_INIT:proc
extern print_board:proc
extern init_srand:proc
extern get_next_direction:proc
extern rand_with_max:proc
extern count_zeros:proc
extern ansi_support:proc
extern gen_tile:proc
.data
board dw 16 dup(0) ; The game board, representing a 4x4 space, 2 bytes each
.code
CWB macro function ; Call w/ board
lea rcx, board ; Utility macro to auto-set
call function ; the board to the
endm ; first parameter
;; ----------------------------------------------------------------------------
;; Entry point of the game.
;; ----------------------------------------------------------------------------
play_2048 proc
call ansi_support ; Inits a 'random' seed
call _CRT_INIT ; Initialize C Runtime
call init_srand ; Inits a 'random' seed
CWB gen_tile ; Generates the starting tiles
CWB gen_tile
CWB print_board ; Initial board print
GameLoop:
call get_next_direction ; Gets the user's input for the next direction
cmp rax, -1 ; If the input is invalid, continue
je Continue
cmp rax, -2 ; If the input is -2, quit
je Finished
mov r10, rax ; Stores the number of rotations needed
mov rdx, r10 ; Rotates the board n times
CWB rot_r
CWB squash_board ; Performs a move in the given direction
CWB add_board
CWB squash_board
mov rdx, r10 ; Un-rotates the board times
CWB rot_l
CWB gen_tile ; Spawns a new tile
CWB print_board ; Prints the updated board
Continue:
CWB count_zeros ; Count the # of 0s in the board
test rax, rax ; If the # of 0s is not zero
jnz GameLoop ; continue the game
Finished:
xor rax, rax ; Zero-out rax
ret ; Return with exit code 0
play_2048 endp
;; ----------------------------------------------------------------------------
;; Moves zeros to the end of the board.
;;
;; Params: rcx -> board ptr
;; ----------------------------------------------------------------------------
squash_board proc
mov rsi, rcx ; Set the board pointer to the RSI register
xor r15, r15 ; Outer loop counter
RowIterations:
xor r13, r13 ; Inner loop counter1; keeps track of non-zeros
xor r14, r14 ; Inner loop counter2; keeps track of iterations
ColIterations:
cmp word ptr [rsi + r14 * 2], 0
jz IsZero
cmp r13, r14 ; If r13 > r14, don't swap, but still increment ctr1
jge R13NotLessThanR14
movzx eax, word ptr [rsi + r14 * 2] ; If r13 is less than r14...
movzx edx, word ptr [rsi + r13 * 2] ; swap board[r13] and board[r14]
mov word ptr [rsi + r13 * 2], ax ; Moving the zeros
mov word ptr [rsi + r14 * 2], dx ; ...to the back
R13NotLessThanR14:
inc r13 ; Increment the number of non-zeros
IsZero:
inc r14
cmp r14, 4
jl ColIterations ; Go through this loop once per col
add rsi, 8
inc r15
cmp r15, 4
jl RowIterations ; Go through this loop once per row
ret
squash_board endp
;; ----------------------------------------------------------------------------
;; Adds together similarly numbered tiles as in traditional 2048.
;;
;; Params: rcx -> board ptr
;; ----------------------------------------------------------------------------
add_board proc
mov rsi, rcx ; Set the board pointer to the RSI register
xor r15, r15 ; Outer loop counter
RowIterations:
xor r14, r14 ; Inner loop counter
ColIterations:
cmp word ptr [rsi + r14 * 2], 0 ; If it's zero...
jz Continue ; continue on
movzx eax, word ptr [rsi + r14 * 2] ; Move board[r14] and board[r15]
movzx ebx, word ptr [rsi + r14 * 2 + 2] ; into registers to compare them
cmp eax, ebx ; If they're not the same...
jnz Continue ; continue on
shl word ptr [rsi + r14 * 2], 1 ; Double board[r14]
mov word ptr [rsi + r14 * 2 + 2], 0 ; Zero-out board[r15]
Continue:
inc r14
cmp r14, 3
jl ColIterations ; Go through this loop (length(col) - 1) times
add rsi, 8
inc r15
cmp r15, 4
jl RowIterations ; Go through this loop once per row
ret
add_board endp
;; ----------------------------------------------------------------------------
;; Rotates the board right <x> times.
;;
;; Params: rcx -> board ptr
;; rdx -> # rotations
;; ----------------------------------------------------------------------------
rot_r proc
test rdx, rdx ; If the number of rotations is 0...
jz NoRotation ; just return
RotationLoop: ; Go through the loop n times
push rcx ; Rotating the board once each time
push rdx
call rot_90
pop rdx
pop rcx
dec rdx
cmp rdx, 0
jg RotationLoop
NoRotation:
ret
rot_r endp
;; ----------------------------------------------------------------------------
;; Rotates the board left <x> times.
;;
;; Params: rcx -> board ptr
;; rdx -> # rotations
;; ----------------------------------------------------------------------------
rot_l proc
mov r8, 4 ; Find the complement of n and 4
sub r8, rdx ; Rotate the board right that many times
mov rdx, r8 ; E.g. rot_l(1) -> rot_r(3)
call rot_r
ret
rot_l endp
;; ----------------------------------------------------------------------------
;; Rotates the board 90 degrees.
;; I am 100% sure there is a MUCH better way to do so.
;;
;; Params: rcx -> board ptr
;; ----------------------------------------------------------------------------
rot_90 proc
push rbp
push rbx
mov rsi, rcx ; Set the board pointer to the RSI register
xor r15, r15 ; Row loop counter
TranspositonRowIterations:
mov r14, r15 ; Col loop counter
inc r14
TranspositonColIterations:
mov rcx, r15 ; Move row counter into rcx
shl rcx, 3 ; Multiply row counter by 2^3 (8) to get to r15th row
mov r8, r14 ; Temp move column counter into r8
shl r8, 1 ; Multiply it by 2^1 (2) to get r14th column
add rcx, r8 ; Add rcx & r8 to get to [row][column]
mov rdx, r15 ; Move row counter into rdx
shl rdx, 1 ; Multiply it by 2^1 (2) to get r15th column
mov r8, r14 ; Temp move column counter into r8
shl r8, 3 ; Multiply col counter by 2^3 (8) to get to r14th row
add rdx, r8 ; Add rdx & r8 to get to [column][row]
movzx eax, word ptr [rsi + rcx] ; Swaps board[row][column]
movzx ebx, word ptr [rsi + rdx] ; and board[column][row]
mov word ptr [rsi + rcx], bx ; to transpose array
mov word ptr [rsi + rdx], ax ; using constant space
inc r14
cmp r14, 4
jl TranspositonColIterations ; Go through this loop (4 - (r15 + 1)) times
inc r15
cmp r15, 4
jl TranspositonRowIterations ; Go through this loop once per row
xor r15, r15 ; Row loop counter
MatrixReversalRowIterations:
mov r14, 4 ; Col loop counter
shr r14, 1 ; Finds midpoint of array
dec r14 ; Starts from mid-1
MatrixReversalColIterations:
mov r13, 4 - 1 ; Complement of mid of array
sub r13, r14 ; Index that is swapped with
movzx eax, word ptr [rsi + r13 * 2] ; Swaps
movzx ebx, word ptr [rsi + r14 * 2] ; board[r14]
mov word ptr [rsi + r13 * 2], bx ; with
mov word ptr [rsi + r14 * 2], ax ; board[r13]
dec r14
cmp r14, 0
jge MatrixReversalColIterations ; Go through this loop ((int) length(col)/2) times
lea rsi, [rsi + 8] ; Increment the row
inc r15
cmp r15, 4
jl MatrixReversalRowIterations ; Go through this loop once per row
pop rbx
pop rbp
ret
rot_90 endp
end