Sudoku als constraint satisfaction problem
| > | restart: |
| > | read "C:/#Stuff/maple/_sudoku/LogicProblem.mpl": |
| > | interface(rtablesize = 30): |
| > | num_cols_per_box := 3: num_rows_per_box := 3: n := num_cols_per_box * num_rows_per_box: |
| > | V := ['place','value']: (Problem besteht aus zwei Mengen: Plaetze und Werte) |
| > | place := [p||(1..n^2)]: value := [$0..n^2-1]: (Alle Plaetze durchnummerieren; die Werte entsprechen im Modulo der gesetzten Zahl-1 und bekommen die zugeordnete Zeile-1 mal Anzahl moeglicher Zahlen als Offset [zur Unterscheidung der verschiedenen Instanzen einer Zahl]) |
| > | Sudoku := LogicProblem(V): |
| > | with(Sudoku): |
Warning, Sudoku is not a correctly formed package - option `package' is missing
| > | infolevel['Constraints'] := 1: infolevel['TC'] := 1: CollectStats := true: |
| > | rowidx := (nr,elem) -> (nr-1)*n + elem: |
| > | colidx := (nr,elem) -> nr + (elem-1)*n: |
| > | boxidx := (nr,elem) -> irem(nr-1,num_rows_per_box)*num_cols_per_box + n*iquo(nr-1, num_rows_per_box)*num_rows_per_box + irem(elem-1,num_cols_per_box) + n*iquo(elem-1,num_cols_per_box) + 1: (Hilfsfunktionen fuer die Zuordnung Gruppennr. + Elementnr. -> Index des Feldes in place[]) |
| > | for i to n do row||i := {place[rowidx(i,j)] $ j=1..n} end do: |
| > | for i to n do col||i := {place[colidx(i,j)] $ j=1..n} end do: |
| > | for i to n do box||i := {place[boxidx(i,j)] $ j=1..n} end do: (Aus place[] die Teilmengen der Zeilen, Spalten und Boxen extrahieren) |
| > | rows := [row||(1..n)]: |
| > | cols := [col||(1..n)]: |
| > | boxs := [box||(1..n)]: (Alle Zeilen, Spalten und Boxen zusammenfassen) |
| > | rowconstr := Rel(DifferentBlock, [v+n*k $ k=0..n-1], place, rows) $ v=0..n-1: |
| > | colconstr := Rel(DifferentBlock, [v+n*k $ k=0..n-1], place, cols) $ v=0..n-1: |
| > | boxconstr := Rel(DifferentBlock, [v+n*k $ k=0..n-1], place, boxs) $ v=0..n-1: (Sudokuregel implementieren: Jede Zahl ist einmalig in ihrer Zeile, Spalte und Box. Rest ergibt sich automatisch.) |
| > | uniqueconstr := Rel(SameBlock, [v*n+k $ k=0..n-1], place, rows) $ v=0..n-1: (Zusatzbedingungen, dadurch sind Permutationen der Einsen etc. untereinander ausgeschlossen. Ansonsten waere die gefundene Loesung fuer Maple nicht eindeutig.) |
| > | sv := (row,col,num) -> (num-1) + (row-1)*n = p||(col + (row-1)*n): (Generierung einer "Zahl gesetzt"-Bedingung aus Zeile, Spalte und gesetzter Zahl) |
| > | setconstr := sv(1,1,2),sv(1,4,4),sv(1,6,1),sv(1,9,6), sv(2,2,7),sv(2,5,3),sv(2,8,2), sv(3,4,2),sv(3,6,8), sv(4,3,9),sv(4,5,8),sv(4,7,5), sv(5,2,3),sv(5,3,8),sv(5,4,5),sv(5,6,6),sv(5,7,2),sv(5,8,4), sv(6,3,7),sv(6,5,2),sv(6,7,6), sv(7,4,8),sv(7,6,9), sv(8,2,6),sv(8,5,4),sv(8,8,7), sv(9,1,3),sv(9,4,6),sv(9,6,7),sv(9,9,5): (Einige Felder vorgebenen: sv(Zeile, Spalte, Zahl); Beispielsudoku aus P.M. Sudoku Trainer 9/2006, #6) |
| > | constraints := [_rowconstr,_colconstr,_boxconstr,_uniqueconstr,_setconstr]: (Alle Bedingungen zusammenfassen) |
| > | Reinitialize(): |
| > | st := time(): Satisfy(subs(_rowconstr=rowconstr,_colconstr=colconstr,_boxconstr=boxconstr, _uniqueconstr=uniqueconstr,_setconstr=setconstr,constraints)): time() - st; (Problem loesen ...) |
Satisfy:
Satisfy:
Rel/Check: Constraint Rel(DifferentBlock,8,71,1,[{p1, p10, p19, p73, p64, p37, p55, p28, p46}, {p2, p11, p20, p29, p38, p74, p65, p56, p47}, {p3, p12, p21, p30, p39, p75, p66, p57, p48}, {p4, p13, p22, p67, p76, p40, p31, p58, p49}, {p5, p14, p41, p59, p32, p23, p68, p77, p50}, {p6, p15, p42, p60, p33, p24, p69, p78, p51}, {p7, p16, p70, p34, p25, p43, p52, p61, p79}, {p8, p17, p44, p62, p26, p80, p53, p71, p35}, {p9, p18, p45, p63, p27, p81, p54, p72, p36}]) contradicted.
Rel/Check: Constraint Rel(DifferentBlock,7,70,1,[{p1, p10, p19, p73, p64, p37, p55, p28, p46}, {p2, p11, p20, p29, p38, p74, p65, p56, p47}, {p3, p12, p21, p30, p39, p75, p66, p57, p48}, {p4, p13, p22, p67, p76, p40, p31, p58, p49}, {p5, p14, p41, p59, p32, p23, p68, p77, p50}, {p6, p15, p42, p60, p33, p24, p69, p78, p51}, {p7, p16, p70, p34, p25, p43, p52, p61, p79}, {p8, p17, p44, p62, p26, p80, p53, p71, p35}, {p9, p18, p45, p63, p27, p81, p54, p72, p36}]) contradicted.
| > | conv_result := (nr) -> irem(op(2,&?(p||nr))[1],n)+1: (Zu einer Feldnummer den zugehoerigen Wert extrahieren und in die gesetzte Zahl umrechnen) |
| > | result := map(conv_result, [$1..n^2]); |
| > | &? ShowStats; |
| > |