News:

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

Main Menu

Tic-Tac-Toe Game

Started by zedd151, February 24, 2025, 01:50:48 PM

Previous topic - Next topic

zedd151

Otherwise known as "Noughts and Crosses", by some countries that "allegedly" share the same language as Americans.  :tongue:



No bitmaps were used, harmed, or mistreaed during the production of this program.  :tongue:
You cannot view this attachment.


Found a minor error, in that a draw condition (board is full after a move) was checked, before checking for a winning condition (either X or O has three in a row). When the last piece set filled up the board it was considered a draw, even though the last move resulted in a winning position.  :joking:  Fixed!
¯\_(ツ)_/¯
tictactoe_final is finished    :smiley:

zedd151

#1
Fully Commented (* note 4) example of the methods that I ultimately used in tic-tac-toe, eliminating the need for actual  bitmaps (*.bmp) or any other resource images. Full source code for tic-tac-toe is presented in post #3, #4, and #5 below.

Function and variable names (used here) are for demonstration purposes. You may of course choose other names.  :biggrin:

;  Example Code:


    Custom1 proto :dword, :dword

    .data?
   
        hDC_Custom1    dd ?                                            ;; global variable for hDC_Custom1
        hBmp_Custom1    dd ?                                            ;; global variable for hBmp_Custom1
        hBmpOld_Custom1 dd ?                                            ;; global variable for hBmpOld_Custom1

    .code

    Custom1 proc hWin:dword, bclr:dword
    local hDC:dword, hPen:dword, hBrush:dword, hBrushOld:dword, hPenOld:dword
        invoke GetDC, hWin                                              ;; get client area DC of main window
        mov hDC, eax                                                    ;; save as local variable
        invoke CreateCompatibleDC, hDC
        mov hDC_Custom1, eax                                            ;; save as global variable - important * note2
        invoke CreateCompatibleBitmap, hDC, 140, 140
        mov hBmp_Custom1, eax                                          ;; save as global variable - important * note2
        invoke SelectObject, hDC_Custom1, hBmp_Custom1
        mov hBmpOld_Custom1, eax                                        ;; save as global variable - important * note2

    ;; any brushes, pens or other gdi objects used after this points should be kept local, and
    ;; deleted here after finished using them

        ;; this piece of code fills the 'bitmap' with the background color 'bclr'.
        ;; important if your custom drawn bitmap has 'transparent' elements to it, and may be omitted otherwise.
       
        invoke CreateSolidBrush, bclr                                  ;; create brush in background color 'bclr'
        mov hBrush, eax                                                ;; store in hBrush
        invoke GetPixel, hDC_Custom1, 1, 1                              ;; get the current color
        invoke SelectObject, hDC_Custom1, hBrush                        ;; select hBrush
        mov hBrushOld, eax
        invoke ExtFloodFill, hDC_Custom1, 1, 1, eax, FLOODFILLSURFACE  ;; flood fill everything that is current color
        invoke SelectObject, hDC_Custom1, hBrushOld                    ;; select hBrushOld
        invoke DeleteObject, hBrush                                    ;; delete hBrush

        ;; ######################################################################
        ;;
        ;;    this area is where you will draw your lines, rectangles, ellipses, etc.
        ;;    after using brushes, pens, etc., you must delete them when no longer needed.
        ;;
        ;; ######################################################################
       

        ;; do NOT delete hDC_Custom1, hBmp_Custom1, or hBmpOld_Custom1 Here!!!
        ;; delete them in WM_CLOSE... that is the reason to keep those variables global in scope.
       
        invoke ReleaseDC, hWin, hDC                                    ;; release main window DC
        ret
    Custom1 endp


      note1  Now you can call this function from WM_CREATE to create your custom drawn bitmap
      note2  You can now use the handle, hDC_Custom1 to BitBlt your custom drawn bitmap into the DC in WM_PAINT...
              ... the DC used will depend on whether double buffering is used or not.
      note3  You must delete hDC_Custom1, hBmp_Custom1 in WM_CLOSE


      typical usage:

    ;;  .elseif uMsg == WM_CREATE
    ;;    invoke Custom1, hWin, BackColor  ; BackColor is whatever background color you want to use.


    ;;  .elseif uMsg == WM_CLOSE
    ;;    invoke SelectObject, hDC_Custom1, hBmpOld_Custom1                    ;; select old bmp
    ;;    invoke DeleteObject, hBmp_Custom1                                    ;; delete bmp
    ;;    invoke DeleteDC, hDC_Custom1                                        ;; delete DC

That is it, in a nutshell.
It strikes me that since I have here the function name appended to its accociated handle names, I could probably make a qeplugin for inserting the template code into an asm source using a dialog box for choosing the desired name.  :biggrin:  More on that, in a new topic near you soon.

note 4:  :tongue:   
You cannot view this attachment.

Found a minor error, in that a draw condition (board is full after a move) was checked, before checking for a winning condition (either X or O has three in a row). When the last piece set filled up the board it was considered a draw, even though the last move resulted in a winning position.  :joking:  Fixed!
¯\_(ツ)_/¯
tictactoe_final is finished    :smiley:

jj2007

Similar but with serious flaws in the game logic :cool:

zedd151

#3
Yes jj, I have seen your "rounded coloured buttons" version before.

Source code of tic-tac-toe (part1)
Contains the header and WndProc
        include \masm32\include\masm32rt.inc

        WinMain        proto :dword                                  ; duh, winmain
        WndProc        proto :dword, :dword, :dword, :dword          ; wndproc
        CenterMain      proto :dword, :dword, :dword, :dword, :dword  ; to center main window on screen
        SetSBParts      proto :dword, :dword                          ; set status bar parts

        randb          proto :dword                                  ; pseudo random generator
        Mouse2Index    proto :dword                                  ; convert mouse x/y to board index
        initialize      proto :dword, :dword, :dword                  ; initialize settings to starting position
        checkdraw      proto :dword                                  ; check if game is tied
        checkwin        proto                                        ; check if game has been won
        findmove        proto :dword, :dword                          ; find best move for computer
                                                                      ; also a built in chance for a random move
        ;; memory bitmap creation procedures:

        vert            proto :dword, :dword  ; vertical game board element
        horz            proto :dword, :dword  ; horizontal game board element
        ttip            proto :dword, :dword  ; top tip of the vertical board element
        btip            proto :dword, :dword  ; bottom tip of the vertical board element
        ltip            proto :dword, :dword  ; left tip of the horizontal board element
        rtip            proto :dword, :dword  ; right tip of the horizontal board element
        isec            proto :dword, :dword  ; intersection between horizontal and vertical elements
        DrawO          proto :dword, :dword  ; "O" playing piece
        DrawX          proto :dword, :dword  ; "X" playing piece

        DrawBanner      proto :dword, :dword, :dword, :dword, :dword    ; title banner

        wwidth          equ 900                                        ; arbitrary main window width
        wheight        equ 600                                        ; arbitrary main window height
        stst            equ WS_CHILD or WS_VISIBLE or SBS_SIZEGRIP
        cwidth          equ 480                                        ; desired client area width
        cheight        equ 554                                        ; desired client are height

        bcolor          equ 00080808h                                  ; background color
        red            equ 002020FFh                                  ; "X" piece color
        blue            equ 00FF2020h                                  ; "O" piece color

 ;        bcolor          equ 00DFDFDFh                                ; background color
 ;        red            equ 008F8F8Fh                                  ; "X" piece color
 ;        blue            equ 004F4F4Fh                                  ; "O" piece color

        ;; x/y coords for tic-tac-toe "pieces"
        ;; left/top coords for mouse clicks

        x1              equ 18                      ; leftmost column
        x2              equ 170                    ; center column
        x3              equ 322                    ; rightmost column
        y1              equ 88                      ; top row
        y2              equ 240                    ; middle row
        y3              equ 392                    ; bottom row

        ;; right/botoom coords for mouse click

        j1              equ 158
        j2              equ 310
        j3              equ 462
        k1              equ 228
        k2              equ 380
        k3              equ 532

        delay          equ 200                    ;; computer player timer delay
        randomfactor    equ 50                      ;; random factor:  approx. 1 out of n moves is random move

    .const
        DispName        db "tic-tac-toe", 0
        Class          db "Template_Class", 0
        cn              dd Class                    ;; pointer to class name
        dn              dd DispName                ;; pointer to display name

    .data
        board label byte
        a1              db 0 ; cell 1
        b1              db 0 ; cell 2
        c1              db 0 ; cell 3
        d1              db 0 ; cell 4
        e1              db 0 ; cell 5
        f1              db 0 ; cell 6
        g1              db 0 ; cell 7
        h1              db 0 ; cell 8
        i1              db 0 ; cell 9
                        db 3 dup (0) ; padding
        player          dd 0                        ; number of player 1=human; 2=computer
        hWnd            dd 0
        hInstance      dd 0
        hStatus        dd 0
        hFont          dd 0

        hDC_horz        dd 0 ; horizontal board element DC handle
        hBmp_horz      dd 0 ; horizontal board element bitmap handle
        hBmpOld_horz    dd 0 ; horizontal board element old bitmap handle
        hDC_vert        dd 0 ; vertical board element DC handle
        hBmp_vert      dd 0 ; vertical board element bitmap handle
        hBmpOld_vert    dd 0 ; vertical board element old bitmap handle
        hDC_O          dd 0 ; piece O DC handle
        hBmp_O          dd 0 ; piece O bitmap handle
        hBmpOld_O      dd 0 ; piece O old bitmap handle
        hDC_X          dd 0 ; piece X DC handle
        hBmp_X          dd 0 ; piece X bitmap handle
        hBmpOld_X      dd 0 ; piece X old bitmap handle
        hDC_ttip        dd 0 ; vertical top tip board element DC handle
        hBmp_ttip      dd 0 ; vertical top tip board element bitmap handle
        hBmpOld_ttip    dd 0 ; vertical top tip board element old bitmap handle
        hDC_btip        dd 0 ; vertical bottom tip board element DC handle
        hBmp_btip      dd 0 ; vertical bottom tip board element bitmap handle
        hBmpOld_btip    dd 0 ; vertical bottom tip board element old bitmap handle
        hDC_ltip        dd 0 ; horizontal left tip board element DC handle
        hBmp_ltip      dd 0 ; horizontal left tip board element bitmap handle
        hBmpOld_ltip    dd 0 ; horizontal left tip board element old bitmap handle
        hDC_rtip        dd 0 ; horizontal right tip board element DC handle
        hBmp_rtip      dd 0 ; horizontal right tip board element bitmap handle
        hBmpOld_rtip    dd 0 ; horizontal right tip board element old bitmap handle
        hDC_isec        dd 0 ; intersection board element DC handle
        hBmp_isec      dd 0 ; intersection board element bitmap handle
        hBmpOld_isec    dd 0 ; intersection board element old bitmap handle
    .code

    start:
        invoke GetModuleHandle, 0
        mov hInstance, eax
        invoke WinMain, hInstance
        invoke ExitProcess, eax

    WndProc proc hWin:dword, uMsg:dword, wParam:dword, lParam:dword
    local rct:RECT, ps:PAINTSTRUCT, hDC:dword, mDC:dword, hBmp:dword, hBmpOld:dword
    local hBrush:dword, hBrushOld:dword

      .if uMsg == WM_CREATE
        invoke CenterMain, hWin, cwidth, cheight, wwidth, wheight
        invoke MoveWindow, hStatus, 0, 0, 0, 0, TRUE
        invoke SetSBParts, hWnd, hStatus
        fn RetFontHandle, "comic sans ms", 72, 700
        mov hFont, eax
        mov player, 1

        ; create memory bitmaps for game board elements

        invoke vert, hWin, bcolor ; create vertical element
        invoke horz, hWin, bcolor ; create horizontal element
        invoke ttip, hWin, bcolor ; create top tip for vert element
        invoke btip, hWin, bcolor ; create bottom tip for vert element
        invoke ltip, hWin, bcolor ; create left tip for horz element
        invoke rtip, hWin, bcolor ; create right tip for horz element
        invoke isec, hWin, bcolor ; create intersection between vert & horz

        ; create playing pieces

        invoke DrawO, hWin, bcolor ; create O
        invoke DrawX, hWin, bcolor ; create X
      .elseif uMsg == WM_LBUTTONUP
        .if player == 1
          invoke Mouse2Index, lParam
          cmp eax, -1
          jz @f
          lea ecx, board
          .if byte ptr [ecx+eax] == 0
            mov byte ptr [ecx+eax], 1
            invoke InvalidateRect, hWin, 0, 0
            mov player, 2                                            ; set player 1=human, 2=computer
            invoke SetTimer, hWin, 100, delay, 0                      ; set timer to activate opponent
          .endif
            call checkwin
            .if eax == 1
              invoke KillTimer, hWin, 100                            ; kill timer
              fn MessageBox, hWnd, " X Wins! ", "Game Over!", 0      ; display Game Over and reason
              invoke initialize, hWin, addr board, addr player        ; initialize game
              xor eax, eax
              ret                                                    ; return
            .elseif eax == 2
              invoke KillTimer, hWin, 100                            ; kill timer
              fn MessageBox, hWnd, " O Wins! ", "Game Over!", 0      ; display Game Over and reason
              invoke initialize, hWin, addr board, addr player        ; initialize game
              xor eax, eax
              ret                                                    ; return
            .endif
              invoke checkdraw, addr board                            ; check if board is full
              .if eax == 1                                            ; if board is full
                invoke KillTimer, hWin, 100                          ; kill timer
                fn MessageBox, hWnd, " - Draw! - ", "Game Over!", 0  ; display Game Over and reason
                invoke initialize, hWin, addr board, addr player      ; initialize game
                xor eax, eax
                ret                                                  ; return
              .endif
          @@:
        .endif
      .elseif uMsg == WM_TIMER
        .if wParam == 100
          .if player == 2
            invoke KillTimer, hWin, 100                            ; kill timer
            invoke findmove, addr board, randomfactor
            lea ecx, board
            mov byte ptr [ecx+eax], 2
            mov player, 1
            invoke InvalidateRect, hWin, 0, 0

            call checkwin
            .if eax == 1
              fn MessageBox, hWnd, " X Wins! ", "Game Over!", 0      ; display Game Over and reason
              invoke initialize, hWin, addr board, addr player        ; initialize game
              xor eax, eax
              ret                                                    ; return
            .elseif eax == 2
              fn MessageBox, hWnd, " O Wins! ", "Game Over!", 0      ; display Game Over and reason
              invoke initialize, hWin, addr board, addr player        ; initialize game
              xor eax, eax
              ret                                                    ; return
            .endif
            invoke checkdraw, addr board                              ; check if board is full
            .if eax == 1                                              ; if board is full
              fn MessageBox, hWnd, " - Draw! - ", "Game Over!", 0    ; display Game Over and reason
              invoke initialize, hWin, addr board, addr player        ; initialize game
              xor eax, eax
              ret                                                    ; return
            .endif
          .endif
        .endif
      .elseif uMsg == WM_COMMAND
        .if wParam == 1900
          fn MessageBox, 0, "tic-tac-toe final edition", dn, MB_OK
        .endif
      .elseif uMsg == WM_PAINT
        ;;  WM_PAINT startup code

        invoke BeginPaint, hWin, addr ps
        mov hDC, eax
        invoke GetClientRect, hWin, addr rct
        invoke CreateCompatibleDC, hDC
        mov mDC, eax
        invoke CreateCompatibleBitmap, hDC, rct.right, rct.bottom
        mov hBmp, eax
        invoke SelectObject, mDC, hBmp
        mov hBmpOld, eax

        ;;  draw background color

        invoke CreateSolidBrush, bcolor
        mov hBrush, eax
        invoke SelectObject, mDC, hBrush
        mov hBrushOld, eax
        invoke FillRect, mDC, addr rct, hBrush
        invoke SelectObject, mDC, hBrushOld
        invoke DeleteObject, hBrush

        ;;  draw game title text

        invoke DrawBanner, mDC, 48, 0, hFont, red

        ;;  draw tic-tac-toe board elements

        invoke BitBlt, mDC, 158,  88,  12, 140, hDC_vert, 0, 0, SRCCOPY  ;; place vertical grid elements
        invoke BitBlt, mDC, 310,  88,  12, 140, hDC_vert, 0, 0, SRCCOPY
        invoke BitBlt, mDC, 158, 240,  12, 140, hDC_vert, 0, 0, SRCCOPY
        invoke BitBlt, mDC, 310, 240,  12, 140, hDC_vert, 0, 0, SRCCOPY
        invoke BitBlt, mDC, 158, 392,  12, 140, hDC_vert, 0, 0, SRCCOPY
        invoke BitBlt, mDC, 310, 392,  12, 140, hDC_vert, 0, 0, SRCCOPY
        invoke BitBlt, mDC,  18, 228, 140, 12, hDC_horz, 0, 0, SRCCOPY  ;; place horizontal grid elements
        invoke BitBlt, mDC, 170, 228, 140, 12, hDC_horz, 0, 0, SRCCOPY
        invoke BitBlt, mDC, 322, 228, 140, 12, hDC_horz, 0, 0, SRCCOPY
        invoke BitBlt, mDC,  18, 380, 140, 12, hDC_horz, 0, 0, SRCCOPY
        invoke BitBlt, mDC, 170, 380, 140, 12, hDC_horz, 0, 0, SRCCOPY
        invoke BitBlt, mDC, 322, 380, 140, 12, hDC_horz, 0, 0, SRCCOPY
        invoke BitBlt, mDC, 158,  82,  12,  6, hDC_ttip, 0, 0, SRCCOPY  ;; place top tip of vertical grid elements
        invoke BitBlt, mDC, 310,  82,  12,  6, hDC_ttip, 0, 0, SRCCOPY
        invoke BitBlt, mDC, 158, 532,  12, 6, hDC_btip, 0, 0, SRCCOPY  ;; place bottom tip of vertical grid elements
        invoke BitBlt, mDC, 310, 532,  12, 6, hDC_btip, 0, 0, SRCCOPY
        invoke BitBlt, mDC,  12, 228,  6, 12, hDC_ltip, 0, 0, SRCCOPY  ;; place left tip of horizontal grid elements
        invoke BitBlt, mDC,  12, 380,  6, 12, hDC_ltip, 0, 0, SRCCOPY
        invoke BitBlt, mDC, 462, 228,  6, 12, hDC_rtip, 0, 0, SRCCOPY  ;; place right tip of horizontal grid elements
        invoke BitBlt, mDC, 462, 380,  6, 12, hDC_rtip, 0, 0, SRCCOPY
        invoke BitBlt, mDC, 158, 228, 12, 12, hDC_isec, 0, 0, SRCCOPY  ;; place intersection of vertical and horizontal...
        invoke BitBlt, mDC, 310, 228, 12, 12, hDC_isec, 0, 0, SRCCOPY  ;; ... grid elements
        invoke BitBlt, mDC, 158, 380, 12, 12, hDC_isec, 0, 0, SRCCOPY
        invoke BitBlt, mDC, 310, 380, 12, 12, hDC_isec, 0, 0, SRCCOPY

        ;;  set pieces depend on board value at given offset ; 1 = X ; 2 = O

      .if    board[0] == 1
        invoke BitBlt, mDC, x1, y1, 140, 140, hDC_X, 0, 0, SRCCOPY
      .elseif board[0] == 2
        invoke BitBlt, mDC, x1, y1, 140, 140, hDC_O, 0, 0, SRCCOPY
      .endif
      .if    board[1] == 1
        invoke BitBlt, mDC, x2, y1, 140, 140, hDC_X, 0, 0, SRCCOPY
      .elseif board[1] == 2
        invoke BitBlt, mDC, x2, y1, 140, 140, hDC_O, 0, 0, SRCCOPY
      .endif
      .if    board[2] == 1
        invoke BitBlt, mDC, x3, y1, 140, 140, hDC_X, 0, 0, SRCCOPY
      .elseif board[2] == 2
        invoke BitBlt, mDC, x3, y1, 140, 140, hDC_O, 0, 0, SRCCOPY
      .endif
      .if    board[3] == 1
        invoke BitBlt, mDC, x1, y2, 140, 140, hDC_X, 0, 0, SRCCOPY
      .elseif board[3] == 2
        invoke BitBlt, mDC, x1, y2, 140, 140, hDC_O, 0, 0, SRCCOPY
      .endif
      .if    board[4] == 1
        invoke BitBlt, mDC, x2, y2, 140, 140, hDC_X, 0, 0, SRCCOPY
      .elseif board[4] == 2
        invoke BitBlt, mDC, x2, y2, 140, 140, hDC_O, 0, 0, SRCCOPY
      .endif
      .if    board[5] == 1
        invoke BitBlt, mDC, x3, y2, 140, 140, hDC_X, 0, 0, SRCCOPY
      .elseif board[5] == 2
        invoke BitBlt, mDC, x3, y2, 140, 140, hDC_O, 0, 0, SRCCOPY
      .endif
      .if    board[6] == 1
        invoke BitBlt, mDC, x1, y3, 140, 140, hDC_X, 0, 0, SRCCOPY
      .elseif board[6] == 2
        invoke BitBlt, mDC, x1, y3, 140, 140, hDC_O, 0, 0, SRCCOPY
      .endif
      .if    board[7] == 1
        invoke BitBlt, mDC, x2, y3, 140, 140, hDC_X, 0, 0, SRCCOPY
      .elseif board[7] == 2
        invoke BitBlt, mDC, x2, y3, 140, 140, hDC_O, 0, 0, SRCCOPY
      .endif
      .if    board[8] == 1
        invoke BitBlt, mDC, x3, y3, 140, 140, hDC_X, 0, 0, SRCCOPY
      .elseif board[8] == 2
        invoke BitBlt, mDC, x3, y3, 140, 140, hDC_O, 0, 0, SRCCOPY
      .endif

        ;;  WM_PAINT ending code and cleanup

        invoke GetClientRect, hWin, addr rct
        invoke BitBlt, hDC, 0, 0, rct.right, rct.bottom, mDC, 0, 0, SRCCOPY
        invoke SelectObject, mDC, hBmpOld
        invoke DeleteObject, hBmp
        invoke DeleteDC, mDC
        invoke EndPaint, hWin, addr ps
        mov eax, 0
        ret
      .elseif uMsg == WM_SIZE
        invoke MoveWindow, hStatus, 0, 0, 0, 0, TRUE
        invoke SetSBParts, hWnd, hStatus
      .elseif uMsg == WM_CLOSE
        ;; deleting self drawn Bmp's and associated DC's
        ;; that were created from within WM_CREATE

        invoke SelectObject, hDC_ttip, hBmpOld_ttip  ;; select old bmp to the associated DC
        invoke DeleteObject, hBmp_ttip              ;; delete the bmp
        invoke DeleteDC, hDC_ttip                    ;; delete the DC
        invoke SelectObject, hDC_btip, hBmpOld_btip  ;; exact same steps for those that follow:
        invoke DeleteObject, hBmp_btip
        invoke DeleteDC, hDC_btip
        invoke SelectObject, hDC_ltip, hBmpOld_ltip
        invoke DeleteObject, hBmp_ltip
        invoke DeleteDC, hDC_ltip
        invoke SelectObject, hDC_rtip, hBmpOld_rtip
        invoke DeleteObject, hBmp_rtip
        invoke DeleteDC, hDC_rtip
        invoke SelectObject, hDC_vert, hBmpOld_vert
        invoke DeleteObject, hBmp_vert
        invoke DeleteDC, hDC_vert
        invoke SelectObject, hDC_horz, hBmpOld_horz
        invoke DeleteObject, hBmp_horz
        invoke DeleteDC, hDC_horz
        invoke SelectObject, hDC_isec, hBmpOld_isec
        invoke DeleteObject, hBmp_isec
        invoke DeleteDC, hDC_isec
        invoke SelectObject, hDC_O, hBmpOld_O
        invoke DeleteObject, hBmp_O
        invoke DeleteDC, hDC_O
        invoke SelectObject, hDC_X, hBmpOld_X
        invoke DeleteObject, hBmp_X
        invoke DeleteDC, hDC_X
      .elseif uMsg == WM_DESTROY
        invoke PostQuitMessage, 0
        return 0
      .endif
        invoke DefWindowProc, hWin, uMsg, wParam, lParam
        ret
    WndProc endp
You cannot view this attachment.


¯\_(ツ)_/¯
tictactoe_final is finished    :smiley:

zedd151

#4
Source code of tic-tac-toe (part2)
Contains WinMain and miscellaneous other functions
    WinMain proc hInst:dword
    local wc:WNDCLASSEX, msg:MSG, Wtx:dword, Wty:dword
        mov wc.cbSize, sizeof WNDCLASSEX
        mov wc.style, 0
        mov wc.lpfnWndProc, offset WndProc
        mov wc.cbClsExtra, 0
        mov wc.cbWndExtra, 0
        mrm wc.hInstance, hInst
        mov wc.hbrBackground, COLOR_BTNFACE+2
        mov wc.lpszMenuName, 0
        mov wc.lpszClassName, offset Class
        invoke LoadIcon, 0, IDI_APPLICATION
        mov wc.hIcon, eax
        mov wc.hIconSm, eax
        invoke LoadCursor, 0, IDC_ARROW
        mov wc.hCursor, eax
        invoke RegisterClassEx, addr wc
        invoke CreateWindowEx, 0, cn, dn, WS_OVERLAPPEDWINDOW, 0, 0, wwidth, wheight, 0, 0, hInst, 0
        mov hWnd, eax
        invoke CreateStatusWindow, stst, 0, hWnd, 0
        mov hStatus, eax
        invoke SetSBParts, hWnd, hStatus
        invoke LoadMenu, hInst, 600
        invoke SetMenu, hWnd, eax
        invoke ShowWindow, hWnd, SW_SHOWNORMAL
        invoke UpdateWindow, hWnd
      StartLoop:
        invoke GetMessage, addr msg, 0, 0, 0
        cmp eax, 0
        je ExitLoop
        invoke TranslateMessage, addr msg
        invoke DispatchMessage, addr msg
        jmp StartLoop
      ExitLoop:
        return msg.wParam
    WinMain endp

    ;; automatic center main window according to desired client area size.
    CenterMain proc hWin:dword, clwd:dword, clht:dword, wd:dword, ht:dword
    local rct:RECT, h:dword, w:dword, x:dword, y:dword
      @@: ; dynamically adjusting width of the window for proper client rect size
        invoke MoveWindow, hWin, x, y, wd, ht, 0
        invoke GetClientRect, hWin, addr rct
        mov eax, rct.right
        sub eax, rct.left
      .if eax > clwd ; desired client rect width
        dec wd
        jmp @b
      .elseif eax < clwd
        inc wd
        jmp @b
      .endif
      @@: ; dynamically adjusting height of the window for proper client rect size
        invoke MoveWindow, hWin, x, y, wd, ht, 0
        invoke GetClientRect, hWin, addr rct
        mov eax, rct.bottom
        sub eax, rct.top
      .if eax > clht ; desired client rect height
        dec ht
        jmp @b
      .elseif eax < clht
        inc ht
        jmp @b
      .endif
        add ht, 22
        invoke GetSystemMetrics, SM_CYMENU
        add ht, eax
        invoke SystemParametersInfoA, SPI_GETWORKAREA, 0, addr rct, 0
        mov eax, rct.right
        sub eax, wd
        sar eax, 1
        mov x, eax
        mov eax, rct.bottom
        sub eax, ht
        sar eax, 1
        mov y, eax
        invoke MoveWindow, hWin, x, y, wd, ht, TRUE
        ret
    CenterMain endp

    SetSBParts proc hWin:dword, hStat:dword
    local rct:RECT
        .data?
            sbParts dd 4 dup (?)
        .code
        invoke GetClientRect, hWin, addr rct
        mov eax, rct.right
        sub eax, rct.left
        shr eax, 2
        mov ecx, eax
        mov [sbParts+0], ecx
        add ecx, eax
        mov [sbParts+4], ecx
        add ecx, eax
        mov [sbParts+8], ecx
        mov [sbParts+12], -1
        invoke SendMessage, hStat, SB_SETPARTS, 4, addr sbParts
        ret
    SetSBParts endp

    ;; convert mouse click to board index
    Mouse2Index proc lParam:dword
        mov eax, lParam
        mov ecx, eax
        movzx eax, ax
        shr ecx, 16
      .if    eax >= x1 && eax <= j1
        mov eax, 0
      .elseif eax >= x2 && eax <= j2
        mov eax, 1
      .elseif eax >= x3 && eax <= j3
        mov eax, 2
      .else
        jmp outabound
      .endif
      .if    ecx >= y1 && ecx <= k1
        mov ecx, 0
      .elseif ecx >= y2 && ecx <= k2
        mov ecx, 3
      .elseif ecx >= y3 && ecx <= k3
        mov ecx, 6
      .else
        jmp outabound
      .endif
        add eax, ecx
        ret
      outabound:
        mov eax, -1
        ret
    Mouse2Index endp

    randb proc base:dword
    .data
    random_seed dd 8675309 ; jenny?
    .code
        push edx
        push ecx
        invoke GetTickCount
        add eax, random_seed
        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 random_seed, ecx
        div base
        mov eax, edx
        pop ecx
        pop edx
        ret
    randb endp

    checkdraw proc bored                    ; check to see if board is full
        mov edx, bored                      ; to be called after checkwin
        xor ecx, ecx
        xor eax, eax
      @@:
        cmp byte ptr [edx+ecx], 0
        jz @f
        inc ecx
        cmp ecx, 9
        jnz @b
        mov eax, 1
      @@:
        ret
    checkdraw endp

    initialize proc hWin:dword, bored:dword, lpPlayer:dword  ; initialize game to startup settings
        mov edx, bored
        xor ecx, ecx
      zeroing:
        mov byte ptr [edx+ecx], 0
        inc ecx
        cmp ecx, 9
        jb zeroing
        invoke InvalidateRect, hWin, 0, 0
        mov eax, lpPlayer
        mov dword ptr [eax], 1
        xor eax, eax
        ret
    initialize endp

    checkwin proc ; check each line for a winner
        mov eax, 1
      @@:
      .if    a1 == al && b1 == al && c1 == al
        return eax
      .elseif d1 == al && e1 == al && f1 == al
        return eax
      .elseif g1 == al && h1 == al && i1 == al
        return eax
      .elseif a1 == al && d1 == al && g1 == al
        return eax
      .elseif b1 == al && e1 == al && h1 == al
        return eax
      .elseif c1 == al && f1 == al && i1 == al
        return eax
      .elseif a1 == al && e1 == al && i1 == al
        return eax
      .elseif g1 == al && e1 == al && c1 == al
        return eax
      .endif
        inc eax
        cmp eax, 2
        jbe @b
        return 0
        ret
    checkwin endp
   
    findmove proc bored:dword, randfactor:dword
        invoke randb, randfactor  ; to give a bit of randomness to computers moves
        .if eax == 1              ; i.e., just like a human might
          jmp randmove
        .endif
      ;; find winning moves      ; check for a position that will yield an immediate win
      .if a1 == 0 && b1 == 2 && c1 == 2
        return 0
      .elseif a1 == 2 && b1 == 0 && c1 == 2
        return 1
      .elseif a1 == 2 && b1 == 2 && c1 == 0
        return 2
      .elseif d1 == 0 && e1 == 2 && f1 == 2
        return 3
      .elseif d1 == 2 && e1 == 0 && f1 == 2
        return 4
      .elseif d1 == 2 && e1 == 2 && f1 == 0
        return 5
      .elseif g1 == 0 && h1 == 2 && i1 == 2
        return 6
      .elseif g1 == 2 && h1 == 0 && i1 == 2
        return 7
      .elseif g1 == 2 && h1 == 2 && i1 == 0
        return 8
      .elseif a1 == 0 && d1 == 2 && g1 == 2
        return 0
      .elseif a1 == 2 && d1 == 0 && g1 == 2
        return 3
      .elseif a1 == 2 && d1 == 2 && g1 == 0
        return 6
      .elseif b1 == 0 && e1 == 2 && h1 == 2
        return 1
      .elseif b1 == 2 && e1 == 0 && h1 == 2
        return 4
      .elseif b1 == 2 && e1 == 2 && h1 == 0
        return 7
      .elseif c1 == 0 && f1 == 2 && i1 == 2
        return 2
      .elseif c1 == 2 && f1 == 0 && i1 == 2
        return 5
      .elseif c1 == 2 && f1 == 2 && i1 == 0
        return 8
      .elseif a1 == 0 && e1 == 2 && i1 == 2
        return 0
      .elseif a1 == 2 && e1 == 0 && i1 == 2
        return 4
      .elseif a1 == 2 && e1 == 2 && i1 == 0
        return 8
      .elseif g1 == 0 && e1 == 2 && c1 == 2
        return 6
      .elseif g1 == 2 && e1 == 0 && c1 == 2
        return 4
      .elseif g1 == 2 && e1 == 2 && c1 == 0
        return 2
      .endif
      ;; find blocking moves                ; check for position that will block X's win
      .if a1 == 0 && b1 == 1 && c1 == 1
        return 0
      .elseif a1 == 1 && b1 == 0 && c1 == 1
        return 1
      .elseif a1 == 1 && b1 == 1 && c1 == 0
        return 2
      .elseif d1 == 0 && e1 == 1 && f1 == 1
        return 3
      .elseif d1 == 1 && e1 == 0 && f1 == 1
        return 4
      .elseif d1 == 1 && e1 == 1 && f1 == 0
        return 5
      .elseif g1 == 0 && h1 == 1 && i1 == 1
        return 6
      .elseif g1 == 1 && h1 == 0 && i1 == 1
        return 7
      .elseif g1 == 1 && h1 == 1 && i1 == 0
        return 8
      .elseif a1 == 0 && d1 == 1 && g1 == 1
        return 0
      .elseif a1 == 1 && d1 == 0 && g1 == 1
        return 3
      .elseif a1 == 1 && d1 == 1 && g1 == 0
        return 6
      .elseif b1 == 0 && e1 == 1 && h1 == 1
        return 1
      .elseif b1 == 1 && e1 == 0 && h1 == 1
        return 4
      .elseif b1 == 1 && e1 == 1 && h1 == 0
        return 7
      .elseif c1 == 0 && f1 == 1 && i1 == 1
        return 2
      .elseif c1 == 1 && f1 == 0 && i1 == 1
        return 5
      .elseif c1 == 1 && f1 == 1 && i1 == 0
        return 8
      .elseif a1 == 0 && e1 == 1 && i1 == 1
        return 0
      .elseif a1 == 1 && e1 == 0 && i1 == 1
        return 4
      .elseif a1 == 1 && e1 == 1 && i1 == 0
        return 8
      .elseif g1 == 0 && e1 == 1 && c1 == 1
        return 6
      .elseif g1 == 1 && e1 == 0 && c1 == 1
        return 4
      .elseif g1 == 1 && e1 == 1 && c1 == 0
        return 2
      .endif
      ;; make a random move                        ; make a not so smart random move
      randmove:
        invoke randb, 9
        mov ecx, bored
        .if byte ptr [ecx+eax] == 0
          return eax
        .else
          jmp randmove
        .endif
        ret
    findmove endp
You cannot view this attachment.


¯\_(ツ)_/¯
tictactoe_final is finished    :smiley:

zedd151

#5
Source code of tic-tac-toe (part3)
Contains the functions to draw the banner make my self drawn "bitmaps"
    DrawBanner proc mDC:dword, x:dword, y:dword, font:dword, color:dword  ; draw text "tic-tac-toe" banner
        invoke SetBkMode, mDC, TRANSPARENT
        invoke SetTextColor, mDC, color
        invoke SelectObject, mDC, font
        fn TextOut, mDC, x, y, "tic - tac - toe", 15
        invoke SetBkMode, mDC, OPAQUE
        xor eax, eax
        ret
    DrawBanner endp

    ttip proc hWin:dword, bclr:dword
    local hDC:DWORD, hPen:dword, hPenOld:dword, hBrush:dword, hBrushOld:dword, rct:RECT
        invoke GetDC, hWin  ; get main window client area DC
        mov hDC, eax
        invoke CreateCompatibleDC, hDC
        mov hDC_ttip, eax
        invoke CreateCompatibleBitmap, hDC, 12, 6
        mov hBmp_ttip, eax
        invoke SelectObject, hDC_ttip, hBmp_ttip
        mov hBmpOld_ttip, eax
        invoke CreateSolidBrush, bclr
        mov hBrush, eax
        invoke SelectObject, hDC_ttip, hBrush
        mov hBrushOld, eax
        invoke GetPixel, hDC_ttip, 1, 1
        invoke ExtFloodFill, hDC_ttip, 1, 1, eax, FLOODFILLSURFACE
        invoke SelectObject, hDC_ttip, hBrushOld
        invoke DeleteObject, hBrush
        invoke CreatePen, 0, 1, 00C0C0C0h
        mov hPen, eax
        invoke SelectObject, hDC_ttip, hPen
        mov hPenOld, eax
        invoke CreateSolidBrush, 00C0C0C0h
        mov hBrush, eax
        invoke SelectObject, hDC_ttip, hBrush
        mov hBrushOld, eax
        invoke MoveToEx, hDC_ttip, 0, 5, 0
        invoke LineTo,   hDC_ttip, 5, 0
        invoke LineTo,   hDC_ttip, 5, 5
        invoke LineTo,   hDC_ttip, 0, 5
        invoke FloodFill, hDC_ttip, 3, 3, 00C0C0C0h
        invoke SelectObject, hDC_ttip, hBrushOld
        invoke DeleteObject, hBrush
        invoke SelectObject, hDC_ttip, hPenOld
        invoke DeleteObject, hPen
        invoke CreatePen, 0, 1, 00808080h
        mov hPen, eax
        invoke SelectObject, hDC_ttip, hPen
        mov hPenOld, eax
        invoke CreateSolidBrush, 00808080h
        mov hBrush, eax
        invoke SelectObject, hDC_ttip, hBrush
        mov hBrushOld, eax
        invoke MoveToEx, hDC_ttip, 6, 0, 0
        invoke LineTo,   hDC_ttip, 11, 5
        invoke LineTo,   hDC_ttip, 6, 5
        invoke LineTo,   hDC_ttip, 6, 0
        invoke FloodFill, hDC_ttip, 8, 3, 00808080h
        invoke SelectObject, hDC_ttip, hBrushOld
        invoke DeleteObject, hBrush
        invoke SelectObject, hDC_ttip, hPenOld
        invoke DeleteObject, hPen
        invoke ReleaseDC, hWin, hDC
        ret
    ttip endp

    btip proc hWin:dword, bclr:dword
    local hDC:dword, hPen:dword, hPenOld:dword, hBrush:dword, hBrushOld:dword
        invoke GetDC, hWin  ; get main window client area DC
        mov hDC, eax
        invoke CreateCompatibleDC, hDC
        mov hDC_btip, eax
        invoke CreateCompatibleBitmap, hDC, 12, 6
        mov hBmp_btip, eax
        invoke SelectObject, hDC_btip, hBmp_btip
        mov hBmpOld_btip, eax
        invoke CreateSolidBrush, bclr
        mov hBrush, eax
        invoke SelectObject, hDC_btip, hBrush
        mov hBrushOld, eax
        invoke GetPixel, hDC_btip, 1, 1
        invoke ExtFloodFill, hDC_btip, 1, 1, eax, FLOODFILLSURFACE
        invoke SelectObject, hDC_btip, hBrushOld
        invoke DeleteObject, hBrush
        invoke CreatePen, 0, 1, 00C0C0C0h
        mov hPen, eax
        invoke SelectObject, hDC_btip, hPen
        mov hPenOld, eax
        invoke CreateSolidBrush, 00C0C0C0h
        mov hBrush, eax
        invoke SelectObject, hDC_btip, hBrush
        mov hBrushOld, eax
        invoke MoveToEx, hDC_btip, 0, 0, 0
        invoke LineTo,   hDC_btip, 5, 0
        invoke LineTo,   hDC_btip, 5, 5
        invoke LineTo,   hDC_btip, 0, 0
        invoke FloodFill, hDC_btip, 3, 2, 00C0C0C0h
        invoke SelectObject, hDC_btip, hBrushOld
        invoke DeleteObject, hBrush
        invoke SelectObject, hDC_btip, hPenOld
        invoke DeleteObject, hPen
        invoke CreatePen, 0, 1, 00808080h
        mov hPen, eax
        invoke SelectObject, hDC_btip, hPen
        mov hPenOld, eax
        invoke CreateSolidBrush, 00808080h
        mov hBrush, eax
        invoke SelectObject, hDC_btip, hBrush
        mov hBrushOld, eax
        invoke MoveToEx, hDC_btip, 6, 0, 0
        invoke LineTo,   hDC_btip, 11, 0
        invoke LineTo,   hDC_btip, 6, 5
        invoke LineTo,   hDC_btip, 6, 0
        invoke FloodFill, hDC_btip, 8, 2, 00808080h
        invoke SelectObject, hDC_btip, hBrushOld
        invoke DeleteObject, hBrush
        invoke SelectObject, hDC_btip, hPenOld
        invoke DeleteObject, hPen
        invoke ReleaseDC, hWin, hDC
        ret
    btip endp

    ltip proc hWin:dword, bclr:dword
    local hDC:dword, hPen:dword, hPenOld:dword, hBrush:dword, hBrushOld:dword
        invoke GetDC, hWin  ; get main window client area DC
        mov hDC, eax
        invoke CreateCompatibleDC, hDC
        mov hDC_ltip, eax
        invoke CreateCompatibleBitmap, hDC, 6, 12
        mov hBmp_ltip, eax
        invoke SelectObject, hDC_ltip, hBmp_ltip
        mov hBmpOld_ltip, eax
       
        invoke CreateSolidBrush, bclr
        mov hBrush, eax
        invoke SelectObject, hDC_ltip, hBrush
        mov hBrushOld, eax
        invoke GetPixel, hDC_ltip, 1, 1
        invoke ExtFloodFill, hDC_ltip, 1, 1, eax, FLOODFILLSURFACE
        invoke SelectObject, hDC_ltip, hBrushOld
        invoke DeleteObject, hBrush
       
        invoke CreatePen, 0, 1, 00C0C0C0h
        mov hPen, eax
        invoke SelectObject, hDC_ltip, hPen
        mov hPenOld, eax
        invoke CreateSolidBrush, 00C0C0C0h
        mov hBrush, eax
        invoke SelectObject, hDC_ltip, hBrush
        mov hBrushOld, eax
        invoke MoveToEx, hDC_ltip, 0, 5, 0
        invoke LineTo,   hDC_ltip, 5, 0
        invoke LineTo,   hDC_ltip, 5, 5
        invoke LineTo,   hDC_ltip, 0, 5
        invoke FloodFill, hDC_ltip, 3, 4, 00C0C0C0h
        invoke SelectObject, hDC_ltip, hBrushOld
        invoke DeleteObject, hBrush
        invoke SelectObject, hDC_ltip, hPenOld
        invoke DeleteObject, hPen
        invoke CreatePen, 0, 1, 00808080h
        mov hPen, eax
        invoke SelectObject, hDC_ltip, hPen
        mov hPenOld, eax
        invoke CreateSolidBrush, 00808080h
        mov hBrush, eax
        invoke SelectObject, hDC_ltip, hBrush
        mov hBrushOld, eax
        invoke MoveToEx, hDC_ltip, 0, 6, 0
        invoke LineTo,   hDC_ltip, 5, 6
        invoke LineTo,   hDC_ltip, 5, 11
        invoke LineTo,   hDC_ltip, 0, 6
        invoke FloodFill, hDC_ltip, 3, 8, 00808080h
        invoke SelectObject, hDC_ltip, hBrushOld
        invoke DeleteObject, hBrush
        invoke SelectObject, hDC_ltip, hPenOld
        invoke DeleteObject, hPen
        invoke ReleaseDC, hWin, hDC
        ret
    ltip endp

    rtip proc hWin:dword, bclr:dword
    local hDC:dword, hPen:dword, hPenOld:dword, hBrush:dword, hBrushOld:dword
        invoke GetDC, hWin  ; get main window client area DC
        mov hDC, eax
        invoke CreateCompatibleDC, hDC
        mov hDC_rtip, eax
        invoke CreateCompatibleBitmap, hDC, 6, 12
        mov hBmp_rtip, eax
        invoke SelectObject, hDC_rtip, hBmp_rtip
        mov hBmpOld_rtip, eax
        invoke CreateSolidBrush, bclr
        mov hBrush, eax
        invoke SelectObject, hDC_rtip, hBrush
        mov hBrushOld, eax
        invoke GetPixel, hDC_rtip, 1, 1
        invoke ExtFloodFill, hDC_rtip, 1, 1, eax, FLOODFILLSURFACE
        invoke SelectObject, hDC_rtip, hBrushOld
        invoke DeleteObject, hBrush
        invoke CreatePen, 0, 1, 00C0C0C0h
        mov hPen, eax
        invoke SelectObject, hDC_rtip, hPen
        mov hPenOld, eax
        invoke CreateSolidBrush, 00C0C0C0h
        mov hBrush, eax
        invoke SelectObject, hDC_rtip, hBrush
        mov hBrushOld, eax
        invoke MoveToEx, hDC_rtip, 0, 0, 0
        invoke LineTo,   hDC_rtip, 5, 5
        invoke LineTo,   hDC_rtip, 0, 5
        invoke LineTo,   hDC_rtip, 0, 0
        invoke FloodFill, hDC_rtip, 1, 4, 00C0C0C0h
        invoke SelectObject, hDC_rtip, hBrushOld
        invoke DeleteObject, hBrush
        invoke SelectObject, hDC_rtip, hPenOld
        invoke DeleteObject, hPen
        invoke CreatePen, 0, 1, 00808080h
        mov hPen, eax
        invoke SelectObject, hDC_rtip, hPen
        mov hPenOld, eax
        invoke CreateSolidBrush, 00808080h
        mov hBrush, eax
        invoke SelectObject, hDC_rtip, hBrush
        mov hBrushOld, eax
        invoke MoveToEx, hDC_rtip, 0, 6, 0
        invoke LineTo,   hDC_rtip, 5, 6
        invoke LineTo,   hDC_rtip, 0, 11
        invoke LineTo,   hDC_rtip, 0, 6
        invoke FloodFill, hDC_rtip, 1, 8, 00808080h
        invoke SelectObject, hDC_rtip, hBrushOld
        invoke DeleteObject, hBrush
        invoke SelectObject, hDC_rtip, hPenOld
        invoke DeleteObject, hPen
        invoke ReleaseDC, hWin, hDC
        ret
    rtip endp

    vert proc hWin:dword, bclr:dword
    local hDC:dword, hBack, rct:RECT, hBrush:dword, hBrushOld:dword
        invoke GetDC, hWin  ; get main window client area DC
        mov hDC, eax
        invoke CreateCompatibleDC, hDC
        mov hDC_vert, eax
        invoke CreateCompatibleBitmap, hDC, 12, 140
        mov hBmp_vert, eax
        invoke SelectObject, hDC_vert, hBmp_vert
        mov hBmpOld_vert, eax
        invoke CreateSolidBrush, bclr
        mov hBrush, eax
        invoke SelectObject, hDC_vert, hBrush
        mov hBrushOld, eax
        invoke GetPixel, hDC_vert, 1, 1
        invoke ExtFloodFill, hDC_vert, 1, 1, eax, FLOODFILLSURFACE
        invoke SelectObject, hDC_vert, hBrushOld
        invoke DeleteObject, hBrush
        mov rct.left, 0
        mov rct.right, 6
        mov rct.top, 0
        mov rct.bottom, 140
        invoke CreateSolidBrush, 00C0C0C0h ; darker grey
        mov hBrush, eax
        invoke SelectObject, hDC_vert, hBrush
        mov hBrushOld, eax
        invoke FillRect, hDC_vert, addr rct, hBrush
        invoke SelectObject, hDC_vert, hBrushOld
        invoke DeleteObject, hBrush
        mov rct.left, 6
        mov rct.right, 12
        mov rct.top, 0
        mov rct.bottom, 140
        invoke CreateSolidBrush, 00808080h ; lighter greay
        mov hBrush, eax
        invoke SelectObject, hDC_vert, hBrush
        mov hBrushOld, eax
        invoke FillRect, hDC_vert, addr rct, hBrush
        invoke SelectObject, hDC_vert, hBrushOld
        invoke DeleteObject, hBrush
        invoke ReleaseDC, hWin, hDC
        ret
    vert endp

    horz proc hWin:dword, bclr:dword
    local hDC:dword, hBack, rct:RECT, hBrush:dword, hBrushOld:dword
        invoke GetDC, hWin  ; get main window client area DC
        mov hDC, eax
        invoke CreateCompatibleDC, hDC
        mov hDC_horz, eax
        invoke CreateCompatibleBitmap, hDC, 140, 12
        mov hBmp_horz, eax
        invoke SelectObject, hDC_horz, hBmp_horz
        mov hBmpOld_horz, eax
        invoke CreateSolidBrush, bclr
        mov hBrush, eax
        invoke SelectObject, hDC_horz, hBrush
        mov hBrushOld, eax
        invoke GetPixel, hDC_horz, 1, 1
        invoke ExtFloodFill, hDC_horz, 1, 1, eax, FLOODFILLSURFACE
        invoke SelectObject, hDC_horz, hBrushOld
        invoke DeleteObject, hBrush
        mov rct.left, 0
        mov rct.right, 140
        mov rct.top, 0
        mov rct.bottom, 6
        invoke CreateSolidBrush, 00C0C0C0h
        mov hBrush, eax
        invoke SelectObject, hDC_horz, hBrush
        mov hBrushOld, eax
        invoke FillRect, hDC_horz, addr rct, hBrush
        invoke SelectObject, hDC_horz, hBrushOld
        invoke DeleteObject, hBrush
        mov rct.left, 0
        mov rct.right, 140
        mov rct.top, 6
        mov rct.bottom, 12
        invoke CreateSolidBrush, 00808080h
        mov hBrush, eax
        invoke SelectObject, hDC_horz, hBrush
        mov hBrushOld, eax
        invoke FillRect, hDC_horz, addr rct, hBrush
        invoke SelectObject, hDC_horz, hBrushOld
        invoke DeleteObject, hBrush
        invoke ReleaseDC, hWin, hDC
        ret
    horz endp

    isec proc hWin:dword, bclr:dword
    local hDC:dword, hPen:dword, hPenOld:dword, hBrush:dword, hBrushOld:dword
        invoke GetDC, hWin  ; get main window client area DC
        mov hDC, eax
        invoke CreateCompatibleDC, hDC
        mov hDC_isec, eax
        invoke CreateCompatibleBitmap, hDC, 12, 12
        mov hBmp_isec, eax
        invoke SelectObject, hDC_isec, hBmp_isec
        mov hBmpOld_isec, eax
        invoke CreateSolidBrush, bclr
        mov hBrush, eax
        invoke SelectObject, hDC_isec, hBrush
        mov hBrushOld, eax
        invoke GetPixel, hDC_isec, 1, 1
        invoke ExtFloodFill, hDC_isec, 1, 1, eax, FLOODFILLSURFACE
        invoke SelectObject, hDC_isec, hBrushOld
        invoke DeleteObject, hBrush
        invoke CreatePen, 0, 1, 00808080h
        mov hPen, eax
        invoke SelectObject, hDC_isec, hPen
        mov hPenOld, eax
        invoke CreateSolidBrush, 00808080h
        mov hBrush, eax
        invoke SelectObject, hDC_isec, hBrush
        mov hBrushOld, eax
        invoke MoveToEx, hDC_isec, 0,  11, 0
        invoke LineTo,   hDC_isec, 11, 11
        invoke LineTo,   hDC_isec, 11, 0
        invoke LineTo,   hDC_isec, 0, 0
        invoke LineTo,   hDC_isec, 0, 6
        invoke FloodFill, hDC_isec, 5, 5, 00808080h
        invoke SelectObject, hDC_isec, hBrushOld
        invoke DeleteObject, hBrush
        invoke SelectObject, hDC_isec, hPenOld
        invoke DeleteObject, hPen
        invoke CreatePen, 0, 1, 00C0C0C0h
        mov hPen, eax
        invoke SelectObject, hDC_isec, hPen
        mov hPenOld, eax
        invoke CreateSolidBrush, 00C0C0C0h
        mov hBrush, eax
        invoke SelectObject, hDC_isec, hBrush
        mov hBrushOld, eax
        invoke MoveToEx, hDC_isec, 5, 0, 0
        invoke LineTo,   hDC_isec, 5, 11
        invoke MoveToEx, hDC_isec, 0, 5, 0
        invoke LineTo,   hDC_isec, 11, 5
        invoke LineTo,   hDC_isec, 11, 0
        invoke LineTo,   hDC_isec, 0, 11
        invoke LineTo,   hDC_isec, 5, 11
        invoke LineTo,   hDC_isec, 5, 0
        invoke LineTo,   hDC_isec, 0, 0
        invoke LineTo,   hDC_isec, 0, 5
        invoke MoveToEx, hDC_isec, 0, 0, 0
        invoke LineTo,   hDC_isec, 11, 11
        invoke FloodFill, hDC_isec, 1, 4, 00C0C0C0h
        invoke FloodFill, hDC_isec, 4, 1, 00C0C0C0h
        invoke FloodFill, hDC_isec, 3, 9, 00C0C0C0h
        invoke FloodFill, hDC_isec, 9, 3, 00C0C0C0h
        invoke SelectObject, hDC_isec, hBrushOld
        invoke DeleteObject, hBrush
        invoke SelectObject, hDC_isec, hPenOld
        invoke DeleteObject, hPen
        invoke ReleaseDC, hWin, hDC
        ret
    isec endp

    DrawO proc hWin:dword, bclr:dword
    local hDC:dword, hPen:dword, hBrush:dword, hBrushOld:dword, hPenOld:dword
        invoke GetDC, hWin  ; get main window client area DC
        mov hDC, eax
        invoke CreateCompatibleDC, hDC
        mov hDC_O, eax
        invoke CreateCompatibleBitmap, hDC, 140, 140
        mov hBmp_O, eax
        invoke SelectObject, hDC_O, hBmp_O
        mov hBmpOld_O, eax
        invoke CreateSolidBrush, bclr
        mov hBrush, eax
        invoke SelectObject, hDC_O, hBrush
        mov hBrushOld, eax
        invoke GetPixel, hDC_O, 1, 1
        invoke ExtFloodFill, hDC_O, 1, 1, eax, FLOODFILLSURFACE
        invoke SelectObject, hDC_O, hBrushOld
        invoke DeleteObject, hBrush
        invoke CreatePen, PS_SOLID, 21, blue
        mov hPen, eax
        invoke SelectObject, hDC_O, hPen
        invoke Ellipse, hDC_O, 20, 20, 118, 115
        invoke SelectObject, hDC_O, hPenOld
        invoke DeleteObject, hPen
        invoke CreateSolidBrush, bclr
        mov hBrush, eax
        invoke SelectObject, hDC_O, hBrush
        invoke GetPixel, hDC_O, 70, 70
        invoke ExtFloodFill, hDC_O, 70, 70, eax, FLOODFILLSURFACE
        invoke CreateSolidBrush, bclr
        mov hBrush, eax
        invoke SelectObject, hDC_O, hBrushOld
        invoke DeleteObject, hBrush
        invoke ReleaseDC, hWin, hDC
        ret
    DrawO endp

    DrawX proc hWin:dword, bclr
    local hDC:dword, hPen:dword, hPenOld:dword, hBrush:dword, hBrushOld:dword
    local rct:RECT
        invoke GetDC, hWin  ; get main window client area DC
        mov hDC, eax
        invoke CreateCompatibleDC, hDC
        mov hDC_X, eax
        invoke CreateCompatibleBitmap, hDC, 140, 140
        mov hBmp_X, eax
        invoke SelectObject, hDC_X, hBmp_X
        mov hBmpOld_X, eax
        invoke CreateSolidBrush, bclr
        mov hBrush, eax
        invoke SelectObject, hDC_X, hBrush
        mov hBrushOld, eax
        invoke GetPixel, hDC_X, 1, 1
        invoke ExtFloodFill, hDC_X, 1, 1, eax, FLOODFILLSURFACE
        invoke SelectObject, hDC_X, hBrushOld
        invoke DeleteObject, hBrush
        invoke CreatePen, 0, 1, red
        mov hPen, eax
        invoke SelectObject, hDC_X, hPen
        mov hPenOld, eax
        invoke MoveToEx, hDC_X, 28, 14, 0
        invoke LineTo,   hDC_X, 29, 14
        invoke LineTo,   hDC_X, 69, 54
        invoke LineTo,   hDC_X, 70, 54
        invoke LineTo,   hDC_X, 110, 14
        invoke LineTo,   hDC_X, 111, 14
        invoke LineTo,   hDC_X, 125, 28
        invoke LineTo,   hDC_X, 125, 29
        invoke LineTo,   hDC_X, 85, 69
        invoke LineTo,   hDC_X, 85, 70
        invoke LineTo,   hDC_X, 125, 110
        invoke LineTo,   hDC_X, 125, 111
        invoke LineTo,   hDC_X, 111, 125
        invoke LineTo,   hDC_X, 110, 125
        invoke LineTo,   hDC_X, 70, 85
        invoke LineTo,   hDC_X, 69, 85
        invoke LineTo,   hDC_X, 29, 125
        invoke LineTo,   hDC_X, 28, 125
        invoke LineTo,   hDC_X, 14, 111
        invoke LineTo,   hDC_X, 14, 110
        invoke LineTo,   hDC_X, 54, 70
        invoke LineTo,   hDC_X, 54, 69
        invoke LineTo,   hDC_X, 14, 29
        invoke LineTo,   hDC_X, 14, 28
        invoke LineTo,   hDC_X, 28, 14
        invoke SelectObject, hDC_X, hPenOld
        invoke DeleteObject, hPen
        invoke CreateSolidBrush, red
        mov hBrush, eax
        invoke SelectObject, hDC_X, hBrush
        mov hBrushOld, eax
        invoke FloodFill, hDC_X, 70, 70, red
        invoke SelectObject, hDC_X, hBrushOld
        invoke DeleteObject, hBrush
        invoke ReleaseDC, hWin, hDC
        ret
    DrawX endp

    end start
tic-tac-toe final version is finished and is attached in post #1.  :smiley:

The rewrite went a hell of a lot better than I had anticipated.
You cannot view this attachment.


¯\_(ツ)_/¯
tictactoe_final is finished    :smiley: