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
|
section .data
; example messages for later
message1 db "Hello, World!", 0xA
msg_len1 equ $ - message1
message2 db "Hello 2!", 0xA
msg_len2 equ $ - message2
; array of snake - 1000 thousand bytes means max length is 500
; x head is at snake[0]
; y head is at snake[1]
snake TIMES 250 db 0
snake_length db 3
; direction of the snake:
; 3
; 2 x 0
; 1
global direction
direction db 0
; delay of the game loop (0.5s in the beginning)
timespec dq 0
dq 500000000
section .rodata
; width and height of the playable area
; (without the borders)
global width
global height
width db 25
height db 10
section .text
extern fruit_x
extern fruit_y
extern spawn_fruit
extern draw_fruit
extern input
extern draw_border
extern write_byte
extern clear_screen
extern reset_cursor
extern move_cursor_right
extern move_cursor_down
extern hide_cursor
extern show_cursor
global _start
global exit
spawn_tail:
inc byte [snake_length]
xor rdx, rdx
mov dl, byte [snake_length]
mov ch, byte [snake+(2*rdx)-4]
mov cl, byte [snake+(2*rdx)-3]
mov byte [snake+(2*rdx)-2], ch
mov byte [snake+(2*rdx)-1], cl
mov ah, byte [direction]
cmp ah, 0
jz _spawn_left
cmp ah, 2
jz _spawn_right
cmp ah, 3
jz _spawn_down
cmp ah, 1
jz _spawn_up
ret ; should not reach this line
_spawn_right:
inc byte [snake+(2*rdx)-2]
ret
_spawn_down:
inc byte [snake+(2*rdx)-1]
ret
_spawn_left:
dec byte [snake+(2*rdx)-2]
ret
_spawn_up:
dec byte [snake+(2*rdx)-1]
ret
draw_snake:
push rbx
;;push r12
xor rdx, rdx
push rdx
call reset_cursor
pop rdx
_12:
mov bh, byte [snake+(2*rdx)]
mov bl, byte [snake+(2*rdx)+1]
_10:push rdx
call move_cursor_right
pop rdx
dec bh
cmp bh, 0
jnz _10
_11:push rdx
call move_cursor_down
pop rdx
dec bl
cmp bl, 0
jnz _11
push rdx
mov rax, 'x'
call write_byte
call reset_cursor
pop rdx
inc rdx
cmp dl, byte [snake_length]
jnz _12
;;pop r12
pop rbx
ret
move_snake:
xor rdx, rdx
mov dl, byte [snake_length]
_move_body:
cmp dl, 1
jz _move_head
mov ah, byte [snake+(2*rdx)-4]
mov al, byte [snake+(2*rdx)-3]
mov byte [snake+(2*rdx)-2], ah
mov byte [snake+(2*rdx)-1], al
dec dl
jmp _move_body
_move_head:
cmp byte [direction], 0
je _move_right
cmp byte [direction], 1
je _move_down
cmp byte [direction], 2
je _move_left
cmp byte [direction], 3
je _move_up
ret ; should not be accessed
_move_right:
inc byte [snake]
ret
_move_down:
inc byte [snake+1]
ret
_move_left:
dec byte [snake]
ret
_move_up:
dec byte [snake+1]
ret
check_eat_fruit:
mov ah, byte [fruit_x]
mov al, byte [fruit_y]
cmp byte [snake], ah
jz _check_y
ret
_check_y:
cmp byte [snake+1], al
jz _same_position
ret
_same_position:
; get longer
call spawn_tail
call spawn_fruit
ret
_start:
call hide_cursor
mov byte [snake], 5
mov byte [snake+1], 5
mov byte [snake+2], 4
mov byte [snake+3], 5
mov byte [snake+4], 3
mov byte [snake+5], 5
call spawn_fruit
main_loop:
call clear_screen
call draw_border
call draw_snake
call draw_fruit
mov rax, 35
lea rdi, [timespec]
xor rsi, rsi
syscall
call input
call move_snake
call check_eat_fruit
jmp main_loop
exit: ; exit syscall with return code 0
call show_cursor
call clear_screen
mov rax, 60
xor rdi, rdi
syscall
|