From: Spam Killer on
Hi!

I learned a lot about the Windows API while writing this, so I thought
I'd share it with you guys. No solver, 'cause you should use your
brains to solve 'em, not your CPU. It is just meant to do it on the
screen, instead of the paper.

Enjoy! Or if you don't, you don't have to tell me, there is enough
bitching going on around here!

In the Menu Editor:

&File
[TAB]&Open
[TAB]&Save
[Empty Line]
[TAB]E&xit
&Edit
[TAB]&Check
[TAB]C&lear

[WINDOW_WIDTH 225 WINDOW_HEIGHT 225]
[M00_Menu 1000 M00_Open 1001 M00_Save 1002
M00_Exit 1003 M00_Check 1004 M00_Clear 1005]

[AppName: b$ "Sudoku.", 0]
[ClassName: b$ "SKELETON", 0]
[StrFilter: b$ 'All files', 0, '*.*', 0, 0]
[<32 LoadName: b$ "csod00.txt" b$ 0 #&MAXPATH - 6]
[<32 SaveName: b$ "csol00.txt" b$ 0 #&MAXPATH - 12]
[Correct: b$ "Correct!", 0 Incorrect: b$ "Incorrect!", 0]
[<32 Multiple_of_3: d$ 0010010000]
[hOutFile: d$ ? hInFile: d$ ? read: d$ ?]
[hWnd: d$ ? hMenu: d$ ?
hBlackPen: d$ ? hFont: d$ ?]
[<32 chartab: b$ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 1 1 1 1 1 1 1 1 1 0 0 0 0 0 0 b$ 0 #192]
[<32 colors: d$ 04080ff 0ffff00 0ff00 0808080
0ff0080 0ff 0ff00ff 0c0c0c0 0ffff]
[rows: d$ 9 columns: d$ 9]
[current_row: d$ 0 current_column: d$ 0]
[<32 column_buffer: b$ ' ' #(9*9)]
[<32 row_buffer: b$ 0 #(9*9)]
[<32 color_buffer: d$ 0 #(9*9)]
[<32 rcZells: d$ 0 0 0 0 #256]

[<32 wcx: ; WNDCLASSEX
@cbSize: d$ len
@style: d$ &CS_HREDRAW+&CS_VREDRAW
@lpfnWndProc: d$ MainWindowProc @cbClsExtra: d$ 0
@cbWndExtra: d$ 0 @hInstance: d$ 0
@hIcon: d$ 0 @hCursor: d$ 0
@hbrBackground: d$ &COLOR_WINDOW+1 @lpszMenuName: d$ 0
@lpszClassName: d$ ClassName @hIconSm: d$ 0]

[psx: ; PAINTSTRUCT
@hdc: D$ 0 @fErase: D$ 0
@rcPaint.left: D$ 0 @rcPaint.top: D$ 0
@rcPaint.right: D$ 0 @rcPaint.bottom: D$ 0
@fRestore: D$ 0 @fIncUpdate: D$ 0
@rgbReserved: B$ 0 #32]

[rect: ; RECT
@left: d$ 0 @top: d$ 0
@right: d$ WINDOW_WIDTH @bottom: d$ WINDOW_HEIGHT]

[pnt: ; POINT
@x: D$ ? @y: D$ ?]

[msg: ; MSG
@hwnd: D$ 0 @message: D$ 0 @wParam: D$ 0 @lParam: D$ 0
@time: D$ 0 @pt.x: D$ 0 @pt.y: D$ 0]

[<16 clf: ; LOGFONT
@lfHeight: D$ 8
@lfWidth: D$ 8
@lfEscapement: D$ 0
@lfOrientation: D$ 0
@lfWeight: D$ &FW_NORMAL
@lfItalic: B$ 0
@lfUnderline: B$ 0
@lfStrikeOut: B$ 0
@lfCharSet: B$ &ANSI_CHARSET
@lfOutPrecision: B$ &OUT_DEFAULT_PRECIS
@lfClipPrecision: B$ &CLIP_DEFAULT_PRECIS
@lfQuality: B$ &DEFAULT_QUALITY
@lfPitchAndFamily: B$ &DEFAULT_PITCH
@lfFaceName: B$ "Fixedsys", 0]

[<32 ofn: ; OPENFILENAME
@lStructSize: d$ len @hwndOwner: d$ &NULL
@hInstance: d$ &NULL @lpstrFilter: d$ StrFilter
@lpstrCustomFilter:d$ 0 @nMaxCustFilter: d$ 0
@nFilterIndex: d$ 0 @lpstrFile: d$ 0
@nMaxFile: d$ &MAX_PATH @lpstrFileTitle: d$ 0
@nMaxFileTitle: d$ 0 @lpstrInitialDir: d$ 0
@lpstrTitle: d$ 0 @Flags: d$ &OFN_FILEMUSTEXIST
@nFileOffset: W$ 0 @nFileExtension: W$ 0
@lpstrDefExt: d$ 0 @lCustData: d$ 0
@lpfnHook: d$ 0 @lpTemplateName: d$ 0]

[hAccel: d$ ?]
[accelerators: ; ACCELERATORS
@key1: u$ &FVIRTKEY+080 &VK_ESCAPE M00_Exit]
[ACCELS 1]

Main: fninit
call 'comctl32.InitCommonControls'
call 'user32.CreateAcceleratorTableA' accelerators,
ACCELS
mov d$hAccel eax

call 'kernel32.GetModuleHandleA' &NULL
cmp eax 1 | jc ExitProg | mov d$wcx(a)hInstance eax

call 'user32.LoadIconA' &NULL &IDI_APPLICATION
cmp eax 1 | jc ExitProg | mov d$wcx(a)hIcon eax

call 'user32.LoadCursorA' &NULL &IDC_ARROW
cmp eax 1 | jc ExitProg | mov d$wcx(a)hCursor eax

call 'user32.LoadMenuA', d$wcx(a)hInstance, M00_Menu
mov d$hMenu,eax

; Register the window class for the main window.
call 'user32.RegisterClassExA' wcx
cmp eax 1 | jc ExitProg

call 'user32.AdjustWindowRectEx' rect,
&WS_OVERLAPPED+&WS_CAPTION+&WS_SYSMENU+&WS_MINIMIZEBOX,
&TRUE &NULL
cmp eax 1 | jc ExitProg

mov esi d$rect(a)right | sub esi d$rect(a)left
mov edi d$rect(a)bottom | sub edi d$rect(a)top
call 'user32.GetSystemMetrics' &SM_CXSCREEN
sub eax esi | shr eax 1 | mov ebx eax
call 'user32.GetSystemMetrics' &SM_CYSCREEN
sub eax edi | shr eax 1

; Create the main window.
call 'user32.CreateWindowExA' &NULL ClassName AppName,
&WS_OVERLAPPED+&WS_CAPTION+&WS_SYSMENU+&WS_MINIMIZEBOX,
ebx eax esi edi,
&NULL d$hMenu,
d$wcx(a)hInstance &NULL
cmp eax 1 | jc ExitProg | mov d$hWnd,eax

; Show the window and paint its contents.
call 'user32.ShowWindow' eax &SW_SHOWDEFAULT
call 'user32.UpdateWindow' d$hWnd
jmp F1>

; Start the message loop.
B1: call 'user32.TranslateAcceleratorA' d$hWnd d$hAccel,
msg
call 'user32.TranslateMessage' msg
call 'user32.DispatchMessageA' msg
F1: call 'user32.GetMessageA' msg &NULL 0 0
test eax eax | jnz B1
; Return the exit code to Windows.
call 'kernel32.ExitProcess' d$msg(a)wParam

ExitProg: call 'user32.DestroyAcceleratorTable' d$hAccel
call 'kernel32.GetLastError'
call 'kernel32.ExitProcess' eax

align 16
proc MainWindowProc:
arguments @hWnd @uMsg @wParam @lParam
uses ebx esi edi

mov eax d(a)uMsg
P1: cmp eax &WM_COMMAND | jne P1>>

mov eax d(a)wParam
P2: cmp ax M00_Exit | je E9>>

P2: cmp ax M00_Open | jne P2>>
mov d$ofn(a)lpstrfile LoadName
call 'comdlg32.GetOpenFileNameA', ofn
cmp eax &TRUE | jc P9>>

call 'kernel32.CreateFileA', LoadName &GENERIC_READ,
&NULL &NULL &OPEN_EXISTING,
&FILE_ATTRIBUTE_NORMAL 0
cmp eax &INVALID_HANDLE_VALUE | je E0>>
mov d$hInFile eax

mov eax d$rows | imul eax d$columns
call 'kernel32.ReadFile' d$hInFile column_buffer eax,
read 0
cmp eax &TRUE | jne E0>>

call 'kernel32.CloseHandle' d$hInFile
cmp eax &TRUE | jc P9>>

call 'user32.SetCaretPos' 0 0
mov d$current_column 0, d$current_row 0
call 'user32.InvalidateRect' d(a)hWnd rect &TRUE
jmp E0>>

P2: cmp ax M00_Save | jne P2>>
mov d$ofn(a)lpstrfile SaveName
call 'comdlg32.GetSaveFileNameA' ofn
cmp eax &TRUE | jc P9>>

call 'kernel32.CreateFileA', SaveName &GENERIC_WRITE,
&NULL &NULL &CREATE_NEW,
&FILE_ATTRIBUTE_NORMAL 0
cmp eax &INVALID_HANDLE_VALUE | je E0>>
mov d$hOutFile eax

mov eax d$rows | imul eax d$columns
call 'kernel32.WriteFile' d$hOutFile column_buffer,
eax read 0
cmp eax &TRUE | jne E0>>

call 'kernel32.CloseHandle' d$hOutFile
cmp eax &TRUE | jc P9>>
jmp E0>>

P2: cmp ax M00_Clear | jne P2>
mov ecx d$rows | imul ecx d$columns
mov al ' ', edi column_buffer | rep stosb
call 'user32.InvalidateRect' d(a)hWnd rect &TRUE
jmp E0>>

P2: cmp ax M00_Check | jne E1>>
L1: call check
mov eax Correct | cmovne eax d${d$ Incorrect}
call 'user32.MessageBoxA' d(a)hWnd eax {"Error", 0},
&MB_OK
jmp E0>>

P1: cmp eax &WM_SETFOCUS | jne P1>
; Create a solid black caret.
call 'user32.CreateCaret' d(a)hWnd &NULL 25 25
; Adjust the caret position, in client coordinates.
imul esi d$current_column 25 | imul edi d$current_row
25
call 'user32.SetCaretPos' esi edi
; Display the caret.
call 'user32.ShowCaret' d(a)hWnd
jmp E1>>

P1: cmp eax &WM_CREATE | jne P1>>
push ebp
mov ebp rcZells
xor eax eax | xor ebx ebx ; left, top
mov ecx 25, edx 25 ; right, bottom
mov edi d$rows
B1: mov esi d$columns
B2: mov d$ebp eax, d$ebp+4 ebx, d$ebp+8 ecx, d$ebp+12 edx
add ebp 16 | add eax 25 | add ecx 25
dec esi | jnz B2
xor eax eax | mov ecx 25
add ebx 25 | add edx 25
dec edi | jnz B1
pop ebp

call 'gdi32.CreateFontIndirectA' clf
mov d$hFont eax

call 'gdi32.GetStockObject' &BLACK_PEN
mov d$hBlackPen eax

mov esi colors, edi color_buffer
B0: mov ebx 9
B1: call 'gdi32.CreateSolidBrush' d$esi | add esi 4
mov d$edi eax, d$edi+(3*4) eax, d$edi+(6*4) eax
mov d$edi+(27*4) eax, d$edi+(30*4) eax
mov d$edi+(33*4) eax, d$edi+(54*4) eax
mov d$edi+(57*4) eax, d$edi+(60*4) eax
mov ecx 4
bt d$multipleof3 ebx | cmovc ecx d${d$ (6*4)+4}
add edi ecx | sub ebx 1 | jnz B1
jmp E0>>

P1: cmp eax &WM_KEYDOWN | jne P1>>
mov eax d(a)wParam

P2: cmp eax &VK_UP | jne P2>
mov eax d$current_row | sub eax 1 | js E0>>
mov d$current_row eax | jmp F1>

P2: cmp eax &VK_DOWN | jne P2>
mov eax d$current_row | add eax 1
cmp eax d$rows | jae E0>>
mov d$current_row eax | jmp F1>

P2: cmp eax &VK_LEFT | jne P2>
mov eax d$current_column | sub eax 1 | js E0>>
mov d$current_column eax | jmp F1>

P2: cmp eax &VK_RIGHT | jne E0>>
mov eax d$current_column | add eax 1
cmp eax d$columns | jae E0>>
mov d$current_column eax

F1: imul esi d$current_column 25
imul edi d$current_row 25
call 'user32.SetCaretPos' esi edi
jmp E0>>

P1: cmp eax &WM_CHAR | jne P1>>
mov eax d(a)wParam, esi d$columns, edi d$rows
mov ecx d$current_column, edx d$current_row
cmp eax 8 | je F1>>
test b$chartab+eax 1 | jz E0>>
; Write the character to the buffer.
mov ebx edx | imul ebx esi | add ebx ecx
mov b$column_buffer+ebx al
; Increment cursor position.
add ecx 1 | cmp ecx esi | jb F3>> | xor ecx ecx
add edx 1 | cmp edx edi | jb F3>> | xor edx edx
jmp F3>>

; Decrement cursor position.
F1: sub ecx 1 | jns F2> | lea ecx d$esi-1
sub edx 1 | jns F2> | lea edx d$edi-1
; Write a space character to the buffer.
F2: mov ebx edx | imul ebx esi | add ebx ecx
mov b$column_buffer+ebx ' '
; Set new row and column and initiate redraw.
F3: mov d$current_column ecx, d$current_row edx
shl ebx 4 | add ebx rcZells
call 'user32.InvalidateRect' d(a)hWnd ebx &TRUE
jmp E0>>

P1: cmp eax &WM_PAINT | jne P7>>
call 'user32.BeginPaint' d(a)hWnd psx
call 'user32.HideCaret' d(a)hWnd
call 'gdi32.SelectObject' d$psx(a)hdc d$hFont

; Draw the grid.
xor ebx ebx
mov edi d$rows
B1: mov esi d$columns
B2: call 'gdi32.SelectObject' d$psx(a)hdc,
d$color_buffer+ebx*4
lea eax d$rcZells+ebx*8 | lea eax d$eax+ebx*8
call 'gdi32.Rectangle' d$psx(a)hdc d$eax d$eax+4,
d$eax+8 d$eax+12
inc ebx | dec esi | jnz B2
dec edi | jnz B1<<
call 'gdi32.CreatePen' &PS_SOLID 4 0 | push eax
call 'gdi32.SelectObject' d$psx(a)hdc eax
call 'gdi32.MoveToEx' d$psx(a)hdc 74 0 pnt
call 'gdi32.LineTo' d$psx(a)hdc 74 225
call 'gdi32.MoveToEx' d$psx(a)hdc 149 0 pnt
call 'gdi32.LineTo' d$psx(a)hdc 149 225
call 'gdi32.MoveToEx' d$psx(a)hdc 0 74 pnt
call 'gdi32.LineTo' d$psx(a)hdc 225 74
call 'gdi32.MoveToEx' d$psx(a)hdc 0 149 pnt
call 'gdi32.LineTo' d$psx(a)hdc 225 149
pop eax | call 'gdi32.DeleteObject' eax

; Fill in the characters.
call 'gdi32.SetTextColor' d$psx(a)hdc 0
xor ebx ebx, esi esi, edi edi
B1: xor esi esi
B2: imul edx edi 25 | add edx 6
imul ecx esi 25 | add ecx 6
lea eax d$ColumnBuffer+ebx
call 'gdi32.TextOutA' d$psx(a)hdc ecx edx eax 1
add ebx 1
add esi 1 | cmp esi d$columns | jb B2 | xor esi esi
add edi 1 | cmp edi d$rows | jb B1

imul edi d$current_column 25
imul esi d$current_row 25
call 'user32.SetCaretPos' edi esi
call 'user32.ShowCaret' d(a)hWnd
call 'user32.EndPaint' d(a)hWnd psx
jmp E0>

P7: cmp eax &WM_DESTROY | jne P8>
E9: call 'gdi32.DeleteObject' d$hFont
call 'user32.PostQuitMessage' &NULL

P8: call 'user32.DefWindowProcA' d(a)hWnd d(a)uMsg,
d(a)wParam d(a)lParam
jmp P9>

E1: mov eax &TRUE | jmp P9>
E0: xor eax eax
endp

align 16
subrt check:
mov ecx 9, esi column_buffer
S4: mov eax d$esi, ebx d$esi+9, edx d$esi+18
lea eax d$eax+(-6316128)+ebx
lea eax d$eax+(-3158064)+edx
add ah al | shr eax 8 | add al ah
cmp al 45 | jne S2>> ; | add esi 3
mov edi 3 | bt d$Multiple_of_3 ecx | cmovc edi d${d$
21}
add esi edi | dec ecx | jnz S4<

mov ecx 9, esi column_buffer
S4: mov eax d$esi, ebx d$esi+3, edx d$esi+6
lea eax d$eax+(-6316128)+ebx
lea eax d$eax+(-3158064)+edx
add ah al | shr eax 8 | add al ah
cmp al 45 | jne S2>> | add esi 9
dec ecx | jnz S4<<

pxor mm0 mm0 | xor eax eax
movq mm1 q${q$ 03030303030303030}
mov ecx 9, esi column_buffer
S1: paddb mm0 q$esi | add al b$esi+8 | add esi 9
psubb mm0 mm1 | sub al 030
dec ecx | jnz S1
cmp al 02d | jne S2>
pcmpeqb mm0 q${q$ 02d2d2d2d2d2d2d2d} | pmovmskb eax mm0
cmp al 0ff
S2: ret
ends check

;------------------------
; General purpose macros:
;------------------------
[push | push #1 | #+1] [pop | pop #1 | #+1] [mov | mov #1 #2 | #+2]
[inc | inc #1 | #+1] [dec | dec #1 | #+1] [xor | xor #1 #2 | #+2]
[movq | movq #1 #2 | #+2]
[call | push #L>2 | call #1] [subrt | #1] [ends | nope]
[Proc | &1=0 | &2=0 | &3= | #1 | push ebp | mov ebp esp]
[Arguments | {#1 Arg#x} | #+1 | &1=SizeOf#x]
[Argument | {#1 Arg#x} | #+1 | &1=SizeOf#x]
[Local | {#1 Local#x} | #+1 | sub esp SizeOf#x | &2=SizeOf#x]
[StrucPtrs | {#3 ebp+#2+#F} | #+2]
[Structure | {#1 ebp-&2-4} | sub esp #2+4
| mov D$#1 esp | StrucPtrs 0-&2-#2-4 #L>3]
[Uses | push #1>L | &3=pop #L>1]
[EndP | P9: | &3 | mov esp ebp | pop ebp | ret &1]
[Arg1 ebp+8 Arg2 ebp+12 Arg3 ebp+16 Arg4 ebp+20 Arg5 ebp+24
Arg6 ebp+28 Arg7 ebp+32 Arg8 ebp+36 Arg9 ebp+40 Arg10 ebp+44]
[Local1 ebp-4 Local2 ebp-8 Local3 ebp-12 Local4 ebp-16
Local5 ebp-20 Local6 ebp-24 Local7 ebp-28 Local8 ebp-32
Local9 ebp-36 Local10 ebp-40]
[SizeOf1 4 SizeOf2 8 SizeOf3 12 SizeOf4 16 SizeOf5 20
SizeOf6 24 SizeOf7 28 SizeOf8 32 SizeOf9 36 SizeOf10 40]
--
wfz
From: Frank Kotler on
Spam Killer wrote:
> Hi!
>
> I learned a lot about the Windows API while writing this, so I thought
> I'd share it with you guys. No solver, 'cause you should use your
> brains to solve 'em, not your CPU. It is just meant to do it on the
> screen, instead of the paper.

Herbert already posted a "solver", IIRC. :)

> Enjoy! Or if you don't, you don't have to tell me, there is enough
> bitching going on around here!

Well... I can't test it, but it *looks* like it'd be cool!

Hey, "Spam Killer"... do you recall sending me the examples from
Jonathan Bartlett's "PGU" book, translated to Nasm? That's something I
lost in "the partition mishap" that I haven't recovered. If you've still
got that around, could you resend? ( fbkotler(a)verizon.net) If you can't
lay your hands on it, no great problem to redo it...

Haven't heard from you for a while. Good to see you still "active" in asm!

Best,
Frank
From: Spam Killer on
On Thu, 29 Nov 2007 23:25:23 GMT, Frank Kotler wrote:
>
>Hey, "Spam Killer"... do you recall sending me the examples from
>Jonathan Bartlett's "PGU" book, translated to Nasm? That's something I
>lost in "the partition mishap" that I haven't recovered. If you've still
>got that around, could you resend? If you can't
>lay your hands on it, no great problem to redo it...

Look into your mail-box.
>
>Haven't heard from you for a while. Good to see you still "active" in asm!
>
Thanks! That will never change, I'm hooked to it!

BTW.: There are two wraping lines in the code
One where the 25 from an imul wraps.
And one from a cmovcc where 21} wraps.
The latter confuses RosAsm when loaded as source only, and
should be fixed before hitting the compile menu option.
--
wfz
From: Frank Kotler on
Spam Killer wrote:
> On Thu, 29 Nov 2007 23:25:23 GMT, Frank Kotler wrote:
>
>>Hey, "Spam Killer"... do you recall sending me the examples from
>>Jonathan Bartlett's "PGU" book, translated to Nasm? That's something I
>>lost in "the partition mishap" that I haven't recovered. If you've still
>>got that around, could you resend? If you can't
>>lay your hands on it, no great problem to redo it...
>
> Look into your mail-box.

Presto! Thanks! Lest I lose it again, I've repackaged it to include just
the Nasm examples, and stuck it up as:

<http://mysite.verizon.net/fbkotler/nasm-pgu-examples.tar.bz2>

The "READDME" I put with it goes like:

--------------------------
These are the examples from Jonathan Bartlett's book,
"Programming from the Ground Up", which uses Gas syntax,
kindly translated to Nasm syntax by Wilhelm Zadrapa.

Note that these are for Linux - sorry, Windows users.

To make any sense of 'em, you'll want the book:

http://www.cafepress.com/bartlettpublish.8640017

Also available in the "'free' as in 'freeloader'" version:
http://savannah.nongnu.org/projects/pgubook/
for those not in the bucks.

If you'd like to read the book, but "follow along" using Nasm,
here are the examples! Thanks Jonathan! Thanks Wilhelm!

fbk - 11/30/07
------------------------

Really appreciate the quick response! Something I meant to do ages ago...

Best,
Frank
From: Terence on
I did this In Fortran with ASM text user interface for the grids and
colours and screen switching..
Allows input, storing, solving, optional step-by-step, which shows
rules applied and second screen of possibilities, progress, optional
hints and so on. Runs in DOS or DOS in Windows.