Files
sudoku/sudoku.py
2026-02-28 12:44:41 +01:00

167 lines
8.8 KiB
Python

from random import randint, shuffle # za generiranje naključnega sudokuja
from copy import deepcopy # za kopiranje že rešenega sudokuja
from time import time # za merjenje časa
sudoku = [ # začnemo s praznim sudokujem
[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,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,0,0,0,0,0,0,0,0],
[0,0,0,0,0,0,0,0,0]
]
class GeneratorSudokuja:
def veljavna(self, sudoku, stevilka, vrstica, stolpec): # funkcija, ki preveri veljavnost številke na določenem mestu, kjer sta vrstica in stolpec enaka i in j (j,i) = (x,y)
for i in range(9):
if stevilka == sudoku[vrstica][i] or stevilka == sudoku[i][stolpec] or stevilka == sudoku[3 * (vrstica//3) + i // 3][3 * (stolpec//3) + i % 3]:
return False # če je številka enaka katerikoli izmed treh možnosti (v vrstici, v stolpcu ali pa v 3x3 mreži), funkcija vrne False
return True # drugače True
def generiraj(self, sudoku): # funkcija, ki generira sudoku
for i in range(9):
for j in range(9):
if sudoku[i][j] == 0:
stevila = list(range(1,10)) # seznam od 1 do 9, tako se nobena ne ponavlja
shuffle(stevila) # jih premešamo npr. [5, 2, 7, 6, 1, 9, 3, 8, 4]
for stevilka in stevila:
if self.veljavna(sudoku, stevilka, i, j): # za vsako številko preverimo, če je na mestu [i][j] veljavna
sudoku[i][j] = stevilka # če je, jo na mesto [i][j] vpišemo, tam ni več 0
if self.generiraj(sudoku) == True:
return True # če je sudoku s tisto številko zgeneriran, bo tam ostala
sudoku[i][j] = 0 # če ne, pa program vpiše na mesto 0 in proba z drugo naključno številko
return False # če ni nobena številka na tistem mestu veljavna, vrne False
return True
def odstranjevanje(self, sudoku, koliko): # funkcija, ki odstranjuje številke iz sudokuja
st = 0
while st < koliko: # odstranjujemo, dokler ne pride st do koliko
i = randint(0, 8) # naključni koordinati
j = randint(0, 8)
if sudoku[i][j] != 0: # odstrani samo, ko ni enako 0, da program ne bi odšel recimo na enem mestu trikrat.
sudoku[i][j] = 0
st += 1
def izpisisudoku(): # funkcija za izpisovanje sudokuja
print()
for i, vrstica in enumerate(sudoku): # v terminal narišemo sudoku # enumerate vrne indeks vrstice(i) in vrstico.
if i % 3 == 0 and i != 0: # ko je indeks večkratnik od 3, bo program vrinil med številke vrsto črtic.
print("-" * 21)
for j, stevilo in enumerate(vrstica): # j je indeks vsake številke v vrstici, ko je ta večkratnik od 3, se bo vrinila navpična črta, končana s presledkom
if j % 3 == 0 and j != 0:
print("|", end=" ")
if stevilo == 0:
print(0, end=" ") # 0 so bele
else:
print("\033[34m"+str(stevilo)+"\033[0m", end=" ") # če j ni večkratnik števila 3, program napiše barvno številko in konča s presledkom
print() # ko se ena vrstica konča, gre program v novo vrstico
print()
# ----------------------------------------------------------------------------------------------------------------------------------------------------------------
# igra
# ----------------------------------------------------------------------------------------------------------------------------------------------------------------
print("SUDOKU")
print()
tezavnost = input("Izberi težavnost(lahka, srednja, težka, nemogoča):")
while tezavnost != "lahka" and tezavnost != "težka" and tezavnost != "srednja" and tezavnost != "nemogoča":
print("Še enkrat jasno napiši.")
tezavnost = input("Izberi težavnost(lahka, srednja, težka, nemogoča):")
if tezavnost == "lahka": # težavnost pove, koliko številk moramo odstraniti
odstrani = 35
elif tezavnost == "srednja":
odstrani = 42
elif tezavnost == "težka":
odstrani = 49
elif tezavnost == "nemogoča":
odstrani = 56
generator = GeneratorSudokuja()
generator.generiraj(sudoku) # zgeneriramo sudoku
resensudoku = deepcopy(sudoku) # kopiramo rešen sudoku in ga damo v spremenljivko
generator.odstranjevanje(sudoku, odstrani) # odstrani nam pove, koliko jih moramo odstraniti, odstrani = koliko
izpisisudoku() # tu program prvič izpiše sudoku
odgovori = ["Pravilno!","Odlično!","Točno tako!","Prav je!","Super!","Bravo!","Zadetek!","Natančno!","Fantastično!"] # množica odgovorov za pravilno rešitev
pomote = 0 # štetje pomot
namigi = 0 # štetje namigov
start = time() # štetje časa
while True: # s tem poskrbimo, da vedno znova (ob vsakem vnosu) program pogleda najprej, če je sudoku rešen, potem če je admin ali pa namig
# šele po vseh teh preverbah program razdeli vnos (vnos.split(","))
if sudoku == resensudoku:
break # ko pride uporabnik do konca, gre program iz While zanke
vnos = input('Vnesi številko in koordinate le-te.:')
if vnos.upper() == "END": # easter egg
break
elif vnos.upper() == "ADM": # samo za admina za preverjanje kode
e = randint(0,8)
f = randint(0,8)
while sudoku[f][e] != 0:
e = randint(0,8)
f = randint(0,8)
sudoku[f][e] = resensudoku[f][e] # program avtomatsko reši eno prazno polje
print()
print("Goljufaš. To je samo za admina.")
izpisisudoku()
continue
elif vnos.upper() == "NAMIG": # uporabnik lahko zaprosi za namig, če je obtičal
namigi += 1 # program prišteje en uporabljen namig
e = randint(0,8)
f = randint(0,8)
while sudoku[f][e] != 0:
e = randint(0,8) # program generira nove koordinate, dokler ne naleti na 0
f = randint(0,8)
print()
print("Na koordinatah x =",e+1,"in y =",f+1,"je število", resensudoku[f][e])
izpisisudoku() # izpiše sudoku
continue
vnos = vnos.split(",") # ko vnos ni več "end" ali pa "namig", program vnos (npr. "6,1,5") razčleni v seznamu (["6", "1", "5"]).
if len(vnos) != 3: # če se uporabnik zatipka (npr. 6,5 namesto 6,1,5), se program ne bo ustavil (line 136 index out of range), pač pa mu dal še eno priložnost
print()
print("Zatipkal si se. Poskusi ponovno.")
izpisisudoku() # izpiše sudoku
continue
try:
vnos_st = int(vnos[0]) # 6
vnos_x = int(vnos[1])-1 # 0 -> ker program sudoku mrežo bere od 0-8, ne od 1-9
vnos_y = int(vnos[2])-1 # 4 -> isto
except ValueError: # če pride do ValueErrorja, program ne bo crashal, pač pa se bo vrnil na začetek zanke
print()
print('Vnesi le števila ali pa "namig".')
izpisisudoku() # izpiše sudoku
continue
if vnos_st not in range(1,10) or vnos_x not in range(9) or vnos_y not in range(9): # v primeru napake pri vnosu velikosti števila
print()
print("Napaka. Vpiši števila med 1 in 9.")
else:
if sudoku[vnos_y][vnos_x] != 0: # če je uporabnik dislektičen
print()
print("Napaka. Številko vpiši v prazno polje.")
else:
sudoku[vnos_y][vnos_x] = vnos_st # vpišemo številko na prazno polje
if resensudoku[vnos_y][vnos_x] != vnos_st: # če se ne ujema s številko v rešenem sudokuju, se številka ne vpiše (line 154)
print()
print("Pomota. Poskusi ponovno.")
sudoku[vnos_y][vnos_x] = 0
pomote += 1 # število pomot gre gor
else:
print()
print(odgovori[randint(0,len(odgovori)-1)]) # potrdilo, vzeto iz množice odgovorov (line 94)
izpisisudoku() # izpiše sudoku
end = time() # ko je zanke konec, se merjenje časa ustavi
cas = end - start
if vnos == "end": # če uporabnik predčasno konča igro
print("Škoda. Več sreče prihodnjič. Število namigov:", namigi, "Število pomot:", pomote)
else: # če pride do konca
print("Čestitke, sudoku si pravilno rešil v", int(cas//60), "min in", int(cas % 60) ,"sek. Število namigov:", namigi, "Število pomot:", pomote)