- Sudoku - na czym polega
- Logika dla walidacji
- Obiekt Set w
python
array_unique()
iarray_flip()
dlaphp
-
Zamiana wierszy na kolumny w
Python
iphp
- Otrzymanie subgrid’a 3 x 3
Sudoku - na czym polega
Sudoku według Wikipedii jest łamigłówką, w której zadaniem jest wypełnienie diagramu 9 × 9 w taki sposób, aby w każdym wierszu, w każdej kolumnie i w każdym z dziewięciu pogrubionych kwadratów 3 × 3 znalazło się po jednej cyfrze od 1 do 9.
Wbrew pozorom nie jest to takie łatwe - sama gra nie pociąga mnie zbytnio, ale zadanie jakie ostatnio wykonywałam właśnie na sudoku - już tak .
Zadaniem było sprawdzenie, czy podany ciąg liczb - spełnia reguły gry - czyli w wierszu i kolumnie są cyfry od 1…9 oraz czy w subgridzie 3 x 3 są cyfry od 1…9.
Danymi wejściowymi był ciąg znaków reprezentujący wypełniony już diagram. Po 9 znaków w każdym wierszu. Powtarzany 9 razy:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
# INPUT:
1 2 3 4 5 6 7 8 9
4 5 6 7 8 9 1 2 3
7 8 9 1 2 3 4 5 6
9 1 2 3 4 5 6 7 8
3 4 5 6 7 8 9 1 2
6 7 8 9 1 2 3 4 5
8 9 1 2 3 4 5 6 7
2 3 4 5 6 7 8 9 1
5 6 7 8 9 1 2 3 4
# OUTPUT
true - dla poprawnie wypełnionego sudoku,
false - gdy jest chociaż jeden błąd w wypełnionym diagramie
Powyższy diagram jest poprawnie wypełnionym sudoku.
Logika dla walidacji
Musimy się zastanowić wpierw nad tym, w jaki sposób sprawdzić wiersze, potem kolumny, a potem poddiagram wielkości 3 x 3.
Jak dla mnie, najprostszym rozwiązaniem jakie przychodzi do głowy, to sprawdzić czy w wierszu występują duplikaty - jeśli któraś z liczb się powtórzyła, tzn. że diagram jest wypełniony niepoprawnie już w pierwszym kroku sprawdzania. Podobną metodę stosujemy w kolejnych krokach, czyli dla kolumn, a potem do poddiagramu 3 x 3.
Obiekt Set w python
W py
jak i w js
mamy do dyspozycji specjalny typ danych zwany Set - jest to obiekt, który przetrzymuje w sobie TYLKO UNIKALNE WARTOŚCI.
Przyjżyjmy się przykładowi. Załóżmy, że mamy listę / tablicę przypisaną do zmiennej tablica. Chcemy z niej otrzymać set:
1
2
3
4
5
6
7
tablica = [1, 2, 1, 2]
set_z_tablica = set(tablica)
print(set_z_tablica)
# OUTPUT:
# {1, 2}
Tak sety nam się w walidacji sudoku przydadzą. Zobaczmy pierwszy wiersz naszych danych wejściowych:
1
2
3
4
wiersz = [1, 2, 3, 4, 5, 6, 7, 8, 9]
print(set(wiersz))
# OUTPUT:
# {1, 2, 3, 4, 5, 6, 7, 8, 9}
No tak ale w taki sposób porównywanie jest bez sensu. Jeśli w naszym set-cie przekształconym z wiersza długość elementów będzie równa 9 to znaczy, że wiersz jest wypełniony prawidłowo. Jeśli, któraś liczba się powtórzy, set będzie krótszy, bo zduplikowana wartość wystąpi jedynie raz:
1
2
3
4
5
wiersz = [8, 9, 1, 2, 3, 4, 5, 6,7]
print(len(set(wiersz)))
# OUTPUT:
# 9
Ok. Wspomniałam, że w py
i w js
i pewnie w jeszcze kilku innych językach programowania są set-y,a co z php
.
array_unique()
i array_flip()
dla php
Otórz w php
też wstępują set-y, ale potrzebna jest do tego dodatkowa biblioteka. Jednak nie będzie ona dostępna wszędzie. Na szczęście mamy dwie inne możliwości jeśli chodzi o php
. Albo wykorzystamy array_unique()
albo array_flip()
.
1
2
3
4
5
6
7
8
9
10
11
12
13
<?php
$tablica = [1,2,1,2];
print_r(array_unique($tablica));
/*
OUTPUT:
Array
(
[0] => 1
[1] => 2
)
*/
array_unique()
działa dość intuicyjnie - tworzy nową tablicę, ze zmiennej, tylko z unikalnymi wartościami.
array_flip()
natomiast jest ciekawszym rozwiązaniem - zamienia on wartości na klucze i klucze na wartości. Wiemy, że w tablicy klucze nie mogą się powtarzać. Stąd, jeśli klucz się powtórzy - wartość zostanie nadpisana. Zobaczmy jak działa to w praktyce:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
<?php
$tablica = [1, 2, 1, 2];
print_r(array_flip($tablica));
/*
OUTPUT:
Array
(
[1] => 2 // bo jedynka jest na pozycji 0 i 2
// więc wartością naszego array_flip dla 1 jest liczba 2
// jako ostatni indeks występowania wartości w pierwotnej tablicy $tablica
[2] => 3 // bo dwójka (jak wskazuje klucz powstałej tablicy)
// występuje na miejscu 1 i 3, stąd mamy [2] => 3
)
*/
Najważniejszą część kodu mamy obmyśloną. Teraz wystarczy sprawdzić, czy wynik z array_unique()
lub array_flip()
jest równy 9. Jeśli tak - to znaczy, że wiersz jest wypełniony prawidłowo.
Zamiana wierszy na kolumny w Python
i php
Przejdźmy do kolumn. Zaczynając swoją przygodę z programowaniem niejednokrotnie człowiek zastanawia się jak przekształcić tablicę zawierającą wiersze na kolumny. Można wymyślać i interować po tablicy, zapisując wartość z poszczególnego wiersza do kolumny. Tylko po co. Pisać kod należy z głową.
Pythonowski, uwielbiany zip
W py
możemy użyć uwielbianą przeze mnie funkcję zip
.
Jej zastosowanie jest mniej więcej takie:
1
2
3
4
5
row = [[1,2],[3,4]]
print(*zip(*row))
# OUTPUT:
# (1, 3)(2, 4)
O to właśnie nam chodziło
array_map()
dla php
i ...
operator
W php
jest to trochę trudniejsze. Musimy skorzystać z array_map()
. Czyli zastosowanie określonej funkcji do każdego z elementów tablicy, np.:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
<?php
function square($n){
return ($n * $n);
}
$a = [[1, 2], [3 4, 5]];
$b = array_map('square', $a);
print_r($b);
/*
OUTPUT:
Array
(
[0] => 1
[1] => 4
[2] => 9
[3] => 16
[4] => 25
)
*/
?>
Oraz z tak zwanego splat operatora lub w js
nazywanego spred operator.
Służy on do “pakowania” i “wypakowywania” wartości np. z tablicy. O tym operatorze mógłby powstać oddzielny wpis.
Na chwilę obecną zatrzymajmy się na tym, że z niego będziemy korzystać .
Jeszcze jedna uwaga, funkcja array_map()
jako pierwszy argument przyjmuje funkcję lub anonimową funkcję, jaka ma zostać użyta na każdym z elementów tablicy. W naszym przypadku, określimy ją na null
, czyli nic nie musi wykonywać. Dzięki temu możemy skorzystać z array_map()
bez błędu i otrzymamy z wierszy kolumny . Kod jest następujący:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
<?php
$a = [[1, 2], [3, 4, 5], [5, 6, 7]];
$b = array_map(null, ...$a);
print_r($b);
/*
OUTPUT:
Array
(
[0] => Array
(
[0] => 1
[1] => 3
[2] => 5
)
[1] => Array
(
[0] => 2
[1] => 4
[2] => 6
)
[2] => Array
(
[0] =>
[1] => 5
[2] => 7
)
)
*/
?>
Otrzymując z wierszy kolumny, jesteśmy w stanie sprawdzić, czy cyfry w tak przekształconej tablicy się powtarzają poprzez już wspomnianego set-a dla py
lub array_unique()
dla php
.
Kolejny krok walidacji wykonany .
Otrzymanie subgrid’a 3 x 3
Python 3 x 3
Teraz musimy uzyskać z naszej tablicy subdiagram o wymiarze 3 x 3.
Wpierw napiszę o pythonie
. Wykorzystam tutaj interację po liście z zastosowaniem tzw. floor division = //
, czyli dzielenia i zaokrąglenia wyniku w dół, oraz operacji modulo %
. Opiszę całość na przykładzie, gdyż tak jest prościej.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
w =
[
[4, 3, 5, 2, 6, 9, 7, 8, 1],
[6, 8, 2, 5, 7, 1, 4, 9, 3],
[8, 9, 7, 1, 3, 4, 5, 6, 2]
]
for i in range(len(w)):
print([w[3*(i//3)+(j//3)][3*(i%3)+(j%3)] for j in range(9)])
# OUTPUT:
[4, 3, 5, 6, 8, 2, 8, 9, 7]
[2, 6, 9, 5, 7, 1, 1, 3, 4]
[7, 8, 1, 4, 9, 3, 5, 6, 2]
[4, 3, 5, 6, 8, 2, 8, 9, 7]
- ten wiersz składa się z:
-
pierwszych trzech wartości wiersza pierwszego listy
w
, - kolejnych 3 pierwszych wartości wiersza drugiego listy
w
oraz - kolejnych 3 pierwszych wartości ostatniego wiersza listy
w
.
Ergo, otrzymaliśmy w jednym wierszu subgrida o wymiarze 3 x 3, który możemy sprawdzić. Wiersz drugi naszego wyniku działania, jest przesunięciem o 3 pola wartości od początku wiersza i powtórzeniem operacji.
Najlepiej rozumiem, kiedy mam zobrazowane dane zagadnienie. Wyświetlmy zatem jak powyższe równanie zachowuje się w pętli:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
w = [
[4, 3, 5, 2, 6, 9, 7, 8, 1],
[6, 8, 2, 5, 7, 1, 4, 9, 3],
[8, 9, 7, 1, 3, 4, 5, 6, 2]
]
for i in range(len(w)):
print(*((3*(i//3)+(j//3),3*(i%3)+(j%3)) for j in range(9)))
# OUTPUT:
# (0, 0) (0, 1) (0, 2) (1, 0) (1, 1) (1, 2) (2, 0) (2, 1) (2, 2)
# (0, 3) (0, 4) (0, 5) (1, 3) (1, 4) (1, 5) (2, 3) (2, 4) (2, 5)
# (0, 6) (0, 7) (0, 8) (1, 6) (1, 7) (1, 8) (2, 6) (2, 7) (2, 8)
# Dane jakie otrzymamy:
# 4 3 5 6 8 2 8 9 7
# 2 6 9 5 7 1 1 3 4
# 7 8 1 4 9 3 5 6 2
Mamy już w wierszu subgrida o wielkości 3 x 3. możemy poprzez set-a
przyrównać go do 9 i walidacja zakończona .
PHP 3 x 3
Przejdźmy zatem do php
. W tym podejściu ograniczyłam się do wychwycenia z input’a odpowiednich fragmentów:
1
2
3
4
5
6
7
8
for ($i = 0; $i < 9; $i++){
foreach ($inputs as $j => $cell) {
$subgrids[
floor($i / 3) * 3 + floor($j / 3)
][] = $cell;
}
}
Podejście to bazuje na tej samej logice co py
, jednak nie mamy tutaj dostępnych skrótów dla floor division więc musimy używać funkcji floor
.
Pełny kod dla py
znajduje się na moim githubie poświęconemu codingame. Tak samo zresztą jako kod php
.