×
Dodano do koszyka:
Pozycja znajduje się w koszyku, zwiększono ilość tej pozycji:
Zakupiłeś już tę pozycję:
Książkę możesz pobrać z biblioteki w panelu użytkownika
Pozycja znajduje się w koszyku
Przejdź do koszyka

Zawartość koszyka

ODBIERZ TWÓJ BONUS :: »

Sudoku z Pythonem

Sudoku z Pythonem


001: """Sudoku, autor: Al Sweigart, al@inventwithpython.com
002: Klasyczna  układanka liczbowa z planszą 9x9.
003: Więcej informacji na stronie https://pl.wikipedia.org/wiki/Sudoku.
004: Kod pobrany ze strony https://ftp.helion.pl/przyklady/wiksma.zip.
005: Etykiety: długi, gra, zorientowany obiektowo, łamigłówka"""
006: 
007: import copy, random, sys
008: 
009: # Ta gra wymaga pliku sudokupuzzle.txt, który zawiera łamigłówkę.
010: # Plik możesz pobrać ze strony https://ftp.helion.pl/przyklady/wiksma.zip.
011: # Oto przykład zawartości takiego pliku:
012: # ..3.2.6..9..3.5..1..18.64....81.29..7.......8..67.82....26.95..8..2.3..9..5.1.3..
013: # 2...8.3...6..7..84.3.5..2.9...1.54.8.........4.27.6...3.1..7.4.72..4..6...4.1...3
014: # ......9.7...42.18....7.5.261..9.4....5.....4....5.7..992.1.8....34.59...5.7......
015: # .3..5..4...8.1.5..46.....12.7.5.2.8....6.3....4.1.9.3.25.....98..1.2.6...8..6..2.
016: 
017: # Deklaracja stałych:
018: EMPTY_SPACE = '.'
019: GRID_LENGTH = 9
020: BOX_LENGTH = 3
021: FULL_GRID_SIZE = GRID_LENGTH * GRID_LENGTH
022: 
023: 
024: class SudokuGrid:
025:     def __init__(self, originalSetup):
026:         # Zmienna originalSetup to łańcuch 81 znaków początkowego stanu
027:         # planszy, z liczbami i kropkami (dla pustych pól).
028:         # Patrz plik sudokupuzzles.txt
029:         self.originalSetup = originalSetup
030: 
031:         # Dany stan planszy sudoku jest przedstawiony za pomocą słownika
032:         # z kluczami (x, y) i wartością liczbową (zapisaną w formie łańcucha znaków) w
033:         # przypisanym do klucza miejscu.
034:         self.grid = {}
035:         self.resetGrid()  # Przywróć planszę do stanu początkowego.
036:         self.moves = []  # Zapisuje każdy ruch, co jest przydatne podczas korzystania z funkcji Cofnij.
037: 
038:     def resetGrid(self):
039:         """Przywraca początkowy stan planszy,
040:         zapisany w self.originalSetup."""
041:         for x in range(1, GRID_LENGTH + 1):
042:             for y in range(1, GRID_LENGTH + 1):
043:                 self.grid[(x, y)] = EMPTY_SPACE
044: 
045:         assert len(self.originalSetup) == FULL_GRID_SIZE
046:         i = 0  # i rośnie od 0 do 80
047:         y = 0  # y rośnie od 0 do 8
048:         while i < FULL_GRID_SIZE:
049:             for x in range(GRID_LENGTH):
050:                 self.grid[(x, y)] = self.originalSetup[i]
051:                 i += 1
052:             y += 1
053: 
054:     def makeMove(self, column, row, number):
055:         """Umieszcza na planszy liczbę w danej kolumnie (litera od A do I)
056:         i danym wierszu (liczba całkowita od 1 do 9)."""
057:         x = 'ABCDEFGHI'.find(column)  # Zamień na liczbę całkowitą.
058:         y = int(row) - 1
059: 
060:         # Sprawdź, czy dany ruch jest wykonywany na liczbie, która jest podana na początku gry:
061:         if self.originalSetup[y * GRID_LENGTH + x] != EMPTY_SPACE:
062:             return False
063: 
064:         self.grid[(x, y)] = number  # Umieść tę liczbę na siatce.
065: 
066:         # Musimy zapisać osobną kopię słownika:
067:         self.moves.append(copy.copy(self.grid))
068:         return True
069: 
070:     def undo(self):
071:         """Przywróć stan planszy do poprzedniego stanu
072:         zapisanego w liście self.moves."""
073:         if self.moves == []:
074:             return  # Brak danych w self.moves, nic nie rób.
075: 
076:         self.moves.pop()  # Usuń dane bieżącego stanu.
077: 
078:         if self.moves == []:
079:             self.resetGrid()
080:         else:
081:             # Ustaw poprzedni stan siatki:
082:             self.grid = copy.copy(self.moves[-1])
083: 
084:     def display(self):
085:         """Wyświetl aktualny stan planszy na ekranie."""
086:         print('   A B C   D E F   G H I')  # Wyświetl oznaczenia kolumn.
087:         for y in range(GRID_LENGTH):
088:             for x in range(GRID_LENGTH):
089:                 if x == 0:
090:                     # Wyświetl oznaczenia wierszy:
091:                     print(str(y + 1) + '  ', end='')
092: 
093:                 print(self.grid[(x, y)] + ' ', end='')
094:                 if x == 2 or x == 5:
095:                     # Wyświetl linię pionową:
096:                     print('| ', end='')
097:             print()  # Wyświetl znak nowej linii:
098: 
099:             if y == 2 or y == 5:
100:                 # Wyświetl linię poziomą:
101:                 print('   ------+-------+------')
102: 
103:     def _isCompleteSetOfNumbers(self, numbers):
104:         """Zwraca wartość True, jeśli liczby zawierają cyfry od 1 do 9."""
105:         return sorted(numbers) == list('123456789')
106: 
107:     def isSolved(self):
108:         """Zwraca wartość True, jeśli bieżący stan planszy to rozwiązanie."""
109:         # Sprawdź każdy wiersz:
110:         for row in range(GRID_LENGTH):
111:             rowNumbers = []
112:             for x in range(GRID_LENGTH):
113:                 number = self.grid[(x, row)]
114:                 rowNumbers.append(number)
115:             if not self._isCompleteSetOfNumbers(rowNumbers):
116:                 return False
117: 
118:         # Sprawdź każdą kolumnę:
119:         for column in range(GRID_LENGTH):
120:             columnNumbers = []
121:             for y in range(GRID_LENGTH):
122:                 number = self.grid[(column, y)]
123:                 columnNumbers.append(number)
124:             if not self._isCompleteSetOfNumbers(columnNumbers):
125:                 return False
126: 
127:         # Sprawdź każdy blok 3x3:
128:         for boxx in (0, 3, 6):
129:             for boxy in (0, 3, 6):
130:                 boxNumbers = []
131:                 for x in range(BOX_LENGTH):
132:                     for y in range(BOX_LENGTH):
133:                         number = self.grid[(boxx + x, boxy + y)]
134:                         boxNumbers.append(number)
135:                 if not self._isCompleteSetOfNumbers(boxNumbers):
136:                     return False
137: 
138:         return True
139: 
140: 
141: print('''Sudoku, autor: Al Sweigart, al@inventwithpython.com
142: 
143: Sudoku to układanka liczbowa. Plansza sudoku to siatka 9x9.
144: Spróbuj umieścić na siatce liczby w taki sposób, by dana cyfra od 1 do 9
145: występowała tylko raz w danym wierszu, kolumnie i bloku 3x3.
146: 
147: Oto przykładowa plansza na początku gry i już rozwiązana:
148: 
149:     5 3 . | . 7 . | . . .     5 3 4 | 6 7 8 | 9 1 2
150:     6 . . | 1 9 5 | . . .     6 7 2 | 1 9 5 | 3 4 8
151:     . 9 8 | . . . | . 6 .     1 9 8 | 3 4 2 | 5 6 7
152:     ------+-------+------     ------+-------+------
153:     8 . . | . 6 . | . . 3     8 5 9 | 7 6 1 | 4 2 3
154:     4 . . | 8 . 3 | . . 1 --> 4 2 6 | 8 5 3 | 7 9 1
155:     7 . . | . 2 . | . . 6     7 1 3 | 9 2 4 | 8 5 6
156:     ------+-------+------     ------+-------+------
157:     . 6 . | . . . | 2 8 .     9 6 1 | 5 3 7 | 2 8 4
158:     . . . | 4 1 9 | . . 5     2 8 7 | 4 1 9 | 6 3 5
159:     . . . | . 8 . | . 7 9     3 4 5 | 2 8 6 | 1 7 9
160: ''')
161: input('Naciśnij Enter, aby rozpocząć...')
162: 
163: 
164: # Wgraj plik sudokupuzzles.txt:
165: with open('sudokupuzzles.txt') as puzzleFile:
166:     puzzles = puzzleFile.readlines()
167: 
168: # Usuń znak nowej linii na końcu każdej łamigłówki:
169: for i, puzzle in enumerate(puzzles):
170:     puzzles[i] = puzzle.strip()
171: 
172: grid = SudokuGrid(random.choice(puzzles))
173: 
174: while True:  # Główna pętla gry.
175:     grid.display()
176: 
177:     # Sprawdź, czy sudoku zostało rozwiązane.
178:     if grid.isSolved():
179:         print('Gratulacje! Rozwiązałeś łamigłówkę!')
180:         print('Dziękujemy za grę!')
181:         sys.exit()
182: 
183:     # Pobierz ruch gracza:
184:     while True:  # Pytaj, dopóki gracz nie poda prawidłowego działania.
185:         print()  # Wyświetl znak nowej linii.
186:         print('Podaj ruch lub wpisz RESET, NOWA, COFNIJ, POCZĄTEK lub KONIEC:')
187:         print('(Przykładowy ruch to "B4 9".)')
188: 
189:         action = input('> ').upper().strip()
190: 
191:         if len(action) > 0 and action[0] in ('R', 'N', 'C', 'P', 'K'):
192:             # Gracz podał prawidłowe działanie.
193:             break
194: 
195:         if len(action.split()) == 2:
196:             space, number = action.split()
197:             if len(space) != 2:
198:                 continue
199: 
200:             column, row = space
201:             if column not in list('ABCDEFGHI'):
202:                 print('Nie ma takiej kolumny', column)
203:                 continue
204:             if not row.isdecimal() or not (1 <= int(row) <= 9):
205:                 print('Nie ma takiego wiersza', row)
206:                 continue
207:             if not (1 <= int(number) <= 9):
208:                 print('Wybierz cyfrę od 1 do 9, a nie ', number)
209:                 continue
210:             break  # Gracz podał odpowiedni ruch.
211: 
212:     print()  # Wyświetl znak nowej linii.
213: 
214:     if action.startswith('R'):
215:         # Przywróć planszę do stanu początkowego:
216:         grid.resetGrid()
217:         continue
218: 
219:     if action.startswith('N'):
220:         # Wgraj nową łamigłówkę:
221:         grid = SudokuGrid(random.choice(puzzles))
222:         continue
223: 
224:     if action.startswith('C'):
225:         # Cofnij ostatni ruch:
226:         grid.undo()
227:         continue
228: 
229:     if action.startswith('P'):
230:         # Pokaż początkowy stan planszy:
231:         originalGrid = SudokuGrid(grid.originalSetup)
232:         print('Na początku plansza wyglądała tak:')
233:         originalGrid.display()
234:         input('Naciśnij Enter, aby rozpocząć...')
235: 
236:     if action.startswith('K'):
237:         # Wyjdź z gry.
238:         print('Dziękujemy za grę!')
239:         sys.exit()
240: 
241:     # Wykonaj podany przez gracza ruch:
242:     if grid.makeMove(column, row, number) == False:
243:         print('Nie możesz nadpisać liczby, która była wpisana już na początku gry.')
244:         print('Wpisz POCZĄTEK, by zobaczyć planszę początkową.')
245:         input('Naciśnij Enter, aby rozpocząć...')


 

 

Zamknij Pobierz aplikację mobilną Helion
Zabrania się wykorzystania treści strony do celów eksploracji tekstu i danych (TDM), w tym eksploracji w celu szkolenia technologii AI i innych systemów uczenia maszynowego. It is forbidden to use the content of the site for text and data mining (TDM), including mining for training AI technologies and other machine learning systems.