flat assembler
Message board for the users of flat assembler.

Index > Windows > Simple game. Turn all tiles yellow.

Author
Thread Post new topic Reply to topic
Picnic



Joined: 05 May 2007
Posts: 1389
Location: Piraeus, Greece
Picnic 02 May 2008, 16:34
Hi guys,
Something i wrote in fasm, not much, a simple windows game.
I'm a newcomer to all this api stuff, so don't be bad on me.

The objective is to turn all tiles on the board yellow.
By clicking a tile you will reverse the state for that tile and every adjacent piece.
Click 'Scramble' to play a new random board anytime.

Code:
  
     ; by Picnic

     format PE GUI 4.0
     entry start

     include "win32ax.inc"

     COLUMNS = 6
     ROWS = 6

     TILEW = 40
     TILEH = 40
     BORDER = 4

     WHITE = 0xFFFFFF
     YELLOW = 0xFFFF
     BLUE = 0xFF0000

     SCRAMBLE = 500
     XWDTH = COLUMNS * 4

macro get x,y
{
     mov eax,y
     mov ebx,x
     imul eax,eax,XWDTH
     mov eax,dword[map+eax+ebx*4]
}

macro set x,y,value
{
     mov ebx,value
     mov eax,y
     mov ecx,x
     imul eax,eax,XWDTH
     mov dword[map+eax+ecx*4],ebx
}

macro flip x,y
{
     local .a, .b
     get x,y
     cmp eax,BLUE
     jne .b
     mov eax,YELLOW
     jmp .a
     .b:
     mov eax,BLUE
     .a:
     set x,y,eax
}


section ".data" data readable writeable

     _class TCHAR "FASMWIN32",0
     _title TCHAR "Flip Flop",0
     _error TCHAR "Startup failed.",0

     align 4
     _btnx dd BORDER
     _btny dd BORDER + (TILEH+BORDER) * ROWS
     _wndw dd 2 * BORDER + (TILEW+BORDER) * COLUMNS
     _wndh dd 50 + BORDER + (TILEH+BORDER) * ROWS
     _wndx dd ?
     _wndy dd ?
     hwnd dd ?
     map rd COLUMNS*ROWS

     align 4
     wc WNDCLASS 0,WindowProc,0,0,0,0,0,COLOR_BTNFACE+1,0,_class
     msg MSG


section ".code" code readable executable

   start:
     invoke GetModuleHandle,0
     mov dword[wc.hInstance],eax
     invoke LoadIcon,0,IDI_APPLICATION
     mov dword[wc.hIcon],eax
     invoke LoadCursor,0,IDC_ARROW
     mov dword[wc.hCursor],eax
     invoke CreateSolidBrush,WHITE
     mov dword[wc.hbrBackground],eax
     invoke RegisterClass,addr wc
     test eax,eax
     jz error

     invoke GetSystemMetrics,SM_CXSCREEN
     shr eax,1
     mov ecx,dword[_wndw]
     sar ecx,1
     sub eax,ecx
     mov dword[_wndx],eax

     invoke GetSystemMetrics,SM_CYSCREEN
     shr eax,1
     mov ecx,dword[_wndh]
     sar ecx,1
     sub eax,ecx
     mov dword[_wndy],eax

     invoke CreateWindowEx,0,addr _class,addr _title,WS_VISIBLE+WS_DLGFRAME+WS_SYSMENU,\
                dword[_wndx],dword[_wndy],dword[_wndw],dword[_wndh],0,0,dword[wc.hInstance],0
     mov dword[hwnd],eax
     test eax,eax
     jz error

  msgloop:
     invoke GetMessage,msg,0,0,0
     cmp eax,1
     jb endloop
     jne msgloop
     invoke TranslateMessage,msg
     invoke DispatchMessage,msg
     jmp msgloop
  error:
     invoke MessageBox,0,addr _error,0,MB_ICONERROR+MB_OK
  endloop:
     invoke ExitProcess,dword[msg.wParam]


proc WindowProc hwnd:dword,wmsg:dword,wparam:dword,lparam:dword

     local ps:PAINTSTRUCT

     push ebx esi edi
     cmp dword[wmsg],WM_CREATE
     je .wmcreate
     cmp dword[wmsg],WM_COMMAND
     je .wmcommand
     cmp dword[wmsg],WM_LBUTTONDOWN
     je .wmlbuttondown
     cmp dword[wmsg],WM_PAINT
     je .wmpaint
     cmp dword[wmsg],WM_CLOSE
     je .wmclose
  .defwndproc:
     invoke DefWindowProc,dword[hwnd],dword[wmsg],dword[wparam],dword[lparam]
     jmp .finish
  .wmcreate:
     stdcall CreateMap
     invoke CreateWindowEx,0,"BUTTON","Scramble",WS_CHILD or WS_VISIBLE,\
              dword[_btnx],dword[_btny],140,22,dword[hwnd],SCRAMBLE,dword[wc.hInstance],0
     jmp .finish
  .wmcommand:
     .if ( dword[wparam] = SCRAMBLE )
        stdcall CreateMap
        stdcall DrawMap
     .endif
     jmp .finish
  .wmlbuttondown:
     stdcall LButtonClick,dword[lparam],dword[lparam]
     jmp .finish
  .wmpaint:
     invoke BeginPaint,dword[hwnd],addr ps
     stdcall DrawMap
     invoke EndPaint,dword[hwnd],addr ps
     jmp .finish
  .wmclose:
     invoke PostQuitMessage,0
     xor eax,eax
  .finish:
     pop edi esi ebx

     ret
endp


; If x,y coords are valid then flip neighbour tiles, redraw map and check if user wins.
proc FlipTiles x:dword,y:dword

     pushad
     .if ( dword[x] >= 0 ) & ( dword[x] <= COLUMNS-1 ) & ( dword[y] >= 0 ) & ( dword[y] <= ROWS-1 )
        flip dword[x],dword[y]
        .if ( dword[x] > 0 )
           push dword[x]
           dec dword[x]
           flip dword[x],dword[y]
           pop dword[x]
        .endif
        .if ( dword[x] < COLUMNS-1 )
           push dword[x]
           inc dword[x]
           flip dword[x],dword[y]
           pop dword[x]
        .endif
        .if ( dword[y] > 0 )
           push dword[y]
           dec dword[y]
           flip dword[x],dword[y]
           pop dword[y]
        .endif
        .if ( dword[y] < ROWS-1 )
           inc dword[y]
           flip dword[x],dword[y]
        .endif
        stdcall DrawMap
        stdcall CheckWin
     .endif
     popad

     ret
endp


; Convert mouse coords into 2D map coords and call FlipTiles.
proc LButtonClick\
    x:dword,y:dword

     local hdc dd ?

     pushad
     invoke GetDC,dword[hwnd]
     mov dword[hdc],eax
     and dword[x],0xFFFF
     shr dword[y],16
     invoke GetPixel,dword[hdc],dword[x],dword[y]
     .if ( eax <> WHITE )
        xor edx,edx
        mov eax,dword[y]
        mov ebx,TILEH+BORDER
        div ebx
        mov dword[y],eax
        xor edx,edx
        mov eax,dword[x]
        mov ebx,TILEW+BORDER
        div ebx
        mov dword[x],eax
        stdcall FlipTiles,dword[x],dword[y]
     .endif
     invoke ReleaseDC,dword[hwnd],dword[hdc]
     popad

     ret
endp


; Fill map array with random colors values yellow or blue.
proc CreateMap

     pushad
     xor ecx,ecx
     .while ( ecx < COLUMNS*ROWS )
        mov dword[map+ecx*4],BLUE
        rdtsc
        and eax,eax
        .if ( PARITY? )
           mov dword[map+ecx*4],YELLOW
        .endif
        inc ecx
     .endw
     popad

     ret
endp


; Count yellow color values in map array.
proc CheckWin

     pushad
     xor ecx,ecx
     xor eax,eax
     .while ( ecx < COLUMNS*ROWS )
        cmp dword[map+ecx*4],YELLOW
        jne @f
        inc eax
       @@:
        inc ecx
     .endw
     .if ( eax = COLUMNS*ROWS )
        invoke MessageBox,dword[hwnd],<"Puzzle Completed.">,addr _title,MB_OK or MB_ICONINFORMATION
     .endif
     popad

     ret
endp


; Draw a 2D grid of tiles.
proc DrawMap

     local x dd ?
     local y dd ?

     pushad
     mov dword[y],0
     .while ( dword[y] < ROWS )
         mov dword[x],0
        .while ( dword[x] < COLUMNS )
           imul esi,dword[x],TILEW+BORDER
           add esi,BORDER
           imul edi,dword[y],TILEH+BORDER
           add edi,BORDER
           get dword[x],dword[y]
           stdcall DrawTile,esi,edi,eax
           inc dword[x]
        .endw
        inc dword[y]
     .endw
     popad

     ret
endp


; Draw a tile at x,y with black pen and b brush.
proc DrawTile\
    x:dword, y:dword, b:dword

     local hdc dd ?
     local brush dd ?

     pushad
     invoke GetDC,dword[hwnd]
     mov dword[hdc],eax
     invoke GetStockObject,BLACK_PEN
     invoke SelectObject,dword[hdc],eax
     invoke CreateSolidBrush,dword[b]
     mov dword[brush],eax
     invoke SelectObject,dword[hdc],dword[brush]
     mov eax,dword[x]
     add eax,TILEW
     mov ecx,dword[y]
     add ecx,TILEH
     invoke RoundRect,dword[hdc],dword[x],dword[y],eax,ecx,8,8
     invoke DeleteObject,dword[brush]
     invoke ReleaseDC,dword[hwnd],dword[hdc]
     popad

     ret
endp


section ".idata" import data readable writeable

     library\
     kernel32,"KERNEL32.DLL",\
     user32,"USER32.DLL",\
     gdi32,"GDI32.DLL"

     include "\api\kernel32.inc"
     include "\api\user32.inc"
     include "\api\gdi32.inc"
    


Image


Last edited by Picnic on 21 Mar 2020, 10:01; edited 2 times in total
Post 02 May 2008, 16:34
View user's profile Send private message Visit poster's website Reply with quote
asmhack



Joined: 01 Feb 2008
Posts: 431
asmhack 02 May 2008, 17:46
gj thimis Wink
bravo Razz
Post 02 May 2008, 17:46
View user's profile Send private message Reply with quote
Yardman



Joined: 12 Apr 2005
Posts: 244
Location: US
Yardman 02 May 2008, 21:13
[ Post removed by author. ]


Last edited by Yardman on 04 Apr 2012, 03:18; edited 1 time in total
Post 02 May 2008, 21:13
View user's profile Send private message Reply with quote
Goplat



Joined: 15 Sep 2006
Posts: 181
Goplat 03 May 2008, 02:20
Only 1 out of every 16 games are actually winnable. The buttons are not "independent" - try pushing any of these combinations:
Code:
. X X X | X X . X | X . X X | X X X .
X . X . | . . . X | X . . . | . X . X
X X . . | X X X . | . X X X | . . X X
X . . . | . X . . | . . X . | . . . X    
And you end up back where you started. This shows that you could do without, for example, all the bottom buttons, by pushing instead all the other buttons in the combination containing it; thus you have only 12 bits of influence (4096 accessible states) rather than the 16 bits one might expect (all 65536 states accessible). And if you are not lucky enough to start in one of the 4096 states that are accessible from the all-tiles-yellow state, then nothing you do can win that game.
Post 03 May 2008, 02:20
View user's profile Send private message Reply with quote
AlexP



Joined: 14 Nov 2007
Posts: 561
Location: Out the window. Yes, that one.
AlexP 03 May 2008, 03:58
darn, I could get all but one to go yellow Smile.
Post 03 May 2008, 03:58
View user's profile Send private message Visit poster's website Reply with quote
rugxulo



Joined: 09 Aug 2005
Posts: 2341
Location: Usono (aka, USA)
rugxulo 03 May 2008, 07:00
Goplat wrote:
Only 1 out of every 16 games are actually winnable. The buttons are not "independent" - try pushing any of these combinations: ... And you end up back where you started. This shows that you could do without, for example, all the bottom buttons, by pushing instead all the other buttons in the combination containing it; thus you have only 12 bits of influence (4096 accessible states) rather than the 16 bits one might expect (all 65536 states accessible). And if you are not lucky enough to start in one of the 4096 states that are accessible from the all-tiles-yellow state, then nothing you do can win that game.


Could I borrow your brain for a bit? Wink
Post 03 May 2008, 07:00
View user's profile Send private message Visit poster's website Reply with quote
Picnic



Joined: 05 May 2007
Posts: 1389
Location: Piraeus, Greece
Picnic 03 May 2008, 11:18
Thanks for the nice comments guys.
It needs a bit of luck Yardman, to get a winnable board.
Like Goplat says, on a 4x4 board (and also on a 5x5), not all boards are solvable.
Post 03 May 2008, 11:18
View user's profile Send private message Visit poster's website Reply with quote
edfed



Joined: 20 Feb 2006
Posts: 4335
Location: Now
edfed 03 May 2008, 12:18
AAAAAAAAAAAAAAARRRRRRRggggghhhhhhhhhhhhhhh Crying or Very sad

this game drives me crazy !!!!!!!!!!
Post 03 May 2008, 12:18
View user's profile Send private message Visit poster's website Reply with quote
bitRAKE



Joined: 21 Jul 2003
Posts: 4043
Location: vpcmpistri
bitRAKE 03 May 2008, 15:14
The code is almost flexible enough to change the board size.
Code:
     _wndw dd 10 + BORDER + (TILEW+BORDER) * COLUMNS
     _wndh dd 56 + BORDER + (TILEH+BORDER) * ROWS    
Look at AdjustWindowRect to determine the size needed for a given client area instead of using the constants.

Edit: GetMessage can return -1, and the branch JB (same as JC) is unsigned - the branch will not be taken in cases of error. Using a signed jump JL would work.

_________________
¯\(°_o)/¯ “languages are not safe - uses can be” Bjarne Stroustrup
Post 03 May 2008, 15:14
View user's profile Send private message Visit poster's website Reply with quote
Picnic



Joined: 05 May 2007
Posts: 1389
Location: Piraeus, Greece
Picnic 04 May 2008, 10:30
Nice tips bitRAKE, i'm doing some tests now of AdjustWindowRect Smile

_________________
Hobby BASIC Interpreter
Post 04 May 2008, 10:30
View user's profile Send private message Visit poster's website Reply with quote
MHajduk



Joined: 30 Mar 2006
Posts: 6115
Location: Poland
MHajduk 04 May 2008, 13:39
What about adding possibility of saving/loading actual state of the game to/from simple TXT file? In this case we would be able to start not from randomly generated board but from the saved one. Smile
Post 04 May 2008, 13:39
View user's profile Send private message Visit poster's website Reply with quote
Picnic



Joined: 05 May 2007
Posts: 1389
Location: Piraeus, Greece
Picnic 08 May 2008, 17:12
Hi MHajduk,
I like such features and i surely implement them on future projects Smile
Post 08 May 2008, 17:12
View user's profile Send private message Visit poster's website Reply with quote
Display posts from previous:
Post new topic Reply to topic

Jump to:  


< Last Thread | Next Thread >
Forum Rules:
You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot vote in polls in this forum
You cannot attach files in this forum
You can download files in this forum


Copyright © 1999-2024, Tomasz Grysztar. Also on GitHub, YouTube.

Website powered by rwasa.