andere opgaven: acht koninginnen | boter, kaas en eieren | logiquiz | sudoku | laatste wint

Sudoku puzzel

Inhoud:
de puzzel
benadering
programma afloop
invoer
voorbeeld
code

Hoe zelfs de moeilijkste sudoku puzzel op te lossen (met een computer) ?

De puzzel:

De bedoeling van een sudoku puzzel is de 9x9 matrix zodanig in te vullen met de getallen 1 t/m 9 dat in iedere rij, kolom of 3x3-kwadrant die getallen maar èèn keer voorkomen. Een aantal posities is al ingevuld.
De eenvoudige sudoku's kunnen worden opgelost door een kolom/rij/kwadrant te vergelijken, waarbij er nog maar een positie overblijft voor een bepaald getal. Bij de moeilijkere puzzels zijn andere strategiën nodig, bijvoorbeeld uitsluiting over meerdere kolommen/rijen/kwadranten.

Benadering:

De computer leent zich voor een andere aanpak. Aanvankelijk krijgt ieder vakje in de matrix alle mogelijke opties 1-9 toegewezen. Dan worden de reeds toegewezen (gevulde) vakjes gebruikt om de opties uit de aangrenzende vakjes weg te strepen. De resterende opties worden nu een voor een uitgeprobeerd, waarbij direkt de gekozen optie wordt doorgerekend in de aangrenzende vakjes. Soms (vaak) blijkt een ingeslagen weg niet te leiden tot een oplossing, waardoor moet worden terug gevallen naar een eerdere keuze. Dit wordt 'backtracking' genoemd. Uiteindelijk resulteert dit in de (èèn) oplossing.

Programma afloop:

Allereerst word de interne nummering van de vakjes van de sudoku bepaald ('rows', 'cols', 'boxs'), en ook van ieder vakje alle aangrenzende vakjes opgesomd, de zgn. 'peers'. Dan wordt voor ieder vakje de kandidaten bepaald: lees_kandidaten() (een kandidaat is een mogelijke uitkomst voor een vakje).
De recursieve functie (backtrack), verloopt volgens deze pseudocode (wikipedia):
Van de eerste (=root) kandidaat voor het eerste vakje, wordt doorgerekend of deze kandidaat een conflict zal geven met een van zijn peers (reject())
• zo niet, dan wordt bekeken of de puzzel is opgelost (accept()), wordt deze kandidaat geplaatst in het vakje, en wordt het eerstvolgende vakje (met eerste kandidaat) onderzocht (eerstvolgende_kandidaat()). Dit gaat net zolang door (while)... totdat er een kandidaat niet meer past, of alle vakjes gevuld zijn.
• indien er wel een conflict is, dan zorgt return dat de tweede/volgende kandidaat wordt bekeken (alternatieve_kandidaat()).
Deze recursieve zorgt ervoor dat alle oplossingen worden gevonden, ook wanneer er geen oplossingen zijn.

Invoeren van een puzzel:

Invoeren van een puzzel kan door de gegeven getallen/vakjes in èèn lange reeks karakters te schrijven: voor een leeg vakje een niet-cijfer, voor een gevuld vakje het cijfer; spaties worden genegeerd. Van links naar rechts, van boven naar beneden.
Voor bovenstaand voorbeeld wordt dit:
3.65.84.. 52....... .87....31 ..3.1..8. 9..863..5 .5..9.6.. 13....25. .......74 ..52.63..
 
In de code zijn ook een aantal voorbeelden gegeven.

De code



#!/usr/bin/env python
# -*- coding: utf-8 -*-

from copy import deepcopy
from datetime import datetime, timedelta
import re

rows =  [ [ 0,  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, 33, 34, 35], [36, 37, 38, 39, 40, 41, 42, 43, 44], [45, 46, 47, 48, 49, 50, 51, 52, 53], 
         [54, 55, 56, 57, 58, 59, 60, 61, 62], [63, 64, 65, 66, 67, 68, 69, 70, 71], [72, 73, 74, 75, 76, 77, 78, 79, 80] ]
cols =  [ [ 0,  9, 18, 27, 36, 45, 54, 63, 72], [ 1, 10, 19, 28, 37, 46, 55, 64, 73], [ 2, 11, 20, 29, 38, 47, 56, 65, 74], 
         [ 3, 12, 21, 30, 39, 48, 57, 66, 75], [ 4, 13, 22, 31, 40, 49, 58, 67, 76], [ 5, 14, 23, 32, 41, 50, 59, 68, 77], 
         [ 6, 15, 24, 33, 42, 51, 60, 69, 78], [ 7, 16, 25, 34, 43, 52, 61, 70, 79], [ 8, 17, 26, 35, 44, 53, 62, 71, 80] ] 
boxs =  [ [ 0,  1,  2,  9, 10, 11, 18, 19, 20], [ 3,  4,  5, 12, 13, 14, 21, 22, 23], [ 6,  7,  8, 15, 16, 17, 24, 25, 26], 
          [27, 28, 29, 36, 37, 38, 45, 46, 47], [30, 31, 32, 39, 40, 41, 48, 49, 50], [33, 34, 35, 42, 43, 44, 51, 52, 53], 
          [54, 55, 56, 63, 64, 65, 72, 73, 74], [57, 58, 59, 66, 67, 68, 75, 76, 77], [60, 61, 62, 69, 70, 71, 78, 79, 80] ] 
peers = [ [ 1,  2,  3,  4,  5,  6,  7,  8,  9, 10, 11, 18, 19, 20, 27, 36, 45, 54, 63, 72], [0,  2,  3,  4,  5,  6,  7,  8,  9, 10, 11, 18, 19, 20, 28, 37, 46, 55, 64, 73], 
  [0,  1,  3,  4,  5,  6,  7,  8,  9, 10, 11, 18, 19, 20, 29, 38, 47, 56, 65, 74], [0,  1,  2,  4,  5,  6,  7,  8, 12, 13, 14, 21, 22, 23, 30, 39, 48, 57, 66, 75], 
  [0,  1,  2,  3,  5,  6,  7,  8, 12, 13, 14, 21, 22, 23, 31, 40, 49, 58, 67, 76], [0,  1,  2,  3,  4,  6,  7,  8, 12, 13, 14, 21, 22, 23, 32, 41, 50, 59, 68, 77], 
  [0,  1,  2,  3,  4,  5,  7,  8, 15, 16, 17, 24, 25, 26, 33, 42, 51, 60, 69, 78], [0,  1,  2,  3,  4,  5,  6,  8, 15, 16, 17, 24, 25, 26, 34, 43, 52, 61, 70, 79], 
  [0,  1,  2,  3,  4,  5,  6,  7, 15, 16, 17, 24, 25, 26, 35, 44, 53, 62, 71, 80], [0,  1,  2, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 27, 36, 45, 54, 63, 72], 
  [0,  1,  2,  9, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 28, 37, 46, 55, 64, 73], [0,  1,  2,  9, 10, 12, 13, 14, 15, 16, 17, 18, 19, 20, 29, 38, 47, 56, 65, 74], 
  [3,  4,  5,  9, 10, 11, 13, 14, 15, 16, 17, 21, 22, 23, 30, 39, 48, 57, 66, 75], [3,  4,  5,  9, 10, 11, 12, 14, 15, 16, 17, 21, 22, 23, 31, 40, 49, 58, 67, 76], 
  [3,  4,  5,  9, 10, 11, 12, 13, 15, 16, 17, 21, 22, 23, 32, 41, 50, 59, 68, 77], [6,  7,  8,  9, 10, 11, 12, 13, 14, 16, 17, 24, 25, 26, 33, 42, 51, 60, 69, 78], 
  [6,  7,  8,  9, 10, 11, 12, 13, 14, 15, 17, 24, 25, 26, 34, 43, 52, 61, 70, 79], [6,  7,  8,  9, 10, 11, 12, 13, 14, 15, 16, 24, 25, 26, 35, 44, 53, 62, 71, 80], 
  [0,  1,  2,  9, 10, 11, 19, 20, 21, 22, 23, 24, 25, 26, 27, 36, 45, 54, 63, 72], [0,  1,  2,  9, 10, 11, 18, 20, 21, 22, 23, 24, 25, 26, 28, 37, 46, 55, 64, 73], 
  [0,  1,  2,  9, 10, 11, 18, 19, 21, 22, 23, 24, 25, 26, 29, 38, 47, 56, 65, 74], [3,  4,  5, 12, 13, 14, 18, 19, 20, 22, 23, 24, 25, 26, 30, 39, 48, 57, 66, 75], 
  [3,  4,  5, 12, 13, 14, 18, 19, 20, 21, 23, 24, 25, 26, 31, 40, 49, 58, 67, 76], [3,  4,  5, 12, 13, 14, 18, 19, 20, 21, 22, 24, 25, 26, 32, 41, 50, 59, 68, 77], 
  [6,  7,  8, 15, 16, 17, 18, 19, 20, 21, 22, 23, 25, 26, 33, 42, 51, 60, 69, 78], [6,  7,  8, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 26, 34, 43, 52, 61, 70, 79], 
  [6,  7,  8, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 35, 44, 53, 62, 71, 80], [0,  9, 18, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 45, 46, 47, 54, 63, 72], 
  [1, 10, 19, 27, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 45, 46, 47, 55, 64, 73], [2, 11, 20, 27, 28, 30, 31, 32, 33, 34, 35, 36, 37, 38, 45, 46, 47, 56, 65, 74], 
  [3, 12, 21, 27, 28, 29, 31, 32, 33, 34, 35, 39, 40, 41, 48, 49, 50, 57, 66, 75], [4, 13, 22, 27, 28, 29, 30, 32, 33, 34, 35, 39, 40, 41, 48, 49, 50, 58, 67, 76], 
  [5, 14, 23, 27, 28, 29, 30, 31, 33, 34, 35, 39, 40, 41, 48, 49, 50, 59, 68, 77], [6, 15, 24, 27, 28, 29, 30, 31, 32, 34, 35, 42, 43, 44, 51, 52, 53, 60, 69, 78], 
  [7, 16, 25, 27, 28, 29, 30, 31, 32, 33, 35, 42, 43, 44, 51, 52, 53, 61, 70, 79], [8, 17, 26, 27, 28, 29, 30, 31, 32, 33, 34, 42, 43, 44, 51, 52, 53, 62, 71, 80], 
  [0,  9, 18, 27, 28, 29, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 54, 63, 72], [1, 10, 19, 27, 28, 29, 36, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 55, 64, 73], 
  [2, 11, 20, 27, 28, 29, 36, 37, 39, 40, 41, 42, 43, 44, 45, 46, 47, 56, 65, 74], [3, 12, 21, 30, 31, 32, 36, 37, 38, 40, 41, 42, 43, 44, 48, 49, 50, 57, 66, 75], 
  [4, 13, 22, 30, 31, 32, 36, 37, 38, 39, 41, 42, 43, 44, 48, 49, 50, 58, 67, 76], [5, 14, 23, 30, 31, 32, 36, 37, 38, 39, 40, 42, 43, 44, 48, 49, 50, 59, 68, 77], 
  [6, 15, 24, 33, 34, 35, 36, 37, 38, 39, 40, 41, 43, 44, 51, 52, 53, 60, 69, 78], [7, 16, 25, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 44, 51, 52, 53, 61, 70, 79], 
  [8, 17, 26, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 51, 52, 53, 62, 71, 80], [0,  9, 18, 27, 28, 29, 36, 37, 38, 46, 47, 48, 49, 50, 51, 52, 53, 54, 63, 72], 
  [1, 10, 19, 27, 28, 29, 36, 37, 38, 45, 47, 48, 49, 50, 51, 52, 53, 55, 64, 73], [2, 11, 20, 27, 28, 29, 36, 37, 38, 45, 46, 48, 49, 50, 51, 52, 53, 56, 65, 74], 
  [3, 12, 21, 30, 31, 32, 39, 40, 41, 45, 46, 47, 49, 50, 51, 52, 53, 57, 66, 75], [4, 13, 22, 30, 31, 32, 39, 40, 41, 45, 46, 47, 48, 50, 51, 52, 53, 58, 67, 76], 
  [5, 14, 23, 30, 31, 32, 39, 40, 41, 45, 46, 47, 48, 49, 51, 52, 53, 59, 68, 77], [6, 15, 24, 33, 34, 35, 42, 43, 44, 45, 46, 47, 48, 49, 50, 52, 53, 60, 69, 78], 
  [7, 16, 25, 33, 34, 35, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 53, 61, 70, 79], [8, 17, 26, 33, 34, 35, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 62, 71, 80], 
  [0,  9, 18, 27, 36, 45, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 72, 73, 74], [1, 10, 19, 28, 37, 46, 54, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 72, 73, 74], 
  [2, 11, 20, 29, 38, 47, 54, 55, 57, 58, 59, 60, 61, 62, 63, 64, 65, 72, 73, 74], [3, 12, 21, 30, 39, 48, 54, 55, 56, 58, 59, 60, 61, 62, 66, 67, 68, 75, 76, 77], 
  [4, 13, 22, 31, 40, 49, 54, 55, 56, 57, 59, 60, 61, 62, 66, 67, 68, 75, 76, 77], [5, 14, 23, 32, 41, 50, 54, 55, 56, 57, 58, 60, 61, 62, 66, 67, 68, 75, 76, 77], 
  [6, 15, 24, 33, 42, 51, 54, 55, 56, 57, 58, 59, 61, 62, 69, 70, 71, 78, 79, 80], [7, 16, 25, 34, 43, 52, 54, 55, 56, 57, 58, 59, 60, 62, 69, 70, 71, 78, 79, 80], 
  [8, 17, 26, 35, 44, 53, 54, 55, 56, 57, 58, 59, 60, 61, 69, 70, 71, 78, 79, 80], [0,  9, 18, 27, 36, 45, 54, 55, 56, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74], 
  [1, 10, 19, 28, 37, 46, 54, 55, 56, 63, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74], [2, 11, 20, 29, 38, 47, 54, 55, 56, 63, 64, 66, 67, 68, 69, 70, 71, 72, 73, 74], 
  [3, 12, 21, 30, 39, 48, 57, 58, 59, 63, 64, 65, 67, 68, 69, 70, 71, 75, 76, 77], [4, 13, 22, 31, 40, 49, 57, 58, 59, 63, 64, 65, 66, 68, 69, 70, 71, 75, 76, 77], 
  [5, 14, 23, 32, 41, 50, 57, 58, 59, 63, 64, 65, 66, 67, 69, 70, 71, 75, 76, 77], [6, 15, 24, 33, 42, 51, 60, 61, 62, 63, 64, 65, 66, 67, 68, 70, 71, 78, 79, 80], 
  [7, 16, 25, 34, 43, 52, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 71, 78, 79, 80], [8, 17, 26, 35, 44, 53, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 78, 79, 80], 
  [0,  9, 18, 27, 36, 45, 54, 55, 56, 63, 64, 65, 73, 74, 75, 76, 77, 78, 79, 80], [1, 10, 19, 28, 37, 46, 54, 55, 56, 63, 64, 65, 72, 74, 75, 76, 77, 78, 79, 80], 
  [2, 11, 20, 29, 38, 47, 54, 55, 56, 63, 64, 65, 72, 73, 75, 76, 77, 78, 79, 80], [3, 12, 21, 30, 39, 48, 57, 58, 59, 66, 67, 68, 72, 73, 74, 76, 77, 78, 79, 80], 
  [4, 13, 22, 31, 40, 49, 57, 58, 59, 66, 67, 68, 72, 73, 74, 75, 77, 78, 79, 80], [5, 14, 23, 32, 41, 50, 57, 58, 59, 66, 67, 68, 72, 73, 74, 75, 76, 78, 79, 80], 
  [6, 15, 24, 33, 42, 51, 60, 61, 62, 69, 70, 71, 72, 73, 74, 75, 76, 77, 79, 80], [7, 16, 25, 34, 43, 52, 60, 61, 62, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 80], 
  [8, 17, 26, 35, 44, 53, 60, 61, 62, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79] ]
peers.append( [ _ for _ in range(81) ] )

class SudokuSolverByBackTracking():
    def __init__(self, nummerreeks: str):
        self.duur = None
        self.opgave = None
        self.oplossingen = []
        self.kandidaten = self.lees_kandidaten(nummerreeks)

    def __str__(self):
        '''
        voegt de scherm output van de originele puzzel en oplossing(en) samen
        '''
        response = self._str_join()
        out = '\n' + 'opgave:\n' + response[0].replace('0', '.') + '\noplossing(en):\n' 
        for resp in response[1:]:
            out += resp + '\n'
        out += '{} gevonden oplossing(en)'.format(len(self.oplossingen), )
        if self.duur:
            out += ' in: {}'.format(self.duur, )
        out += '\n'
        return out

    def _str_join(self) -> list:
        '''
        voegt de originele opgave en oplossingen samen tbv scherm output
        '''
        response = []
        for opl in [self.opgave] + self.oplossingen:
            resp = ''
            c = ''.join([ str(item) for item in opl ])
            c = [ c[i*3:(i+1)*3] for i in range(27) ]
            for row in range(9):
                resp += ' ' + c[3*row+0] + ' \u2502 ' + c[3*row+1] + ' \u2502 ' + c[3*row+2] + '\n'
                if row in [2, 5]: 
                    resp += '\u253c'.join(['\u2500'*5]*3) + '\n'
            resp += '\n'
            response.append(resp)
        return response

    def lees_kandidaten(self, nummers: str) -> list:
        '''
        omzetten van de opgave in een lijst van kandidaten per positie
        '''
        deze_kandidaten = []
        nummers = re.sub(r'\s', '', nummers) # verwijder spaties
        nummers = re.sub(r'[^\d]', '0', nummers) # verander overige karakters in '0'
        self.opgave = nummers
        for positie in range(81):
            nummer = int(nummers[positie])
            if nummer == 0:
                reeks = [ 1,2,3,4,5,6,7,8,9 ]
                for peer in peers[positie]:
                    if int(nummers[peer]) in reeks:
                        reeks.remove(int(nummers[peer]))
            else:
                reeks = [ nummer ]
            deze_kandidaten.append(reeks)
        deze_kandidaten.append([99])
        return deze_kandidaten

    def root(self) -> tuple:
        '''
        bepaalt het startpunt (root (=kandidaat)) van de recursieve zoektocht
        '''
        return ( len(self.kandidaten)-1, self.kandidaten[len(self.kandidaten)-1][0] )

    def los_op(self):
        start_tijd = datetime.now()
        self.backtrack(deepcopy(self.kandidaten), self.root())
        self.duur = datetime.now()-start_tijd

    def reject(self, kandidaten: list, kandidaat: tuple):
        '''
        bepaalt (True/False) of een kandidaat (positie, waarde) geen conflict geeft met zijn buren, maw of dit een mogelijke zet is
        '''
        buren = [ kandidaten[peer][0] for peer in peers[kandidaat[0]] if len(kandidaten[peer])==1 ]
        return kandidaat[1] in buren

    def accept(self, kandidaat: tuple) -> bool:
        '''
        bepaalt (True/False) of een kandidaat (positie, waarde) resulteert in een oplossing van de sudoku
        '''
        self.kandidaten[kandidaat[0]] = [ kandidaat[1] ]
        for reeks in rows+cols+boxs:
            if ''.join( sorted( [ str(self.kandidaten[reeks[indx]][0]) for indx in range(9) ] ) ) != '123456789':
                return False
        deze_oplossing = ''.join(str(self.kandidaten[pos][0]) for pos in range(81) ) 
        if deze_oplossing not in self.oplossingen:
            self.oplossingen.append(deze_oplossing)
        return True

    def eerstvolgende_kandidaat(self, kandidaten: list, kandidaat: tuple) -> tuple:
        '''
        bepaalt de eerstvolgende kandidaat (positie, waarde) voor een volgende positie in de puzzel
        '''
        kandidaten[kandidaat[0]] = [ kandidaat[1] ]
        indx = kandidaat[0] - 1
        if indx < 0:
            return (False, False)
        else:
            return kandidaten, (indx, kandidaten[indx][0])

    def alternatieve_kandidaat(self, lijst: list, kandidaat: tuple) -> tuple:
        '''
        bepaalt een alternatieve kandidaat (positie, waarde) voor dezelfde positie in de puzzel
        '''
        indx = lijst[kandidaat[0]].index(kandidaat[1])
        if indx >= len(lijst[kandidaat[0]])-1:
            return False
        else:
            return (kandidaat[0], lijst[kandidaat[0]][indx+1])

    def backtrack(self, kandidaten: list, kandidaat: tuple):
        if self.reject(kandidaten, kandidaat):
            return False
        if self.accept(kandidaat):
            return False
        kandidaten, nw_kandidaat = self.eerstvolgende_kandidaat(kandidaten, kandidaat)
        while nw_kandidaat:
            self.backtrack(deepcopy(kandidaten), deepcopy(nw_kandidaat))
            nw_kandidaat = self.alternatieve_kandidaat(kandidaten, nw_kandidaat)

if __name__ == "__main__":
    sudokus={}
    sudokus[1]  = [ '2.19..5.. ...5481.. 4..1..798 .57.8..36 .4..7...9 3..65...7 762..5.4. ....14.8. .....3.7.', '1. makkelijk' ]
    sudokus[2]  = [ '62..9.7.5 4...8.6.. .91.5.4.. ..3..527. .863.2... ..7.1..8. 87......1 ...9.7..2 352......', '2. makkelijk' ]
    sudokus[3]  = [ '945..8..6 2.3.6...5 ...547.32 7....3269 3.4..2... ..6.1984. ...8..571 68....... .5.32...8', '3. makkelijk' ]
    sudokus[4]  = [ '215..9..7 3..8.5..4 ..7..6..5 9...2..1. 1.2.6..9. 6.8.9..53 .9.4..8.. .4.9.13.2 .2...7..9', '4. gemiddeld' ]
    sudokus[5]  = [ '..24.1... 8.5..271. ..4....5. .8.2..... ....34... .36...8.7 2...839.. 6..1.94.8 1986..2..', '5. gemiddeld' ]
    sudokus[6]  = [ '2386.9... 4..2..3.8 .7......5 ....7..4. 36....... .1..4365. 7.1...28. 659.....7 ...764.9.', '6. gemiddeld' ]
    sudokus[7]  = [ '...2.3... ...9..1.8 265...... .1..9..7. .96.5.... 37....5.. ......2.1 9.46..... ...4.236.', '7. moeilijk' ]
    sudokus[8]  = [ '56....... ..3.1.5.. ...69.4.. .....8.67 ..1..9.8. 94...3.5. ...9...23 ..927.6.. ..4...1.8', '8. moeilijk' ]
    sudokus[9]  = [ '......2.5 ...6289.. 8.9...... .5..91... ......64. 714...... 9.2....6. .31...824 ...34....', '9. moeilijk' ]
    sudokus[10] = [ '4.5.2.... ...75.... ......4.3 .2...8..6 ......7.1 .8..9.... ..327.... ..1...69. ..76...1.', '10. zeer moeilijk' ]
    sudokus[11] = [ '....7.4.. 673...... ...39.5.. 3.2.....8 ..7.1...9 ...5.2... ...258.3. .....7.4. 86.......', '11. zeer moeilijk' ]
    sudokus[12] = [ '.......47 .....3..8 .9...6... .64.8..5. ..5...79. ....62... 1..8..... 4.21..... ......5.4', '12. zeer moeilijk' ]
    sudokus[13] = [ '.......47 .....3... .9...6... .64.8..5. ..5...79. ....62... 1..8..... 4.21..... ......5.4', '13. meerdere oplossingen' ]
    sudokus[14] = [ '.......47 .....3..7 .9...6... .64.8..5. ..5...79. ....62... 1..8..... 4.21..... ......5.4', '14. geen oplossingen' ]
    
    puzzel = SudokuSolverByBackTracking(sudokus[1][0])
    puzzel.los_op()
    print(puzzel)