Zadání Sudoku
Zadání Sudoku

Sudoku je populární logická hra, jejímž cílem je na plochu 9x9 polí doplnit chybějící číslice 1-9 takovým způsobem, aby se žádná neopakovala vícekrát v žádném řádku, sloupci ani čtverci (plocha se skládá z devíti čtverců velikosti 3x3 pole).

Autorem hlavolamu je Howard Garns, který jej publikoval v roce 1979 (pod názvem Number place). Hra se stala populární nejprve v Japonsku (vydávána od roku 1984) pod názvem Suuji wa dokushin ni kagiru a v roce 2005 se stala známou na celém světě.

Jak řešit Sudoku?

Sudoku se obvykle luští za pomoci tzv. kandidátů, což jsou všechna čísla, která mohou být v daném poli umístěna (na začátku všechna čísla 1-9). Kandidáti jsou poté postupně eliminováni za pomoci více či méně složitých myšlenkových postupů a konstrukcí. V okamžiku, kdy zbyde pouze jeden kandidát, tak je řešením pro dané pole.

Základní pravidla

Pro prvotní eliminaci kandidátů poslouží základní pravidla Sudoku. V žádné řádce, sloupci ani skupině nesmí být žádné číslo vícekrát. Ačkoliv je tato strategie velmi jednoduchá, tak postačuje pro většinu jednoduchých Sudoku.

(Hidden) Singles

Hidden single
Hidden single

Singles jsou ta políčka, pro která existuje pouze jeden kandidát, který je jejich řešením. Hidden single je takový kandidát, který je jedinečný v rámci dané řádky, sloupce nebo skupiny, ale není v daném políčku osamocený. Přesto je díky základním pravidlům řešením tohoto políčka.

Naked pair
Naked pair

Naked pair

Pokud dvě políčka v rámci skupiny obsahují pouze totožnou dvojici kandidátů, pak žádné další pole v této skupině nesmí dané kandidáty obsahovat (pokud by tomu tak nebylo, tj. některý kandidát by byl řešením jiného pole, tak by nešlo původní políčka vyplnit). Tuto strategii lze analogicky použít pro trojice kandidátů a tři políčka, čtveřice a čtyři políčka a tak dále.

Pointing pair
Pointing pair

Pointing pairs, Pointing tripples (intersection removal)

Za předpokladu, že se některý kandidát vyskytuje vícekrát v rámci jednoho řádku nebo sloupce skupiny (ale ne v rámci více sloupců/řádků), tak jej můžeme odstranit z průsečíku tohoto řádku/sloupce v ostatních skupinách, kterými tento řádek/sloupec prochází.

Box/Line reduction (intersection removal)

Pokud předchozí postup obrátíme naruby, tak dostaname Box/Line reduction strategii. Mějme řádek nebo sloupec, který má určité kandidáty pouze v jedné skupině, pak můžeme tyto kandidáty vyškrtnout ze všech ostatních polí dané skupiny.

Box/Line reduction
Box/Line reduction

Strojové řešení a generování Sudoku

Při generování nového zadání je zapotřebí řešit Sudoku ve dvou rovinách. Tou první je ověření jednoznačnosti zadání, které provedeme pomocí backtrackingu. Backtracking je metoda organizovaných pokusů a omylů, při které zkusíme na dané pole vložit nějakou hodnotu a zkontrolujeme, jestli toto částečné řešení neodporuje pravidlům. Pokud je vše v pořádku, zkusíme to znovu u dalšího pole. V případě selhání se vrátíme na místo posledního omylu a opravíme jej novým pokusem. Tímto způsobem zaručeně najdeme všechna řešení, která zadání umožňuje. Nevýhodou je velká výpočetní náročnost tohoto postupu (ručně by se dala tato metoda aplikovat jen na velmi omezené podproblémy).

Druhou rovinou je ověření praktické řešitelnosti daného Sudoku. To provedeme pouze za pomoci lidmi použitelných technik, z nichž některé jsme uvedli výše. Tímto způsobem také můžeme snadno stanovit obtížnost řešení na základě počtu potřebných tahů nebo obtížnosti nutných strategií.

Generování zadání

V předchozích odstavcích jsme předpokládali existenci zadání, ale neuvedli jsme si, jakým způsobem jej lze získat. V praxi se používají především dva postupy. První z nich vygeneruje náhodné konzistentní úplné řešení Sudoku a postupně z něj odebírá vyplněná řešení jednotlivých polí. Takto postupuje tak dlouho, dokud má Sudoku jednoznačné řešení, případně dokud obtížnost řešení nepřesáhne nějaký práh.

Druhý přístup je zcela opačný. Algoritmus nejprve vygeneruje zadání, v němž je konzistentně vyplněno 17 polí (nejmenší známý počet polí, pro nějž bylo nalezeno zadání, které má unikátní řešení). Poté procedura postupně vyplňuje náhodná pole a kontroluje konzistenci zadání. V okamžiku, kdy má dané zadání pouze jedno řešení, jehož obtížnost nepřesáhne daný práh, procedura terminuje.


Kód

001./**
002. * Resic Sudoku pomoci backtrackingu. Tato metoda nezjisti, jestli je dane
003. * sudoku resitelne clovekem, ale zda-li ma dane zadani vubec reseni, pripadne
004. * kolik takovychto reseni umoznuje (zjisti a vypise vsechna reseni).
005. * @author Pavel Micka
006. */
007.public class SudokuSolver {
008.    /**
009.     * Velikost ulohy == klasicke Sudoku 9*9, 3x vnitrni ctverec 3*3, kazde cislo
010.     * (1-9) pouze jednou v radku, sloupci i ctverci
011.     */
012.    public static final int SUDOKU_SIZE = 9;
013.    /**
014.     * Velikost vnitrnich ctvercu (3*3 dle beznych pravidel)
015.     */
016.    public static final int SQUARE_SIZE = 3;
017.    /**
018.     * Prazdne pole
019.     */
020.    public static final int EMPTY = 0;
021. 
022.    /**
023.     * Vyresi zadane Sudoku pomoci backtrackingu (najde vsechna reseni)
024.     * @param array pole zadani
025.     */
026.    public static void solveSudoku(int[][] array) {
027.        if(array.length != SUDOKU_SIZE) throw new IllegalArgumentException("Pole ma mit velikost 9x9");
028. 
029.        boolean[][] fixed = new boolean[SUDOKU_SIZE][SUDOKU_SIZE];
030.        for (int i = 0; i < array.length; i++) {
031.            if (array[i].length != SUDOKU_SIZE) throw new IllegalArgumentException("Pole ma mit velikost 9x9");
032.            for (int j = 0; j < array.length; j++) {
033.                if (array[i][j] != 0) fixed[i][j] = true;
034. 
035.            }
036.        }
037. 
038.        //prejdeme na prvni nepredvyplnenou souradnici
039.        int x = -1;
040.        int y = 0;
041.        do {
042.            x = x + 1; //posun o souradnici dal
043.            boolean overflow = x >= SUDOKU_SIZE; //pretekl radek?
044.            if (overflow) {
045.                x = 0;
046.                y += 1;
047.            }
048.        } while(fixed[y][x]); //dokud je pole zablokovane (soucasti zadani)
049. 
050.        for (int i = 1; i <= SUDOKU_SIZE; i++) {
051.            solve(array, fixed, x, y, i);
052.        }
053.    }
054.    /**
055.     * Resi Sudoku
056.     * @param array pole reseni
057.     * @param fixed pole, ve kterem true znamena, ze jde o hodnotu ze zadani,
058.     * @false, ze jde o hodnotu resitele
059.     * @param x souradnice x, na kterou se bude pridavat dalsi hodnota
060.     * @param y souradnice y, na kterou se bude pridavat dalsi hodnota
061.     * @param value hodnota
062.     */
063.    private static void solve(int[][] array, boolean[][] fixed, int x, int y, int value) {
064.        if (!checkConsistency(array, x, y, value)) return; //reseni neni konzistentni
065.        array[y][x] = value; //set
066.        do {
067.            x = x + 1; //posun o souradnici dal
068.            boolean overflow = x >= SUDOKU_SIZE; //pretekl radek?
069.            if (overflow) {
070.                x = 0;
071.                y += 1;
072.                if (y == SUDOKU_SIZE) { //pretekl sloupec...konec reseni
073.                    printArray(array);
074.                    return;
075.                }
076.            }
077.        } while(fixed[y][x]);//dokud je pole zablokovane (soucasti zadani)
078.        for (int i = 1; i <= SUDOKU_SIZE; i++) { //backtrack
079.            solve(array, fixed, x, y, i);
080.        }
081.        array[y][x] = EMPTY; //reset policka (aby neprekazelo pri backtracku)
082.    }
083.    /**
084.     * Zkontroluje, jestli je reseni stale korektni
085.     * @param array pole reseni
086.     * @param x x souradnice, na kterou je pridavana hodnota
087.     * @param y y souradnice, na kterou je pridavana hodnota
088.     * @param value hodnota
089.     * @return true - pokud je reseni konzistentni, false - pokud reseni neni konzistentni
090.     */
091.    private static boolean checkConsistency(int[][] array, int x, int y, int value) {
092.        //Sloupec
093.        for (int i = 0; i < array.length; i++) {
094.            if (i != y && array[i][x] == value) return false;
095.        }
096.        //radek
097.        for (int i = 0; i < array[y].length; i++) {
098.            if (i != x && array[y][i] == value) return false;
099.        }
100.        //ctverec
101.        int vertical = y/SQUARE_SIZE; //o kolikaty vertikalni ctverec se jedna
102.        int horizontal = x/SQUARE_SIZE; //o kolikaty horizontalni ctverec se jedna
103. 
104.        for (int i = vertical*SQUARE_SIZE; i < vertical*SQUARE_SIZE + SQUARE_SIZE; i++) {
105.            for (int j = horizontal*SQUARE_SIZE; j < horizontal*SQUARE_SIZE + SQUARE_SIZE; j++) {
106.                if (array[i][j] == value) return false;
107.            }
108.        }
109.        return true;
110.    }
111.    /**
112.     * Vypise pole Sudoku
113.     * @param array pole sudoku
114.     */
115.    private static void printArray(int[][] array) {
116.        for (int i = 0; i < array.length; i++){
117.            for (int j = 0; j < array[i].length; j++) {
118.                System.out.print(array[i][j] + "|");
119.            }
120.            System.out.println("");
121.        }
122.        System.out.println("");
123.    }
124.}
001./**
002. * Resicka sudoku vyuzivajici "lidske" strategie
003. * @author Pavel Micka
004. */
005.public class HumanizedSudokuSolver {
006.    private SudokuField[][] sudoku;
007.    private SudokuStrategy[] strategies;
008. 
009.    /**
010.     * Zkonstruuje resicku pro zadane sudoku
011.     * @param setting zadani sudoku, 0 znaci prazdne pole
012.     * @param strategies pole strategii, ktere maji byt pouzity
013.     */
014.    HumanizedSudokuSolver(int[][] setting, SudokuStrategy... strategies) {
015.        this.strategies = strategies;
016.        sudoku = new SudokuField[setting.length][setting.length];
017.        for (int i = 0; i < setting.length; i++) {
018.            for (int j = 0; j < setting[i].length; j++) {
019.                if (setting[i][j] == 0) {
020.                    sudoku[i][j] = new SudokuField();
021.                } else {
022.                    sudoku[i][j] = new SudokuField(setting[i][j]);
023.                }
024.            }
025.        }
026.    }
027.    /**
028.     * Vrati reseni sudoku
029.     * @return
030.     */
031.    public int[][] solve() {
032.        boolean succ;
033.        do{
034.            succ = false;
035.            for (SudokuStrategy s : strategies) {
036.                succ = s.solve(sudoku);
037.                if (succ) {
038.                    break;
039.                }
040.            }
041.        } while(succ);
042. 
043.        int[][] solution = new int[sudoku.length][sudoku.length];
044.        for (int i = 0; i < sudoku.length; i++) {
045.            for (int j = 0; j < sudoku.length; j++) {
046.                solution[i][j] = sudoku[i][j].getSolution();
047.            }
048.        }
049. 
050.        return solution;
051. 
052. 
053.    }
054. 
055. 
056. 
057.    /**
058.     * Testovaci main metoda
059.     * Program vyresi, co umi, coz jsou s temito strategiemi cca. az pokrocila
060.     * Sudoku a vypise vysledek
061.     * @param args the command line arguments
062.     */
063.    public static void main(String[] args) {
064.        int[][] setting = { //MF DNES 23.8.2010, priloha leto
065.            {0, 0, 4, 0, 3, 6, 9, 2, 7},
066.            {1, 0, 0, 0, 0, 5, 0, 0, 0},
067.            {0, 0, 0, 2, 0, 0, 0, 0, 4},
068.            {0, 0, 5, 0, 0, 0, 0, 6, 0},
069.            {6, 4, 0, 0, 0, 0, 0, 8, 5},
070.            {0, 7, 0, 0, 0, 0, 2, 0, 0},
071.            {5, 0, 0, 0, 0, 1, 0, 0, 0},
072.            {0, 0, 0, 7, 0, 0, 0, 0, 2},
073.            {4, 3, 7, 9, 2, 0, 5, 0, 0}
074.        };
075.        SudokuStrategy[] s = {new OneInARowStrategy(), new OneInAColumnStrategy(), new OneInAGroupStrategy()};
076.        HumanizedSudokuSolver solver = new HumanizedSudokuSolver(setting, s);
077.        int[][] solution = solver.solve();
078.        for (int i = 0; i < solution.length; i++) {
079.            for (int j = 0; j < solution.length; j++) {
080.                System.out.print(solution[i][j] + " ");
081.            }
082.            System.out.println("");
083.        }
084.    }
085.}
086. 
087./**
088. * Specifikuje metodu, kterou by mely mit vsechny strategie pro reseni Sudoku
089. * @author Pavel Micka
090. */
091.interface SudokuStrategy {
092. 
093.    /**
094.     * Provede jeden krok reseni Sudoku
095.     * @param sudoku pole obsahujici sudoku, 0 oznacuje prazdna mista
096.     * @return true pokud se povedlo krok provest, false v opacnem pripade
097.     */
098.    public boolean solve(SudokuField[][] sudoku);
099.}
100. 
101./**
102. * Strategie, ktera rika, ze v jednom radku smi byt dane cislo pouze jednou
103. * @author Pavel Micka
104. */
105.class OneInARowStrategy implements SudokuStrategy {
106. 
107.    public boolean solve(SudokuField[][] sudoku) {
108.        for (int i = 0; i < sudoku.length; i++) {
109.            for (int j = 0; j < sudoku[i].length; j++) {
110.                int solution = sudoku[i][j].getSolution();
111.                if (solution != 0) { //pokud pole neni vyreseno
112.                    for (int k = 0; k < sudoku[i].length; k++) { //overme radku na kandidaty
113.                        if (sudoku[i][k].getSolution() == 0) { //pokud dane pole neni vyreseno
114.                            if (sudoku[i][k].hasCandidate(solution)) { //a pokud ma kandidata
115.                                sudoku[i][k].removeCandidate(solution); //tak kandidata odstranime
116.                                System.out.println("OneInARow: Odstranuji kandidata " + solution
117.                                        + " na souradnicich x: " + k + " y: " + i);
118.                                return true; //a vratime uspech
119.                            }
120.                        }
121.                    }
122.                }
123.            }
124.        }
125.        return false;
126.    }
127.}
128. 
129./**
130. * Strategie, ktera rika, ze v jednom sloupci smi byt dane cislo pouze jednou
131. * @author Pavel Micka
132. */
133.class OneInAColumnStrategy implements SudokuStrategy {
134. 
135.    public boolean solve(SudokuField[][] sudoku) {
136.        for (int i = 0; i < sudoku.length; i++) {
137.            for (int j = 0; j < sudoku[i].length; j++) {
138.                int solution = sudoku[j][i].getSolution();
139.                if (solution != 0) { //pokud pole neni vyreseno
140.                    for (int k = 0; k < sudoku.length; k++) { //overme sloupec na kandidaty
141.                        if (sudoku[k][i].getSolution() == 0) { //pokud dane pole neni vyreseno
142.                            if (sudoku[k][i].hasCandidate(solution)) { //a pokud ma kandidata
143.                                sudoku[k][i].removeCandidate(solution); //tak kandidata odstranime
144.                                System.out.println("OneInAColumn: Odstranuji kandidata " + solution
145.                                        + " na souradnicich x: " + i + " y: " + k);
146.                                return true; //a vratime uspech
147.                            }
148.                        }
149.                    }
150.                }
151.            }
152.        }
153.        return false;
154.    }
155.}
156. 
157./**
158. * Strategie, ktera rika, ze v jedne skupine muze byt dane cislo pouze jednou
159. * @author Pavel Micka
160. */
161.class OneInAGroupStrategy implements SudokuStrategy {
162. 
163.    public boolean solve(SudokuField[][] sudoku) {
164.        int groupCount = (int) Math.sqrt(sudoku.length); //pocitame se ctvercovym sudoku, pocet skupin na radku a sloupec
165.        for (int i = 0; i < sudoku.length; i++) {
166.            for (int j = 0; j < sudoku[i].length; j++) {
167.                int solution = sudoku[i][j].getSolution();
168.                if (solution != 0) { //pokud pole neni vyreseno
169.                    for (int k = i - (i % groupCount); k < i - (i % groupCount) + groupCount; k++) {//radky
170.                        for (int l = j - (j % groupCount); l < j - (j % groupCount) + groupCount; l++) {//sloupce
171.                            if (sudoku[k][l].getSolution() == 0){ //pokud pole jeste neni vyreseno
172.                                if (sudoku[k][l].hasCandidate(solution)){ //a ma odpovidajiciho kandidata
173.                                    sudoku[k][l].removeCandidate(solution);
174.                                System.out.println("OneInAGroup: Odstranuji kandidata " + solution
175.                                        + " na souradnicich x: " + l + " y: " + k);
176.                                    return true;
177.                                }
178.                            }
179.                        }
180.                    }
181.                }
182.            }
183.        }
184.        return false;
185.    }
186.}
187. 
188./**
189. * Trida policka sudoku
190. * @author Pavel Micka
191. */
192.class SudokuField {
193. 
194.    /**
195.     * Mnozina kandidatu
196.     */
197.    private Set<Integer> candidates;
198. 
199.    /**
200.     * Vytvori policko, kandidaty jsou cisla 1-9
201.     */
202.    public SudokuField() {
203.        this.candidates = new HashSet<Integer>();
204.        for (int i = 1; i <= 9; i++) {
205.            candidates.add(i);
206.        }
207.    }
208. 
209.    /**
210.     * Vytvori policko s jedinym kandidatem (resenim)
211.     * @param nr reseni
212.     */
213.    public SudokuField(int nr) {
214.        this.candidates = new HashSet<Integer>();
215.        candidates.add(nr);
216.    }
217. 
218.    /**
219.     * Zjisti, jestli je dane cislo kandidatem tohoto pole
220.     * @param nr cislo
221.     * @return true pokud je cislo kandidatem, false jinak
222.     */
223.    public boolean hasCandidate(int nr) {
224.        return candidates.contains(nr);
225.    }
226.    /**
227.     * Odstrani kandidata
228.     * @param nr kandidat
229.     */
230.    public void removeCandidate(int nr) {
231.        boolean succ = candidates.remove(nr);
232.        assert succ;
233.    }
234. 
235.    /**
236.     * Vrati cislo, ktere je resenim tohoto policka
237.     * @return cislo, ktere je resenim, 0 pokud jeste pole nebylo vyreseno
238.     */
239.    public int getSolution() {
240.        if (candidates.size() != 1) {
241.            return 0;
242.        } else {
243.            return (Integer) (candidates.toArray()[0]);
244.        }
245.    }
246.}
001./**
002. * Resic Sudoku pomoci backtrackingu. Tato metoda nezjisti, jestli je dane
003. * sudoku resitelne clovekem, ale zda-li ma dane zadani vubec reseni, pripadne
004. * kolik takovychto reseni umoznuje (zjisti a vypise vsechna reseni).
005. * @author Pavel Micka
006. */
007.class SudokuSolver {
008.public:
009.    /**
010.     * Velikost ulohy == klasicke sudoku 9*9, 3x vnitrni ctverec 3*3, kazde cislo
011.     * (1-9) pouze jednou v radku, sloupci i ctverci
012.     */
013.    static const int SUDOKU_SIZE = 9;
014.    /**
015.     * Velikost vnitrnich ctvercu (3*3 dle beznych pravidel)
016.     */
017.    static const int SQUARE_SIZE = 3;
018.    /**
019.     * Prazdne pole
020.     */
021.    static const int EMPTY = 0;
022. 
023.    /**
024.     * Vyresi zadane Sudoku pomoci backtrackingu (najde vsechna reseni)
025.     * @param array pole zadani
026.     */
027.    static void solveSudoku(int ** array) {
028.        bool ** fixed = new bool *[SUDOKU_SIZE];
029.        for (int i = 0; i < SUDOKU_SIZE; i++) {
030.            fixed[i] = new bool[SUDOKU_SIZE];
031.        }
032.         
033.        for (int i = 0; i < SUDOKU_SIZE; i++) {
034.            for (int j = 0; j < SUDOKU_SIZE; j++) {
035.                if (array[i][j] != 0) fixed[i][j] = true;
036.                else fixed[i][j] = false;
037.            }
038.        }
039. 
040.        //prejdeme na prvni nepredvyplnenou souradnici
041.        int x = -1;
042.        int y = 0;
043.        do {
044.            x = x + 1; //posun o souradnici dal
045.            bool overflow = x >= SUDOKU_SIZE; //pretekl radek?
046.            if (overflow) {
047.                x = 0;
048.                y += 1;
049.            }
050.        } while (fixed[y][x]);//dokud je pole zablokovane (soucasti zadani)
051. 
052.        for (int i = 1; i <= SUDOKU_SIZE; i++) {
053.            solve(array, fixed, x, y, i);
054.        }
055. 
056.        //dealokace
057.        for (int i = 0; i < SUDOKU_SIZE; i++) delete fixed[i];
058.        delete[] fixed;
059. 
060.    }
061.private:
062.    /**
063.     * Resi Sudoku
064.     * @param array pole reseni
065.     * @param fixed pole, ve kterem true znamena, ze jde o hodnotu ze zadani,
066.     * @false, ze jde o hodnotu resitele
067.     * @param x souradnice x, na kterou se bude pridavat dalsi hodnota
068.     * @param y souradnice y, na kterou se bude pridavat dalsi hodnota
069.     * @param value hodnota
070.     */
071.    static void solve(int ** array, bool ** fixed, int x, int y, int value) {
072.        if (!checkConsistency(array, x, y, value)) return; //reseni neni konzistentni
073.        array[y][x] = value; //set
074.        do {
075.            x = x + 1; //posun o souradnici dal
076.            bool overflow = x >= SUDOKU_SIZE; //pretekl radek?
077.            if (overflow) {
078.                x = 0;
079.                y += 1;
080.                if (y == SUDOKU_SIZE) { //pretekl sloupec...konec reseni
081.                    printArray(array);
082.                    return;
083.                }
084.            }
085.        } while(fixed[y][x]);//dokud je pole zablokovane (soucasti zadani)
086.        for (int i = 1; i <= SUDOKU_SIZE; i++) { //backtrack
087.            solve(array, fixed, x, y, i);
088.        }
089.        array[y][x] = EMPTY; //reset policka (aby neprekazelo pri backtracku)
090.    }
091.    /**
092.     * Zkontroluje, jestli je reseni stale korektni
093.     * @param array pole reseni
094.     * @param x x souradnice, na kterou je pridavana hodnota
095.     * @param y y souradnice, na kterou je pridavana hodnota
096.     * @param value hodnota
097.     * @return true - pokud je reseni konzistentni, false - pokud reseni neni konzistentni
098.     */
099.    static bool checkConsistency(int ** array, int x, int y, int value) {
100.        //Sloupec
101.        for (int i = 0; i < SUDOKU_SIZE; i++) {
102.            if (i != y && array[i][x] == value) return false;
103.        }
104.        //radek
105.        for (int i = 0; i < SUDOKU_SIZE; i++) {
106.            if (i != x && array[y][i] == value) return false;
107.        }
108.        //ctverec
109.        int vertical = y/SQUARE_SIZE; //o kolikaty vertikalni ctverec se jedna
110.        int horizontal = x/SQUARE_SIZE; //o kolikaty horizontalni ctverec se jedna
111. 
112.        for (int i = vertical*SQUARE_SIZE; i < vertical*SQUARE_SIZE + 3; i++) {
113.            for (int j = horizontal*SQUARE_SIZE; j < horizontal*SQUARE_SIZE + 3; j++) {
114.                if (array[i][j] == value) return false;
115.            }
116.        }
117.        return true;
118.    }
119.    /**
120.     * Vypise pole Sudoku
121.     * @param array pole sudoku
122.     */
123.    static void printArray(int ** array) {
124.        for (int i = 0; i < SUDOKU_SIZE; i++) {
125.            for (int j = 0; j < SUDOKU_SIZE; j++) {
126.                cout << array[i][j] << "|";
127.            }
128.            cout << "\\n";
129.        }
130.        cout << "\\n";
131.    }
132.};

Litaratura

  • STUART, Andrew. Sudokuwiki.org/ [online]. 2008 [cit. 2010-08-24]. Dostupné z WWW: <http://www.sudokuwiki.org/>.
  • JOHNSON, Angus. Angus johnson's homepage [online]. 2005 [cit. 2010-08-24]. SOLVING SUDOKU. Dostupné z WWW: <http://www.angusj.com/sudoku/hints.php>.

SEO od společnosti Digital Pylon


Online casino s algoritmem

České casino online online slot-vegas.cz

Hrajte nejlepší hry jako je GoodGame Empire.





Zajímavé články: Jak najít práci snů? Zvolte kariéru v IT!, Češi mají rádi hrací automaty online, Jak funguje algoritmické obchodování Casino, Online výuka Algoritmus a online marketing mají svá pravidla, Automaty, Matematický vliv, Ratings, Jak fungují algoritmy hazardních her online: více znalostí, více peněz, SYPWAI - nástroj pro vědecký vývoj, Vynikají na globálním trhu: Nejlepší vývojáři softwaru pro online výherní automaty, Jak si vybrat nejlepší české online casino, Proč byste měli hrát online casino VPN revoluce, Kde najdeme algoritmy v každodenním životě?, Čeká vás pracovní pohovor mimo město? Podívejte se, jak dokonale zvládnout včasný příchod, 5 úžasných technologií ze světa hazardních her, Mirror and access to Mostbet, Svou kancelář můžete mít stále po ruce, Jaké výhody má digitalizovaná firma oproti off-line konkurenci?, Jaký systém vybrat pro snadné řízení výroby?, Nahradí umělá inteligence ajťáky?, Důvody, proč používat SnapTik ke stahování videí TikTok, Dokonalý den na pláži: Co si vzít s sebou, aby byl výlet zábavný a bezpečný?, Jak přežít dlouhý let?, Go pay GoodGame Empire, Blockchain, Rozhovor, Umělá inteligence, Ochranná známka pre softvér: Prečo ju registrovať?, Role kryptografických algoritmů v zabezpečení online kasin, Jaké jsou náklady na nákup 3D tiskárny?, Jak algoritmy vylepšují online zážitky v roce 2025,


Doporučujeme

Internet pro vaši firmu na míru

https://www.algoritmy.net