rem ================================================================== rem SuNaaLaaDoku rem rem By Marcus rem ================================================================== visible: rem Images. FIELD_IMAGE = 0 BG_IMAGE = 1 PUZZLE_IMAGE = 2 BUTTON_IMAGE = 3 PUZZLE_SOLVED_IMAGE = 4 LOGO_IMAGE = 6 rem Buttons. NEW_PUZZLE_BUTTON = 1 EASY_BUTTON = 2 NORMAL_BUTTON = 3 HARD_BUTTON = 4 hidden: if javac() ext$ = ".png" else ext$ = ".bmp" endif rem Set size of window and turn off automatic redraw. set window 16, 16, 330, 362 set redraw off set color 0, 0, 0 cls redraw rem Create or load font. if javac() load font 0, "arial24.txt", "arial24.png" else create font 0, "arial", 24, true, false, false, true save font 0, "arial24.txt", "arial24.bmp" endif rem Tell user that we're loading. set caret width(primary)/2, (height(primary) - fheight(0))/2 set color 255, 255, 255 center "Loading ..." redraw rem Load field image. load image FIELD_IMAGE, "field" + ext$ set image grid FIELD_IMAGE, 2, 1 rem Load background image. load image BG_IMAGE, "bg" + ext$ rem Load button image. load image BUTTON_IMAGE, "button" + ext$ set image grid BUTTON_IMAGE, 1, 3 load image LOGO_IMAGE, "sunaalaadoku" + ext$ load image PUZZLE_SOLVED_IMAGE, "puzzle_solved" + ext$ create image PUZZLE_IMAGE, width(primary), height(primary) puzzle[9][9] solution[9][9] player[9][9] do rem Select difficulty. set image PUZZLE_IMAGE proc DrawGrid puzzle, puzzle set image primary x = (width(primary) - width(BUTTON_IMAGE))/ 2 w = width(BUTTON_IMAGE) h = height(BUTTON_IMAGE) create zone EASY_BUTTON, x, 100 - 10, w, h create zone NORMAL_BUTTON, x, 150 - 10, w, h create zone HARD_BUTTON, x, 200 - 10, w, h selected = 0 do if not running() then end set color 128, 128, 128 draw image PUZZLE_IMAGE, 0, 0 set color 255, 255, 255 draw image LOGO_IMAGE, (width(primary) - width(LOGO_IMAGE))/2, 30 selected = zone() proc DrawButton EASY_BUTTON, "Easy" proc DrawButton NORMAL_BUTTON, "Normal" proc DrawButton HARD_BUTTON, "Hard" redraw wait 10 until selected free zone EASY_BUTTON free zone NORMAL_BUTTON free zone HARD_BUTTON if selected = EASY_BUTTON level = 30 elseif selected = NORMAL_BUTTON level = 60 else level = 100 endif rem Generate puzzle. proc GenerateSudoku puzzle, solution, level for y = 0 to 8 for x = 0 to 8 player[x][y] = puzzle[x][y] next next set image PUZZLE_IMAGE proc DrawGrid puzzle, player set image primary marked = false create zone NEW_PUZZLE_BUTTON, (width(primary) - width(BUTTON_IMAGE))/ 2, 309, width(BUTTON_IMAGE), height(BUTTON_IMAGE) rem Game loop. do if not running() then end rem Transform mouse coordinates to sudoku grid. if not marked xm = mousex() - 16 ym = mousey() - 16 xm = xm - ((xm/32)/3)*4 ym = ym - ((ym/32)/3)*4 xm = xm / 32 ym = ym / 32 rem Check if it's possible to change the value at the mouse position. valid = false if xm >= 0 and xm < 9 and ym >= 0 and ym < 9 if puzzle[xm][ym] = 0 then valid = true endif endif rem Mark cel? if not marked if mousebutton(0, true) and valid marked = true dummy = inkey() endif else rem Unmark if mousebutton. if mousebutton(0, true) marked = false else rem Check for key. key = inkey() if key > 0 k$ = chr$(key) key = int(k$) if key > 0 and key <= 9 player[xm][ym] = key else player[xm][ym] = 0 endif set image PUZZLE_IMAGE proc DrawGrid puzzle, player set image primary if PuzzleCompleted(player, solution) set color 128, 128, 128 draw image PUZZLE_IMAGE, 0, 0 set color 255, 255, 255 draw image PUZZLE_SOLVED_IMAGE, (width(primary) - width(PUZZLE_SOLVED_IMAGE))/2, 118 redraw wait mousebutton break endif marked = false endif endif endif rem Draw puzzle. set color 255, 255, 255 draw image PUZZLE_IMAGE, 0, 0 rem Draw marked cel. if marked set color 128, 128, 255, 128 draw rect 16 + xm*32 + (xm/3)*4, 16 + ym*32 + (ym/3)*4, 32, 32, true elseif valid set color 255, 255, 255, 128 draw rect 16 + xm*32 + (xm/3)*4, 16 + ym*32 + (ym/3)*4, 32, 32, true endif proc DrawButton NEW_PUZZLE_BUTTON, "New Puzzle" rem Redraw and wait. redraw wait 10 until zone() loop rem ================================================================== rem Put a puzzle in 'puzzle' and the solution in 'solution'. They're rem Both assumed to be of the size 9*9. Difficulty is simply the rem number of fields that the generator will try to remove. rem ================================================================== procedure GenerateSudoku(&puzzle[][], &solution[][], difficulty) rem A valid grid but stupid grid. for y = 0 to 8 for x = 0 to 8 solution[x][y] = (x + 3*y + y/3)%9 + 1 next next rem Let's make some legal transformations to mess up the grid. randomize time() for i = 0 to 20 proc Transform solution next rem Copy solution to puzzle. As this is supposed to work in java, rem we can't simply write puzzle = solution. for y = 0 to 8 for x = 0 to 8 puzzle[x][y] = solution[x][y] next next rem Remove some fields. candidates[81] for i = 0 to difficulty rem Find all visible fields. cCount = 0 for y = 0 to 8 for x = 0 to 8 if puzzle[x][y] > 0 candidates[cCount] = y*9 + x cCount = cCount + 1 endif next next rem Select a field. cel = candidates[rnd(cCount)] y = cel/9 x = cel%9 rem Store number of field, remove it and try to solve puzzle. number = puzzle[x][y] puzzle[x][y] = 0 rem If puzzle can't be solved, then put the number back. if not Solve(puzzle) then puzzle[x][y] = number next endproc rem ================================================================== rem Return true if puzzle can be solved. rem ================================================================== function Solve(&puzzle[][]) g[9][9] for y = 0 to 8 for x = 0 to 8 g[x][y] = puzzle[x][y] next next lastCelsLeft = 0 do celsLeft = 0 for y = 0 to 8 for x = 0 to 8 if g[x][y] = 0 celsLeft = celsLeft + 1 value = Single(g, x, y) g[x][y] = value endif next next if celsLeft = lastCelsLeft if celsLeft = 0 return true else return false endif endif lastCelsLeft = celsLeft loop endfunc rem ================================================================== rem Is there a single solution for this field? rem ================================================================== function Single(&g[][], celX, celY) numbers[10] for i = 0 to 9 numbers[i] = true next for x = 0 to 8 numbers[g[x][celY]] = false next for y = 0 to 8 numbers[g[celX][y]] = false next celX = (celX/3)*3 celY = (celY/3)*3 for y = 0 to 2 for x = 0 to 2 numbers[g[celX + x][celY + y]] = false next next numberCount = 0 for i = 1 to 9 if numbers[i] then numberCount = numberCount + 1 next if numberCount > 1 return 0 else for i = 1 to 9 if numbers[i] then break next return i endif endfunc rem ================================================================== rem Draw grid. rem ================================================================== procedure DrawGrid(&puzzle[][], player[][]) xadd = 16 yadd = 16 set color 255, 255, 255 draw image BG_IMAGE, 0, 0 set color 255, 255, 255 for y = 0 to 8 for x = 0 to 8 if puzzle[x][y] > 0 draw image FIELD_IMAGE, xadd + x*32 + (x/3)*4, yadd + y*32 + (y/3)*4, 0 else draw image FIELD_IMAGE, xadd + x*32 + (x/3)*4, yadd + y*32 + (y/3)*4, 1 endif next next modX = rnd(9) modY = rnd(9) for y = 0 to 8 for x = 0 to 8 set caret xadd + x*32 + 16 + (x/3)*4, yadd + y*32 + 5 + (y/3)*4 if puzzle[x][y] set color 112, 0, 53 center puzzle[x][y] elseif player[x][y] set color 128, 128, 255 center player[x][y] endif next next endproc rem ================================================================== rem Transform grid. rem ================================================================== procedure Transform(&g[][]) type = rnd(4) if type = 0 rem Flip by row. add = rnd(3)*3 for y = 0 to 3 for x = 0 to 8 tmp = g[x][(y + add)%9] g[x][(y + add)%9] = g[x][(8 - y + add)%9] g[x][(8 - y + add)%9] = tmp next next elseif type = 1 rem Flip by col. add = rnd(3)*3 for x = 0 to 3 for y = 0 to 8 tmp = g[(x + add)%9][y] g[(x + add)%9][y] = g[(8 - x + add)%9][y] g[(8 - x + add)%9][y] = tmp next next elseif type = 2 rem Flip diagonally. add = rnd(3)*3 for i = 0 to 7 for x = i + 1 to 8 tmp = g[(x + add)%9][i] g[(x + add)%9][i] = g[(i + add)%9][x] g[(i + add)%9][x] = tmp next next elses rem Flip diagonally add = rnd(3)*3 for i = 0 to 7 for x = i + 1 to 8 tmp = g[(8 - x + add)%9][i] g[(8 - x + add)%9][i] = g[(8 - i + add)%9][x] g[(8 - i + add)%9][x] = tmp next next endif rem Always swap two numbers. do numberA = rnd(9) + 1 numberB = rnd(9) + 1 until numberA <> numberB for y = 0 to 8 for x = 0 to 8 if g[x][y] = numberA g[x][y] = numberB elseif g[x][y] = numberB g[x][y] = numberA endif next next endproc rem ================================================================== rem Return true if player's puzzle matches solution. rem ================================================================== function PuzzleCompleted(player[][], solution[][]) completed = true for y = 0 to 8 for x = 0 to 8 if player[x][y] <> solution[x][y] then completed = false next next return completed endfunc rem ================================================================== rem Draw button. rem ================================================================== procedure DrawButton(id, text$) set color 255, 255, 255 state = zone(id) draw image BUTTON_IMAGE, zonex(id), zoney(id), state offs = 0 if state = 0 set color 112, 0, 53 elseif state = 1 set color 112, 0, 53, 128 else set color 96, 0, 48 offs = 1 endif set caret zonex(id) + zonew(id)/2 + offs, zoney(id) + 11 + offs center text$ endproc