Add user input handling and board initialization logic

This commit is contained in:
Afonso Clerigo Mendes de Sousa 2025-04-01 18:48:00 +01:00
parent de5707f280
commit 84993e3b8d
5 changed files with 351 additions and 126 deletions

BIN
bin/main

Binary file not shown.

View File

@ -1,5 +1,5 @@
echo ">>> Compiling ASM code..."
nasm -f macho64 -o ./bin/obj/main.o ./src/main.asm
nasm -f macho64 -g -o ./bin/obj/main.o ./src/main.asm
if [ $? -ne 0 ]; then
echo " >> Error: Assembly failed."
exit 1

76
src/io/io.asm Normal file
View File

@ -0,0 +1,76 @@
; returns the user input in r15
; 0x01 = up
; 0x02 = left
; 0x03 = down
; 0x04 = right
; 0xDEAD = no valid key pressed
read_user_input:
; Read user input for the game
; Read AWSD keys (basically, read a single byte)
; Ensure symmetric register saving
push rax ; added missing push for symmetry
push rbx
push rcx
push rdx
push rsi
push rdi
xor r15, r15 ; Clear r15 to indicate no valid key pressed
; changed: use read syscall number 0x2000003
mov rax, 0x2000003
mov rdi, 0
lea rsi, [rsp] ; Read into stack
mov rdx, 1
syscall
; Check for W key
cmp byte [rsp], 0x77
je up_key
; Check for A key
cmp byte [rsp], 0x61
je left_key
; Check for S key
cmp byte [rsp], 0x73
je down_key
; Check for D key
cmp byte [rsp], 0x64
je right_key
; Check for e key
cmp byte [rsp], 0x65
je unburry_key
mov r15, 0xDEAD ; Debug: no valid key pressed
jmp exit_user_with_no_input
up_key:
mov r15, 0x01 ; Debug: up key pressed
jmp exit_user_with_no_input
left_key:
mov r15, 0x02 ; Debug: left key pressed
jmp exit_user_with_no_input
down_key:
mov r15, 0x03 ; Debug: down key pressed
jmp exit_user_with_no_input
right_key:
mov r15, 0x04 ; Debug: right key pressed
jmp exit_user_with_no_input
unburry_key:
mov r15, 0x05 ; Debug: unburry key pressed
exit_user_with_no_input:
; Restore registers
pop rdi
pop rsi
pop rdx
pop rcx
pop rbx
pop rax
ret

View File

@ -14,42 +14,37 @@ section .data
user_input times 3 db 0
user_input_len equ $ - user_input
newline db 0xA, 0
newline_len equ $ - newline
digit_buffer db 0
first_move db 0
section .bss
board resb 100
; termios resb 20 ; Reserve space for termios structure
section .text
global _main
_main:
; Fill the board with 0s and 1s
xor r10, r10 ; Counter
lea r11, [rel board] ; Load address of board
; Initialize the board with mines and empty tiles
xor rax, rax
mov rcx, 100 ; Loop 100 times
fill_loop:
rdrand rax
and rax, 15 ; Reduce probability of mine (1 in 16 chance)
cmp rax, 1
sete al ; Set al to 1 if rax == 1, otherwise 0
mov [r11 + r10], al ; Store at board[r10]
inc r10
loop fill_loop
; Set up user location
mov byte [rel user_location_pos], 0
; Print the board
xor r10, r10 ; Reset counter
xor r10, r10 ; Reset counter before refill
print_loop:
xor rcx , rcx ; Reset mine count
lea r11, [rel board]
movzx rax, byte [r11 + r10] ; Load board[r10]
movzx rax, byte [r11 + r10] ; Load board[r10]
; Print user location
cmp r10, [rel user_location_pos]
; Print user location (load byte with zero-extension)
movzx rbx, byte [rel user_location_pos]
cmp r10, rbx
jne not_user_location
lea r8, [rel user_location]
mov r9, tile_len
@ -112,115 +107,119 @@ no_newline:
cmp r10, 100
jb print_loop
; Read arrow keys
; Small bracket to be able to distinguish between first move and refill
lea r8, [rel newline]
mov r9, newline_len
call print_String
call print_String
xor r15, r15
; Read user input
call read_user_input
cmp byte [rel first_move], 0 ; Compare memory content of first_move
je not_first_move
; Instead of resetting and jumping to fill_loop, call fill_board from ui.asm
call fill_board
jmp print_loop
not_first_move:
; Check if user pressed a valid key
cmp r15, 0xDEAD
je invalid_key
cmp r15, 0x01
je move_up
cmp r15, 0x02
je move_left
cmp r15, 0x03
je move_down
cmp r15, 0x04
je move_right
cmp r15, 0x05
je unburry
jmp invalid_key
move_up:
; Move up
lea r8, [rel user_location]
mov r9, tile_len
call print_String
; Update user location safely (read one byte)
movzx rax, byte [rel user_location_pos]
sub rax, 10
mov [rel user_location_pos], al
; Print the board again
xor r10, r10 ; Reset counter before refill
jmp print_loop
move_left:
; Move left
lea r8, [rel user_location]
mov r9, tile_len
call print_String
; Update user location safely (read one byte)
movzx rax, byte [rel user_location_pos]
sub rax, 1
mov [rel user_location_pos], al
; Print the board again
xor r10, r10 ; Reset counter before refill
jmp print_loop
move_down:
; Move down
lea r8, [rel user_location]
mov r9, tile_len
call print_String
; Update user location safely (read one byte)
movzx rax, byte [rel user_location_pos]
add rax, 10
mov [rel user_location_pos], al
; Print the board again
xor r10, r10 ; Reset counter before refill
jmp print_loop
move_right:
; Move right
lea r8, [rel user_location]
mov r9, tile_len
call print_String
; Update user location safely (read one byte)
movzx rax, byte [rel user_location_pos]
add rax, 1
mov [rel user_location_pos], al
; Print the board again
xor r10, r10 ; Reset counter before refill
jmp print_loop
unburry:
; Unburry the tile: set first move flag and refill board
mov byte [rel first_move], 1
call fill_board
jmp print_loop
; Invalid key pressed
invalid_key:
; Exit
mov rax, 0x2000001
xor rdi, rdi
syscall
; r8 = string
; r9 = length
print_String:
mov rax, 0x2000004
mov rdi, 1
mov rsi, r8
mov rdx, r9
syscall
ret
; r10 = current tile index
; r11 = board
; rdx = mine count
; r8 = offset
count_adjacent_mines:
xor rdx, rdx
mov r8, 0
; Check top left
mov rax, r10
sub rax, 11
cmp rax, 0
jl .skip_top_left
movzx rax, byte [r11 + rax]
cmp rax, 1
sete al
add dl, al
.skip_top_left:
; Check top
mov rax, r10
sub rax, 10
cmp rax, 0
jl .skip_top
movzx rax, byte [r11 + rax]
cmp rax, 1
sete al
add dl, al
.skip_top:
; Check top right
mov rax, r10
sub rax, 9
cmp rax, 0
jl .skip_top_right
movzx rax, byte [r11 + rax]
cmp rax, 1
sete al
add dl, al
.skip_top_right:
; Check left
mov rax, r10
sub rax, 1
cmp rax, 0
jl .skip_left
movzx rax, byte [r11 + rax]
cmp rax, 1
sete al
add dl, al
.skip_left:
; Check right
mov rax, r10
add rax, 1
cmp rax, 100
jge .skip_right
movzx rax, byte [r11 + rax]
cmp rax, 1
sete al
add dl, al
.skip_right:
; Check bottom left
mov rax, r10
add rax, 9
cmp rax, 100
jge .skip_bottom_left
movzx rax, byte [r11 + rax]
cmp rax, 1
sete al
add dl, al
.skip_bottom_left:
; Check bottom
mov rax, r10
add rax, 10
cmp rax, 100
jge .skip_bottom
movzx rax, byte [r11 + rax]
cmp rax, 1
sete al
add dl, al
.skip_bottom:
; Check bottom right
mov rax, r10
add rax, 11
cmp rax, 100
jge .skip_bottom_right
movzx rax, byte [r11 + rax]
cmp rax, 1
sete al
add dl, al
.skip_bottom_right:
ret
%include "./src/io/io.asm"
%include "./src/ui/ui.asm"

150
src/ui/ui.asm Normal file
View File

@ -0,0 +1,150 @@
; r8 = string
; r9 = length
print_String:
mov rax, 0x2000004
mov rdi, 1
mov rsi, r8
mov rdx, r9
syscall
ret
; r10 = current tile index
; r11 = board
; rdx = mine count
; r8 = offset
count_adjacent_mines:
; Compute current column: r12 = r10 mod 10
mov rax, r10
xor rdx, rdx
mov rcx, 10
div rcx
mov r12, rdx ; r12 holds the column index (0-9)
xor rdx, rdx ; rdx will accumulate the mine count
; Check top-left: valid if r10 >= 11 and column != 0
cmp r10, 11
jb .skip_top_left
cmp r12, 0
je .skip_top_left
mov rax, r10
sub rax, 11
movzx rax, byte [r11 + rax]
cmp rax, 1
sete al
add dl, al
.skip_top_left:
; Check top: valid if r10 >= 10
cmp r10, 10
jb .skip_top
mov rax, r10
sub rax, 10
movzx rax, byte [r11 + rax]
cmp rax, 1
sete al
add dl, al
.skip_top:
; Check top-right: valid if r10 >= 9 and column != 9
cmp r10, 9
jb .skip_top_right
cmp r12, 9
je .skip_top_right
mov rax, r10
sub rax, 9
movzx rax, byte [r11 + rax]
cmp rax, 1
sete al
add dl, al
.skip_top_right:
; Check left: valid if column != 0
cmp r12, 0
je .skip_left
mov rax, r10
sub rax, 1
movzx rax, byte [r11 + rax]
cmp rax, 1
sete al
add dl, al
.skip_left:
; Check right: valid if column != 9
cmp r12, 9
je .skip_right
mov rax, r10
add rax, 1
cmp rax, 100
jge .skip_right
movzx rax, byte [r11 + rax]
cmp rax, 1
sete al
add dl, al
.skip_right:
; Check bottom-left: valid if r10 < 90 and column != 0
cmp r10, 90
jae .skip_bottom_left
cmp r12, 0
je .skip_bottom_left
mov rax, r10
add rax, 9
movzx rax, byte [r11 + rax]
cmp rax, 1
sete al
add dl, al
.skip_bottom_left:
; Check bottom: valid if r10 < 90
cmp r10, 90
jae .skip_bottom
mov rax, r10
add rax, 10
movzx rax, byte [r11 + rax]
cmp rax, 1
sete al
add dl, al
.skip_bottom:
; Check bottom-right: valid if r10 < 90 and column != 9
cmp r10, 90
jae .skip_bottom_right
cmp r12, 9
je .skip_bottom_right
mov rax, r10
add rax, 11
movzx rax, byte [r11 + rax]
cmp rax, 1
sete al
add dl, al
.skip_bottom_right:
ret
; Print the board
; r10 = current tile index
; r11 = board
; r12 = column index
; rdx = mine count
; r8 = offset
fill_board:
xor r10, r10 ; Counter for filling the board
push rbp
mov rbp, rsp
push rcx
xor r10, r10 ; Counter
lea r11, [rel board] ; Load address of board
fill_loop:
rdrand rax
and rax, 15 ; Reduce probability of mine (1 in 16 chance)
cmp rax, 1
sete al ; Set al to 1 if rax == 1, otherwise 0
mov [r11 + r10], al ; Store at board[r10]
inc r10
cmp r10, 100 ; Check if we've filled 100 tiles
jb fill_loop
pop rcx
pop rbp
ret