covered_color equ 0x70 controls_color equ 0x70 flag_character equ 'F' bombs_per_65535 equ 5000 board_width equ 26 board_height equ 10 offset_x equ 1 offset_y equ 1 org 0x0100 mov ax, 0x0501 int 0x10 xor ah, ah int 0x1a test dx, dx jnz nonzero inc dx nonzero: mov word [xorshift_state], dx mov cx, board_width * board_height mov si, cx mov di, board_flags bomb_loop: call xorshift cmp ax, bombs_per_65535 ja .no_bomb mov byte [di], board_bomb dec si .no_bomb: inc di loop bomb_loop mov word [non_bombs_left], si xor bx, bx mov di, board_numbers number_loop: call get_number_of_bx mov byte [di], al inc di inc bl cmp bl, board_width jne number_loop xor bl, bl inc bh cmp bh, board_height jne number_loop push 0xb900 pop es xor di, di mov ax, (covered_color << 8) | ' ' mov cx, 80 * 25 rep stosw ; mov di, offset_y * 80 * 2 + offset_x * 2 ; mov cx, board_width * 3 ; mov ax, (covered_color << 8) | 0xdf ; rep stosw ; ; mov di, (offset_y + 1) * 80 * 2 + offset_x * 2 ; mov ax, (covered_color << 8) | ' ' ;gray_loop: ; mov cx, board_width * 3 ; rep stosw ; add di, (80 - board_width * 3) * 2 ; cmp di, (offset_y + board_height * 2) * 80 * 2 + offset_x * 2 ; jne gray_loop ; ; mov cx, board_width * 3 ; mov ax, (covered_color << 8) | 0xdc ; rep stosw mov si, controls_str mov di, (offset_y + board_height * 2 + 2) * 80 * 2 + offset_x * 2 + ((board_width * 3 - controls_str.len) / 4) * 2 mov cx, controls_str.len mov ah, controls_color show_controls_loop: mov al, byte [si] mov word [es:di], ax inc si add di, 2 loop show_controls_loop call set_cursor main_loop: xor ah, ah int 0x16 cmp ah, 0x48 je up_arrow cmp ah, 0x50 je down_arrow cmp ah, 0x4b je left_arrow cmp ah, 0x4d je right_arrow cmp ah, 0x20 je dig cmp ah, 0x21 je flag cmp ah, 0x10 jne main_loop mov ax, 0x0500 int 0x10 mov ax, 0x4c00 int 0x21 xorshift_state: dw 0 xorshift: mov ax, word [xorshift_state] mov dx, ax shl dx, 7 xor ax, dx mov dx, ax shr dx, 9 xor ax, dx xor ah, al mov word [xorshift_state], ax ret ;bx - y:x ;preserves bx, di, and si ;returns in ax bx_has_bomb: push bx movzx ax, bh mov cx, board_width mul cx xor bh, bh add bx, ax mov ax, board_bomb and al, byte [board_flags + bx] pop bx ret ;bx - y:x ;preserves bx, di, and si ;returns in ax bx_uncovered: push bx movzx ax, bh mov cx, board_width mul cx xor bh, bh add bx, ax mov ax, board_uncovered and al, byte [board_flags + bx] pop bx ret ;bx - y:x ;preserves bx and di ;returns in al get_number_of_bx: xor si, si test bh, bh jz .no_ups dec bh test bl, bl jz .no_ul dec bl call bx_has_bomb add si, ax inc bl .no_ul: call bx_has_bomb add si, ax cmp bl, board_width - 1 je .no_ur inc bl call bx_has_bomb add si, ax dec bl .no_ur: inc bh .no_ups: test bl, bl jz .no_cl dec bl call bx_has_bomb add si, ax inc bl .no_cl: cmp bl, board_width - 1 je .no_cr inc bl call bx_has_bomb add si, ax dec bl .no_cr: cmp bh, board_height - 1 je .no_downs inc bh test bl, bl jz .no_bl dec bl call bx_has_bomb add si, ax inc bl .no_bl: call bx_has_bomb add si, ax cmp bl, board_width - 1 je .no_br inc bl call bx_has_bomb add si, ax dec bl .no_br: dec bh .no_downs: mov ax, si ret set_cursor: mov ah, 0x02 mov bh, 0x01 mov cx, word [cursor_x] mov dl, cl add dl, cl add dl, cl add dl, offset_x + 1 mov dh, ch add dh, ch add dh, offset_y + 1 int 0x10 jmp main_loop up_arrow: mov al, byte [cursor_y] test al, al jz main_loop dec al mov byte [cursor_y], al call set_cursor jmp main_loop down_arrow: mov al, byte [cursor_y] cmp al, board_height - 1 je main_loop inc al mov byte [cursor_y], al call set_cursor jmp main_loop left_arrow: mov al, byte [cursor_x] test al, al jz main_loop dec al mov byte [cursor_x], al call set_cursor jmp main_loop right_arrow: mov al, byte [cursor_x] cmp al, board_width - 1 je main_loop inc al mov byte [cursor_x], al call set_cursor jmp main_loop dig: push main_loop do_dig: call get_board_flags_at_cursor test al, board_uncovered | board_flagged jz .can_dig ret .can_dig: test al, board_bomb jnz lose or al, board_uncovered call set_board_flags_at_cursor push ax call get_cursor_vram_offset mov di, ax pop ax call get_number_at_cursor push ax movzx bx, al mov al, byte [bx + uncovered_numbers] mov ah, byte [bx + uncovered_colors] mov word [es:di], ax mov bx, word [cursor_x] test bh, bh jz .top_half_block dec bh call bx_uncovered inc bh test al, al jz .top_half_block mov word [es:di - 80 * 2 - 2], ' ' mov word [es:di - 80 * 2], ' ' mov word [es:di - 80 * 2 + 2], ' ' jmp .middle .top_half_block: mov word [es:di - 80 * 2 - 2], (covered_color << 8) | 0xdc mov word [es:di - 80 * 2], (covered_color << 8) | 0xdc mov word [es:di - 80 * 2 + 2], (covered_color << 8) | 0xdc .middle: mov byte [es:di - 2 + 1], 0 mov byte [es:di + 2 + 1], 0 cmp bh, board_height - 1 je .bottom_half_block inc bh call bx_uncovered dec bh test al, al jz .bottom_half_block mov word [es:di + 80 * 2 - 2], ' ' mov word [es:di + 80 * 2], ' ' mov word [es:di + 80 * 2 + 2], ' ' jmp .dec_bombs .bottom_half_block: mov word [es:di + 80 * 2 - 2], (covered_color << 8) | 0xdf mov word [es:di + 80 * 2], (covered_color << 8) | 0xdf mov word [es:di + 80 * 2 + 2], (covered_color << 8) | 0xdf .dec_bombs: mov ax, word [non_bombs_left] dec ax test ax, ax jz win mov word [non_bombs_left], ax pop ax test al, al jz .expand ret .expand: mov al, byte [cursor_y] test al, al jz .no_up dec al mov byte [cursor_y], al call do_dig mov al, byte [cursor_y] inc al mov byte [cursor_y], al .no_up: mov al, byte [cursor_y] cmp al, board_height - 1 je .no_down inc al mov byte [cursor_y], al call do_dig mov al, byte [cursor_y] dec al mov byte [cursor_y], al .no_down: mov al, byte [cursor_x] test al, al jz .no_left dec al mov byte [cursor_x], al call do_dig mov al, byte [cursor_x] inc al mov byte [cursor_x], al .no_left: mov al, byte [cursor_x] cmp al, board_width - 1 je .no_right inc al mov byte [cursor_x], al call do_dig mov al, byte [cursor_x] dec al mov byte [cursor_x], al .no_right: ret uncovered_colors: db 0x08, 0x08, 0x0a, 0x0c, 0x0b, 0x0e, 0x09, 0x07, 0x0f uncovered_numbers: db " 12345678" flag: call get_board_flags_at_cursor test al, board_uncovered jnz main_loop xor al, board_flagged push ax call get_cursor_vram_offset mov di, ax pop ax call set_board_flags_at_cursor test al, board_flagged jz .not_flagged mov byte [es:di], flag_character jmp main_loop .not_flagged: mov byte [es:di], ' ' jmp main_loop ;as rows board_flags: times board_width * board_height db 0 board_bomb equ 1 board_uncovered equ 2 board_flagged equ 4 board_numbers: times board_width * board_height db 0 get_board_flags_at_cursor: movzx ax, byte [cursor_y] mov cx, board_width mul cx movzx bx, byte [cursor_x] add bx, ax mov al, byte [board_flags + bx] ret get_cursor_vram_offset: mov cx, word [cursor_x] mov bl, cl add bl, cl add bl, cl add bl, offset_x + 1 mov bh, ch add bh, ch add bh, offset_y + 1 mov cx, 80 movzx ax, bh mul cx xor bh, bh add ax, bx add ax, ax ret ;preserves ax and di set_board_flags_at_cursor: mov si, ax movzx ax, byte [cursor_y] mov cx, board_width mul cx movzx bx, byte [cursor_x] add bx, ax mov ax, si mov byte [board_flags + bx], al ret ;preserves di get_number_at_cursor: movzx ax, byte [cursor_y] mov cx, board_width mul cx movzx bx, byte [cursor_x] add bx, ax mov al, byte [board_numbers + bx] ret cursor_x: db 0 cursor_y: db 0 non_bombs_left: dw 0 controls_str: db "Controls: Arrows - Move Cursor D - Dig F - Flag Q - Quit" .len equ $ - controls_str win: push ds pop es mov ax, 0x1300 mov bx, 0x010f mov cx, .len mov dx, 0x0a24 mov bp, .str int 0x10 jmp win_or_lose .str: db "You win!" .len equ $ - .str lose: push ds pop es mov ax, 0x1300 mov bx, 0x010f mov cx, .len mov dx, 0x0a23 mov bp, .str int 0x10 jmp win_or_lose .str: db "You lose!" .len equ $ - .str win_or_lose: mov ax, 0x1300 mov bx, 0x010f mov cx, .len mov dx, 0x0c1d mov bp, .str int 0x10 xor ax, ax int 0x16 mov ax, 0x0500 int 0x10 mov ax, 0x4c00 int 0x21 .str: db "Press any key to quit." .len equ $ - .str