Lekce 5 - Tvorba sudoku v Xamarin - Kontrolní mechanismy Nové
V minulé lekci, Tvorba sudoku v Xamarin - Nahrání aplikace do mobilu, jsme nahráli aplikaci na iPhone a Android a nastavili mobil pro vývoj, abychom mohli aplikaci debugovat.
V dnešním Xamarin tutoriálu implementujeme kontrolní mechanismy pro zadání a řešení Sudoku. Základem bude kontrola dvou buněk, kterou zavoláme při kontrole stejných čísel ve sloupcích, řádcích, mřížce a nakonec v celém Sudoku.
Budeme rozšiřovat naši aplikaci z lekce Nahrání
aplikace do mobilu. Všechen kód budeme psát do souboru
MainPage.xaml.cs
.
Třída EntrySudoku
Jelikož máme 81 Entry
, které umí reagovat na uživatelský
vstup, ale nevědí, kde v mřížce se nacházejí, musíme určit
souřadnice. Tyto souřadnice budeme definovat při vytvoření
nového objektu třídy EntrySudoku
, kterou si teď vložíme na
začátek souboru MainPage.xaml.cs
:
public class EntrySudoku : Entry { int row; int column; public int getRow() => row; public int getColumn() => column; public EntrySudoku(int r, int c) : base() { row = r; column = c; } }
Třídu využijeme pro testování implementovaných funkcionalit z uživatelského rozhraní.
V proměnných row
a column
budeme ukládat
umístění mřížky. Umístění pak definujeme v
konstruktoru.
Změny stávajícího kódu
Na základě vytvoření třídy EntrySudoku
změníme:
- všechny výskyty typu
Entry
za typEntrySudoku
, - vytvoření nového objektu typu
Entry
za nový objekt typuEntrySudoku
.
Struktura Bunka
Pod třídu EntrySudoku
si vložíme novou strukturu
Bunka
, do které umístíme proměnné hodnota
a
konstanta
:
public struct Bunka { public int hodnota; public bool konstanta; };
Proměnná hodnota
bude moci nabývat hodnot:
0
pro neutrální hodnotu,1
-9
pro povolené hodnoty,- ostatní pro nepovolené hodnoty.
Pomocí proměnné konstanta
budeme zjišťovat, zda daná
hodnota nabývá hodnoty true
a jedná se tedy o zadání
sudoku, nebo hodnoty false
a jedná se o buňku kterou
musí vyplnit řešitel úlohy.
Následující metody si napíšeme například na konec souboru
MainPage.xaml.cs
.
Kontrola buněk
Jako první si napíšeme metodu pro kontrolu, zda hodnoty obou přijatých buněk jsou stejné:
static public bool JsouStejne(Bunka bunka1, Bunka bunka2) { if ((bunka1.hodnota < 1) || (bunka1.hodnota > 9)) return false; if ((bunka2.hodnota < 1) || (bunka2.hodnota > 9)) return false; return bunka1.hodnota == bunka2.hodnota; }
V metodě porovnáváme buňky bunka1
a bunka2
,
které jsme přijali v parametrech metody. Pokud se hodnoty buněk v intervalu
1
až 9
shodují, vrátíme hodnotu true
.
Pokud se hodnoty buněk v tomto intervalu neshodují, nebo máme v buňce
neutrální hodnotu 0
, vrátíme hodnotu false
.
Kontrola sloupce
Nyní v nové metodě zkontrolujeme, zda ve sloupci se vyskytují stejné hodnoty:
static public bool ZkontrolujSloupec(int row) { for (int column = 0; column < 8; column++) { for (int i = column + 1; i < 9; i++) { if (JsouStejne(sudoku_grid[row, column], sudoku_grid[row, i])) return false; } } return true; }
V prvním cyklu načítáme číslo. V druhém cyklu načteme další
číslo. Načtená dvě čísla porovnáme pomocí metody
JsouStejne()
a vrátíme hodnotu false
nebo
true
. Takto následně porovnáme číslo z prvního cyklu se
zbývajícími čísly z druhého cyklu. Nakonec načteme další číslo v
prvním cyklu a pokračujeme v porovnávání.
Kontrola řádku
Obdobně v další metodě zkontrolujeme, zda se v řádku vyskytují stejné hodnoty:
static public bool ZkontrolujRadek(int column) { for (int row = 0; row < 8; row++) { for (int i = row + 1; i < 9; i++) { if (JsouStejne(sudoku_grid[row, column], sudoku_grid[i, column])) return false; } } return true; }
Stejně tak zkontrolujeme čísla v řádku. Tedy opět
načteme číslo v prvním cyklu. V druhém cyklu načteme další číslo.
Načtená dvě čísla porovnáme pomocí metody JsouStejne()
a
vrátíme hodnotu false
nebo true
. Takto následně
porovnáme číslo z prvního cyklu se zbývajícími čísly z druhého cyklu.
Nakonec načteme další číslo v prvním cyklu a pokračujeme v
porovnávání.
Kontrola mřížky
Nyní implementujeme metodu pro kontrolu čísel v mřížce 3x3:
static public bool ZkontrolujMrizku(int row_in, int column_in) { int zaciatok_mriezky_row = 0; int zaciatok_mriezky_column = 0; int row, column, i, j; Bunka[] pole = new Bunka[9]; zaciatok_mriezky_row = row_in / 3 * 3; // bude to 0 nebo 3 nebo 6 zaciatok_mriezky_column = column_in / 3 * 3; // bude to 0 nebo 3 nebo 6 i = 0; for (row = zaciatok_mriezky_row; row < zaciatok_mriezky_row + 3; row++) { for (column = zaciatok_mriezky_column; column < zaciatok_mriezky_column + 3; column++) { pole[i++] = sudoku_grid[row, column]; } } for (i = 0; i < 8; i++) { for (j = i + 1; j < 9; j++) { if (JsouStejne(pole[i], pole[j])) return false; } } return true; }
V metodě jsme převedli mřížku na řádek a použili stejný algoritmus.
U výpočtu počátečního řádku a sloupce mřížky používáme
celočíselnou aritmetiku. Takže například u kontroly
pátého řádku, počáteční řádek mřížky je 5/3=1 a
1*3=3, tedy třetí řádek. Pokud je vše v
pořádku, vrátíme hodnotu true
. V případě dvou stejných
čísel v mřížce vrátíme hodnotu false
.
Kontrola Sudoku
Poslední metodou zkontrolujeme celé Sudoku:
static public bool ZkontrolujSudoku() { int riadok, stlpec; // kontrola řádků for (riadok = 0; riadok < 9; riadok++) { if (!ZkontrolujRadek(riadok)) return false; } // kontrola sloupců for (stlpec = 0; stlpec < 9; stlpec++) { if (!ZkontrolujSloupec(stlpec)) return false; } // kontrola mřížky for (riadok = 0; riadok < 9; riadok += 3) { for (stlpec = 0; stlpec < 9; stlpec += 3) { if (!ZkontrolujMrizku(riadok, stlpec)) return false; } } return true; }
Zkontrolujeme postupně všechny řádky, sloupce a mřížku. Pokud
nalezneme chybu, z metody vyskočíme a vrátíme hodnotu false
.
Pokud dojdeme až na konec bez chyby, vrátíme hodnotu true
.
Měl jsi s čímkoli problém? Zdrojový kód vzorové aplikace je ke stažení každých pár lekcí. Zatím pokračuj dál, a pak si svou aplikaci porovnej se vzorem a snadno oprav.