News:

Masm32 SDK description, downloads and other helpful links
Message to All Guests
NB: Posting URL's See here: Posted URL Change

Main Menu

4x4 Game

Started by zedd151, February 24, 2025, 03:29:56 PM

Previous topic - Next topic

zedd151

Since I am pulling out some old code to repost, here is the 4x4 Game.
Object of the game, is to use the arrow keys to move the pieces of the randomly generated puzzle (example shown here):


To acheive the numerically ordered layout as shown here:
(The Number on the Title Bar is how many moves it took to solve the puzzle.)  :wink2:


Keyboard Mappings:
Left Arrow = move left
Up Arrow = move up
Right Arrow = move right
Down Arrow = move down

Other keyboard functions:
Enter = auto solve from position
Esc = quit game
R = restart game
N = New Game

The game itself works as is. There are a few minor errors in the code that don't seem to bother the operation of the program i.e., it will not crash. Tested on Windows xp, 7 and 10. If anyone would like to address the issues in the code, go for it. This project is basically abandoned - if you think that you have found a bug, fix it yourself - it's all yours!.  :greensml:  Happy coding!  :biggrin:

The file 'strings.dat' are for use with the autosolver, and must be present to re-assemble the program. At the time, it was a convenient way to store the least known number of moves from one position to another - and it seems to work pretty good.  :azn:
¯\_(ツ)_/¯
tictactoe_final is finished    :smiley:
Sometimes is needed some slice n dice to make the forum look nice.

sinsi

Works fine here :thumbsup:

I wonder if the strange behaviour is caused by WndProc using esi and edi but not saving them?

zedd151

#2
Quote from: sinsi on February 24, 2025, 04:25:10 PMWorks fine here :thumbsup:

I wonder if the strange behaviour is caused by WndProc using esi and edi but not saving them?
No strange behavior has been noticed, else I would have acted accordingly. Mind you this code is probably six years old, and I have no intentions of doing any more work on it - since it works as-is. (read below).
There are some calls that rely on ebx for instance, having a value already set in ebx inside the called function. There may be other functions that also rely on esi and edi having preset values. It never caused any issues, so I never bothered to preserve the registers. You can do that for yourself, if you would like, since this is abandonware (read below).  :smiley:
¯\_(ツ)_/¯
tictactoe_final is finished    :smiley:
Sometimes is needed some slice n dice to make the forum look nice.

zedd151

#3
I have had an epiphany while I slept. When I have a free weekend, I will try to decipher my old code here (my notes I had when writing it, have been lost), and bring it up to 21st century standards I.e., win32 ABI specs.  :tongue:  It of course may take some time. So, the project is no longer abandoned, but reclaimed as a project that will be enhanced/fixed/renewed.  :biggrin:

I will probably work on this concurrently with my Connect 4 and Tic-Tac-Toe code.  :smiley:  I need a break from my top secret projects.  :tongue:

P.S. I found an earlier version of the original 4x4 code... but not my notes (for auto solve, and the GUI code).  :biggrin:
4x4 console game. It 10 years old!!! Wow, time flies.
    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
    ;;                                                ;;
    ;; 4x4 game - console version - Movember 5, 2015  ;;
    ;;                    by zedd                    ;;
    ;;                                                ;;
    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
    ;;                                                ;;
    ;;  The object of the game is to use the arrow    ;;
    ;;  keys on the keyboard to arrange the numbered  ;;
    ;;  'pieces' so that they are in numerically      ;;
    ;;  ascending sequence:                          ;;
    ;;                                                ;;
    ;;  ---------------                              ;;
    ;;    1  2  3  4                              ;;
    ;;    5  6  7  8                              ;;
    ;;    9  10  11  12                              ;;
    ;;  13  14  15                                  ;;
    ;;  ---------------                              ;;
    ;;                                                ;;
    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

    include \masm32\include\masm32rt.inc

        set_board      proto :dword, :dword
        randb          proto :dword
        moveit          proto :dword, :dword, :dword, :dword, :dword, :dword, :dword
        board_to_string proto :dword, :dword
        find_mt        proto :dword, :dword

    .data
        sqct            dd 4 dup (0)
        board          dd 4 dup (0)
        str1            db 16 dup (0)
        str2            db 16 dup (0)
        str3            db 16 dup (0)
        str4            db 16 dup (0)
        mt_offs        dd 0

        ; equates for key presses
        quit  = 1Bh                        ; <Esc> key
        up    = 48h                        ; 'up' arrow key
        left  = 4Bh                        ; 'left' arrow key
        right = 4Dh                        ; 'right' arrow key
        down  = 50h                        ; 'down' arrow key

    .code

    start:

        invoke set_board, addr board, addr sqct
        jmp printit                        ; skip over the move routines
    moveleft:
        invoke moveit, addr board, mt_offs,3,7,11,15,1
        jmp printit                        ; jump to print results of move
    moveup:
        invoke moveit, addr board, mt_offs,12,13,14,15,4
        jmp printit                        ; jump to print results of move
    moveright:
        invoke moveit, addr board, mt_offs,0,4,8,12,-1
        jmp printit                        ; jump to print results of move
    movedown:
        invoke moveit, addr board, mt_offs,0,1,2,3,-4
                                            ; stay here to print results of move
    printit:
        invoke board_to_string, addr board, addr str1
        invoke find_mt, addr board, addr mt_offs
        cls
        print offset str1,13,10
        print offset str2,13,10
        print offset str3,13,10
        print offset str4,13,10,13,10

    startloop:                              ; keyboard message loop
        call crt__getch                    ; retrieve keyboard char
        cmp eax, quit
            jz quitting                    ; get ouitta here!
        cmp eax, left
            jz moveleft                    ; move left
        cmp eax, up
            jz moveup                      ; move up
        cmp eax, right
            jz moveright                    ; move right
        cmp eax, down
            jz movedown                    ; move down
    jmp startloop

    quitting:
        invoke ExitProcess, 0              ; adios amigo!

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

    randb proc base:dword
    .data
        seed dd 12345678
    .code
        push edx
        push ecx
        invoke GetTickCount
        add eax, seed
        test eax, 80000000h
        jz  @F
        add eax, 7fffffffh
      @@: 
        xor edx, edx
        mov ecx, 127773
        div ecx
        mov ecx, eax
        mov eax, 16807
        mul edx
        mov edx, ecx
        mov ecx, eax
        mov eax, 2836
        mul edx
        sub ecx, eax
        xor edx, edx
        mov eax, ecx
        mov seed, ecx
        div base
        mov eax, edx
        inc eax
        pop ecx
        pop edx
        ret 4
    randb endp

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

    set_board proc pbrd:dword, psqct:dword
        push esi
        push edi
        mov esi, pbrd                      ; pointer to byte values representing the game board
        mov edi, psqct                      ; pointer to byte array acting as 'valid piece' counter
    toppa:
        push ecx
        invoke randb, 16                    ; generate random value for location
        pop ecx
        mov edx, eax
        dec edx
        push edx
        invoke randb, 15                    ; generate random value for game piece
        pop edx
        mov ecx, eax
        dec ecx
        ; both of these values must be zero to create a new valid game piece

        cmp byte ptr [edi+ecx], 0          ; check if location is empty
        jnz @f
        cmp byte ptr [esi+edx], 0          ; check if piece value is not already used
        jnz @f

        mov byte ptr [esi+edx], al          ; write new piece value to location
        mov byte ptr [edi+ecx], 1          ; set counter for piece value to 1
                                            ; indicating the value has been used already
    @@:
        xor eax, eax                        ; clear eax for the next step
        xor ecx, ecx                        ; clear ecx for the next step
    @@:
        add al, byte ptr [edi+ecx]          ; adding up all of the piece value counters
        inc ecx
        cmp ecx, 16                        ; check all 16 possible locations
        jl @b
        cmp eax, 15                        ; check all possible piece values
        jnz toppa
        pop edi
        pop esi
        ret
    set_board endp

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

    moveit proc pbrd:dword, mt:dword, i1:dword, i2:dword, i3:dword, i4:dword, v7:dword
        push esi
        push edi
        mov esi, pbrd                      ; pointer to game board
        mov ecx, mt                        ; pointer to empty square
        cmp ecx, i1                        ; check against illegal move #1
        jz @f
        cmp ecx, i2                        ; check against illegal move #2
        jz @f
        cmp ecx, i3                        ; check against illegal move #3
        jz @f
        cmp ecx, i4                        ; check against illegal move #4
        jz @f
        mov edi, ecx                        ; move empty location to edi
        add edi, v7                        ; add movement offset
        mov al, [esi+ecx]                  ; swap values of the two squares
        mov dl, [esi+edi]                  ; source square now becomes the empty square
        mov [esi+edi], al                  ; empty square now becomes filled with source value
        mov [esi+ecx], dl
    @@:
        pop edi
        pop esi
        ret
    moveit endp

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

    find_mt proc pbrd:dword, pmtoffs:dword  ; simple proc that scans all locations
        xor eax, eax                        ; to locate the empty square
        mov ecx, pbrd                      ; pointer to game board
    @@:
        cmp byte ptr [ecx+eax], 0          ; loooking for zero
        jz @f
        inc eax
        jmp @b
    @@:
        mov ecx, pmtoffs
        mov [ecx], eax                      ; saving the location of the empty square
        ret
    find_mt endp

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

    board_to_string proc brd:dword, pstr1:dword
        push esi
        push edi
        mov esi, brd                        ; pointer to game board
        mov edi, pstr1                      ; pointer to string buffer
        xor edx, edx
    top:
        xor ecx, ecx

        @@:
            xor eax, eax
            movzx eax, byte ptr [esi+ecx]  ; get hexadecimal digit from board
            aaa                            ; if greater than 9 split into 2 decimal digits
            add ax, 3030h                  ; add 30h to each byte,
                                            ; effectively converting the bytes to ascii chars

                cmp ax, 3030h              ; if pair of bytes equals ascii '00'
                jnz gg
                mov ax, 2020h              ; replace with 2 spaces
                gg:

                cmp ah, 30h                ; if leading digit is zero
                jnz hh
                mov ah, 20h                ; replace with space
                hh:

            mov byte ptr [edi+edx], ah      ; write leading ascii digit to string
            inc edx                        ; increment string index
            mov byte ptr [edi+edx], al      ; write trailing ascii digit to string
            inc edx                        ; increment string index
            mov byte ptr [edi+edx], 20h    ; write space
            inc edx                        ; increment string index
            inc ecx                        ; increment source index
            cmp ecx, 4                      ; compare to 4
        jnz @b                              ; not 4? - jmp back

        cmp edx, 3Ch                        ; compare to 40h - 4
        jz done                            ; if equal, we're done!

        add edx, 4                          ; -- else -- add 4 to string index
        add esi, 4                          ; increment source offset by 4
    jmp top                                ; loop back to top
        done:
        pop edi                            ; restore esi, edi
        pop esi
        ret                                ; return to caller
    board_to_string endp

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

end start
There is a serious issue with this early version. The random board generator generates a solvable game only 50% of the time. The later version starts with a solved game, and scrambles the tiles (many times using valid moves) randomly to ensure every game is solvable. A cute lil game nonetheless.

About 4x4 console:
about 4x4 console version (final)

Written with MASM32.
November 5, 2015
Coded by zedd in the twilight hours.
Built from the ground up, brick-by-brick.
Bugs were fully  tested - and they are
working properly!
A blast from the past!
¯\_(ツ)_/¯
tictactoe_final is finished    :smiley:
Sometimes is needed some slice n dice to make the forum look nice.