sudoku.py

Created by ziii

Created on August 26, 2023

4.63 KB

A basic sudoku game, the game is interactive even though I couldn’t create a start menu due to memory limitations.

It creates randomly a sudoku grid every restart.

You can change the difficulty by changing the number of prefilled squares.

The program will tell you if the position is legal, illegal or a solution.

Colors are also customizable, from line 60 to 67 changing the 3 values in parenthesis to some RGB values will change the colors of the things stated above. For example changing (50,50,50) under “# background color” to (0,0,0) will change the color of the background (dark grey to black in this example).

How to play:

Enter a number in the console at the beginning to set the amount of prefilled squares.

Arrows to move the cursor.

0 to empty square.

1-9 to fill a square with a number.

Exe to show a solution, it will also stop the program.


from kandinsky import fill_rect as f, draw_string as d
from ion import *
from time import monotonic
from random import randint,choice
def number(num,pos,COLORS):
  if 10>num>0:
    for x in range(7):
      if l[num][x]:
          f(pos[0]+coo[x][0],pos[1]+coo[x][1],a[x%2],a[(x+1)%2],COLORS)
def possible_numbers(grid, coo):
  l=[1 for _ in range(9)]
  for a in range(9):
    if grid[a][coo[1]]!=-1 and coo[0]!=a:
      l[grid[a][coo[1]]%10]=0
    if grid[coo[0]][a]!=-1 and coo[1]!=a:
      l[grid[coo[0]][a]%10]=0
  for x in range(coo[0]-coo[0]%3,coo[0]-coo[0]%3+3):
    for y in range(coo[1]-coo[1]%3,coo[1]-coo[1]%3+3):
      if grid[x][y]!=-1 and [x,y]!=[coo[0],coo[1]]:
        l[grid[x][y]%10]=0
  l=[x for x in range(9) if l[x]]
  return l
def position_status(grid):
  grid=[[grid[x][y]-1 for y in range(9)]for x in range(9)]
  filled=1
  for x in range(9):
    for y in range(9):
      if grid[x][y]==-1:
        filled=0
      elif not (grid[x][y]%10 in possible_numbers(grid,[x,y])):
        return 0
  return 1+filled
def cur(COLORS):
  f(pos[0]*24+2*(pos[0]//3),pos[1]*24+2*(pos[1]//3),25,1,COLORS)
  f(pos[0]*24+2*(pos[0]//3),(pos[1]+1)*24+2*(pos[1]//3),25,1,COLORS)
  f((pos[0]+1)*24+2*(pos[0]//3),1+pos[1]*24+2*(pos[1]//3),1,23,COLORS)
  f(pos[0]*24+2*(pos[0]//3),1+pos[1]*24+2*(pos[1]//3),1,23,COLORS)
def mov(vx,vy):
  global t,pos
  if monotonic()-t>0.125:
    t=monotonic()
    cur(COLORS[1])
    pos[0]=(pos[0]+vx)%9
    pos[1]=(pos[1]+vy)%9
    cur(COLORS[3])
COLORS=(
(50,50,50),#background
(194,224,255),#grid & text
(220,170,80),#base number & selected text
(255,0,0))# cursor
blanks=81-int(input("Enter prefilled spaces amount\n(80 max,20 advised): "))
show=int(input("show if position is legal ?\n1 for yes, 0 for no: "))
if not 82>blanks>0:
  blanks=20
text=(
"Not legal",
"Legal",
"Solution !")
keys={KEY_ZERO:0,KEY_ONE:1,KEY_TWO:2,KEY_THREE:3,KEY_FOUR:4,KEY_FIVE:5,KEY_SIX:6,KEY_SEVEN:7,KEY_EIGHT:8,KEY_NINE:9}
key_pressing=[0 for _ in range(10)]
key_pressed=[0 for _ in range(10)]
a=2
a=(a,(21-3*a)//2)
l=((1,1,1,0,1,1,1),(1,0,0,0,1,0,0),(0,1,1,1,1,1,0),(0,1,1,1,0,1,1),(1,0,1,1,0,0,1),(1,1,0,1,0,1,1),(1,1,0,1,1,1,1),(0,1,1,0,0,0,1),(1,1,1,1,1,1,1),(1,1,1,1,0,0,1))
coo=((0,a[0]),(a[0],0),(a[0]+a[1],a[0]),(a[0],a[0]+a[1]),(0,2*a[0]+a[1]),(a[0],2*a[0]+2*a[1]),(a[0]+a[1],2*a[0]+a[1]))
f(222,0,98,222,COLORS[0])
f(0,0,222,222,COLORS[1])
for x in range(9):
  for y in range(9):
    f(1+24*x+2*(x//3),1+24*y+2*(y//3),23,23,COLORS[0]) 
if show:
  d("position:",224,10,COLORS[1],COLORS[0])
  d("Legal",224,26,COLORS[1],COLORS[0])
d("0:",224,46,COLORS[1],COLORS[0])
d("empty",224,62,COLORS[1],COLORS[0])
d("1-9:",224,82,COLORS[1],COLORS[0])
d("fill",224,98,COLORS[1],COLORS[0])
d("Exe:",224,118,COLORS[1],COLORS[0])
d("Show a",224,136,COLORS[1],COLORS[0])
d("solution",224,154,COLORS[1],COLORS[0])
sol_grid=[[-1 for _ in range(9)] for _ in range(9)]
tree=[[x for x in range(9)]]
while len(tree)<82:
  if len(tree[-1])==0:
    del tree[-1]
    del tree[-1][tree[-1].index(sol_grid[(len(tree)-1)%9][(len(tree)-1)//9])]
    sol_grid[(len(tree)-1)%9][(len(tree)-1)//9]=-1
  else:
    sol_grid[(len(tree)-1)%9][(len(tree)-1)//9]=choice(tree[-1])
    tree.append(possible_numbers(sol_grid,(len(tree)%9,(len(tree)//9)%9)))
for x in range(9):
  for y in range(9):
    sol_grid[x][y]+=1
del tree
grid=[[y+10 for y in x] for x in sol_grid]
while blanks:
  rand_coo=(randint(0,8),randint(0,8))
  if grid[rand_coo[0]][rand_coo[1]]//10:
    blanks-=1
    grid[rand_coo[0]][rand_coo[1]]=0
for x in range(9):
  for y in range(9):
    if grid[x][y]//10:
      number(grid[x][y]%10,[7+24*x+2*(x//3),2+24*y+2*(y//3)],COLORS[2])
pos=[0,0]
cur(COLORS[3])
t=monotonic()
run=1
while run:
  for k in keys:
    key_pressed[keys[k]]=0
    if keydown(k):
      if not key_pressing[keys[k]]:
        key_pressed[keys[k]]=1
      key_pressing[keys[k]]=1
    else:
      key_pressing[keys[k]]=0
  if keydown(KEY_LEFT):
    mov(-1,0)
  elif keydown(KEY_UP):
    mov(0,-1)
  elif keydown(KEY_DOWN):
    mov(0,1)
  elif keydown(KEY_RIGHT):
    mov(1,0)
  elif keydown(KEY_EXE):
    cur(COLORS[1])
    for x in range(9):
      for y in range(9):
        f(1+24*x+2*(x//3),1+24*y+2*(y//3),23,23,COLORS[0])
        number(sol_grid[x][y]%10,(7+x*24+2*(x//3),2+y*24+2*(y//3)),COLORS[2])
    run=0
  elif not grid[pos[0]][pos[1]]//10:
    for n,k in enumerate(key_pressed):
      if k:
        grid[pos[0]][pos[1]]=n
        f(1+pos[0]*24+2*(pos[0]//3),1+pos[1]*24+2*(pos[1]//3),23,23,COLORS[0])
        f(224,26,96,18,COLORS[0])
        if show:
          state=position_status(grid)
          d(text[state],224,26,COLORS[1],COLORS[0])
        if n:
          number(n,(7+24*pos[0]+2*(pos[0]//3),2+24*pos[1]+2*(pos[1]//3)),COLORS[1])