Added deduction logic checks (if there's a value only in one row/col in a square, it can't be in the rest of the row/col)
This commit is contained in:
parent
1afd7e739e
commit
ab4a6e96e2
@ -49,7 +49,7 @@ class @SudokuChecks
|
||||
@twoValPlaces: (cells) ->
|
||||
return if not cells[0]
|
||||
dim2 = cells[0].boardObj.dim2
|
||||
console.group('twoValPlaces: (%o) %o', dim2, cells)
|
||||
console.groupCollapsed('twoValPlaces: (%o) %o', dim2, cells)
|
||||
for i in [0...dim2-1] by 1 # walk all possible 2s combinations
|
||||
for j in [i+1...dim2] by 1
|
||||
n = 0
|
||||
@ -73,3 +73,27 @@ class @SudokuChecks
|
||||
cells[k].setMask(newMask)
|
||||
console.groupEnd()
|
||||
return true
|
||||
|
||||
@rowMatch: (blockSubject, blockRest, lineRest) ->
|
||||
# aaabbbccc ... if bbb is only possibility for one num (check rest of block!), remove from aaa and ccc
|
||||
return if not blockSubject[0] or not blockRest[0] or not lineRest[0]
|
||||
console.groupCollapsed('rowMatch: %o, %o, %o', blockSubject, blockRest, lineRest)
|
||||
for i in [0...blockSubject[0].boardObj.dim2] by 1 # walk all possible values
|
||||
p = (1 << i)
|
||||
isInSubject = false
|
||||
isInRest = false
|
||||
# test if number is in subject
|
||||
for j of blockSubject
|
||||
if blockSubject[j].getValue() is '.' and (p & blockSubject[j].getMask())
|
||||
isInSubject = true
|
||||
break
|
||||
# test if number is in rest of square
|
||||
for j of blockRest
|
||||
if blockRest[j].getValue() is '.' and (p & blockRest[j].getMask())
|
||||
isInRest = true
|
||||
break
|
||||
# if only in subject, remove candidate from rest
|
||||
if isInSubject and not isInRest
|
||||
for j of lineRest
|
||||
lineRest[j].setMask(lineRest[j].getMask() & ~p)
|
||||
console.groupEnd()
|
||||
|
@ -31,6 +31,60 @@ class @SudokuSolver
|
||||
result.push(board.cellAt(i, col))
|
||||
return result
|
||||
|
||||
@getSquareColCells: (board, squareid, squarecol) ->
|
||||
result = []
|
||||
rb = Math.floor(squareid / board.dim) * board.dim # base row for square
|
||||
cx = squareid % board.dim * board.dim + squarecol # x for column
|
||||
for i in [0...board.dim] by 1
|
||||
result.push(board.cellAt(cx, rb + i))
|
||||
return result
|
||||
|
||||
@getSquareNonColCells: (board, squareid, squarecol) ->
|
||||
result = []
|
||||
rb = Math.floor(squareid / board.dim) * board.dim # base row for square
|
||||
cx = squareid % board.dim * board.dim # base x for column
|
||||
for i in [0...board.dim] by 1
|
||||
continue if i is squarecol
|
||||
for j in [0...board.dim] by 1
|
||||
result.push(board.cellAt(cx + i, rb + j))
|
||||
return result
|
||||
|
||||
@getNonSquareColCells: (board, squareid, squarecol) ->
|
||||
result = []
|
||||
rb = Math.floor(squareid / board.dim) * board.dim # base row for square
|
||||
cx = squareid % board.dim * board.dim + squarecol # x for column
|
||||
for i in [0...board.dim2] by 1
|
||||
continue if i in [rb...rb+board.dim]
|
||||
result.push(board.cellAt(cx, i))
|
||||
return result
|
||||
|
||||
@getSquareRowCells: (board, squareid, squarerow) ->
|
||||
result = []
|
||||
cb = squareid % board.dim * board.dim # base col for square
|
||||
ry = Math.floor(squareid / board.dim) * board.dim + squarerow # y for row
|
||||
for i in [0...board.dim] by 1
|
||||
result.push(board.cellAt(cb + i, ry))
|
||||
return result
|
||||
|
||||
@getSquareNonRowCells: (board, squareid, squarerow) ->
|
||||
result = []
|
||||
cb = squareid % board.dim * board.dim # base column for square
|
||||
ry = Math.floor(squareid / board.dim) * board.dim # base y for row
|
||||
for i in [0...board.dim] by 1
|
||||
continue if i is squarerow
|
||||
for j in [0...board.dim] by 1
|
||||
result.push(board.cellAt(cb + j, ry + i))
|
||||
return result
|
||||
|
||||
@getNonSquareRowCells: (board, squareid, squarerow) ->
|
||||
result = []
|
||||
cb = squareid % board.dim * board.dim # base col for square
|
||||
ry = Math.floor(squareid / board.dim) * board.dim + squarerow # y for row
|
||||
for i in [0...board.dim2] by 1
|
||||
continue if i in [cb...cb+board.dim]
|
||||
result.push(board.cellAt(i, ry))
|
||||
return result
|
||||
|
||||
@runAllRows: (board, func) ->
|
||||
for i in [0...board.dim2] by 1 # walk all rows
|
||||
rowcells = @getRowCells(board, i)
|
||||
@ -56,6 +110,28 @@ class @SudokuSolver
|
||||
SudokuChecks[func](diag1)
|
||||
SudokuChecks[func](diag2)
|
||||
|
||||
@runSpecialColumns: (board, func) ->
|
||||
blockCol = []
|
||||
blockRest = []
|
||||
colRest = []
|
||||
for s in [0...board.dim2] by 1 # walk all squares
|
||||
for c in [0...board.dim] by 1 # walk all square columns
|
||||
blockCol = @getSquareColCells(board, s, c)
|
||||
blockRest = @getSquareNonColCells(board, s, c)
|
||||
colRest = @getNonSquareColCells(board, s, c)
|
||||
SudokuChecks[func](blockCol, blockRest, colRest)
|
||||
|
||||
@runSpecialRows: (board, func) ->
|
||||
blockRow = []
|
||||
blockRest = []
|
||||
rowRest = []
|
||||
for s in [0...board.dim2] by 1 # walk all squares
|
||||
for r in [0...board.dim] by 1 # walk all square rows
|
||||
blockRow = @getSquareRowCells(board, s, r)
|
||||
blockRest = @getSquareNonRowCells(board, s, r)
|
||||
rowRest = @getNonSquareRowCells(board, s, r)
|
||||
SudokuChecks[func](blockRow, blockRest, rowRest)
|
||||
|
||||
@oneUnknownAll: (board) ->
|
||||
cells = []
|
||||
for r in [0...board.dim2] by 1
|
||||
@ -71,6 +147,8 @@ class @SudokuSolver
|
||||
@twoValPlacesRow: (board) -> @runAllRows(board, 'twoValPlaces')
|
||||
@twoValPlacesColumn: (board) -> @runAllColumns(board, 'twoValPlaces')
|
||||
@twoValPlacesDiag: (board) -> @runBothDiags(board, 'twoValPlaces')
|
||||
@oneColumnForValue: (board) -> @runSpecialColumns(board, 'rowMatch')
|
||||
@oneRowForValue: (board) -> @runSpecialRows(board, 'rowMatch')
|
||||
|
||||
@solveBoard: (board) ->
|
||||
checks =
|
||||
@ -84,6 +162,8 @@ class @SudokuSolver
|
||||
'twoValPlacesColumn': 'Only two possible places for pair in column.'
|
||||
'twoValPlacesDiag': 'Only two possible places for pair in diagonale.'
|
||||
'oneUnknownAll': 'Only one possible value left.'
|
||||
'oneColumnForValue': 'Only one possible column for value.'
|
||||
'oneRowForValue': 'Only one possible row for value.'
|
||||
|
||||
i = 1
|
||||
while true
|
||||
|
@ -20,9 +20,10 @@
|
||||
//board.loadString('69..2...............81...32..9......3....4.76.6...3.....5....4.....8..........5..', true);
|
||||
//board.loadString('.2.....8.3..6.2..5...1.9....74...31...........68...47....5.8...6..7.3..9.3.....4.', false);
|
||||
//board.loadString('7...54..949..67.1....192347....71.9....63........48.3.35.....716487139...7......3', false);
|
||||
board.loadString('..3.........4.....98.23.....2.91.8..5.....1.....3.67...4...7.....6...2.91.2.....6', false);
|
||||
board.loadString('..3.........4.....98.23.....2.91.8..5.....1.....3.67...4...7.....6...2.91.2.....6', false); // HARD
|
||||
//board.loadString('9.8.6.15...5.1...8.1.2.....8..............349.4.9....71......8..6..9........5..6.', false);
|
||||
//board.loadString('.......14..92..6.3.4.....9.2..3.4.....579......8162.3....98..2.5.....4...1...3...', false);
|
||||
//board.loadString('....1..........47576...9.1..34..26..8..9.3..4..68..12..9.4...61147..........2....', false); // HARD
|
||||
document.write('Base board:<br />');
|
||||
board.print();
|
||||
</script>
|
||||
|
@ -75,7 +75,7 @@
|
||||
return;
|
||||
}
|
||||
dim2 = cells[0].boardObj.dim2;
|
||||
console.group('twoValPlaces: (%o) %o', dim2, cells);
|
||||
console.groupCollapsed('twoValPlaces: (%o) %o', dim2, cells);
|
||||
for (i = _i = 0, _ref = dim2 - 1; _i < _ref; i = _i += 1) {
|
||||
for (j = _j = _ref1 = i + 1; _j < dim2; j = _j += 1) {
|
||||
n = 0;
|
||||
@ -110,6 +110,37 @@
|
||||
return true;
|
||||
};
|
||||
|
||||
SudokuChecks.rowMatch = function(blockSubject, blockRest, lineRest) {
|
||||
var i, isInRest, isInSubject, j, p, _i, _ref;
|
||||
if (!blockSubject[0] || !blockRest[0] || !lineRest[0]) {
|
||||
return;
|
||||
}
|
||||
console.groupCollapsed('rowMatch: %o, %o, %o', blockSubject, blockRest, lineRest);
|
||||
for (i = _i = 0, _ref = blockSubject[0].boardObj.dim2; _i < _ref; i = _i += 1) {
|
||||
p = 1 << i;
|
||||
isInSubject = false;
|
||||
isInRest = false;
|
||||
for (j in blockSubject) {
|
||||
if (blockSubject[j].getValue() === '.' && (p & blockSubject[j].getMask())) {
|
||||
isInSubject = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
for (j in blockRest) {
|
||||
if (blockRest[j].getValue() === '.' && (p & blockRest[j].getMask())) {
|
||||
isInRest = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (isInSubject && !isInRest) {
|
||||
for (j in lineRest) {
|
||||
lineRest[j].setMask(lineRest[j].getMask() & ~p);
|
||||
}
|
||||
}
|
||||
}
|
||||
return console.groupEnd();
|
||||
};
|
||||
|
||||
return SudokuChecks;
|
||||
|
||||
})();
|
||||
|
@ -1,5 +1,7 @@
|
||||
// Generated by CoffeeScript 1.6.3
|
||||
(function() {
|
||||
var __indexOf = [].indexOf || function(item) { for (var i = 0, l = this.length; i < l; i++) { if (i in this && this[i] === item) return i; } return -1; };
|
||||
|
||||
this.SudokuSolver = (function() {
|
||||
function SudokuSolver() {}
|
||||
|
||||
@ -50,6 +52,96 @@
|
||||
return result;
|
||||
};
|
||||
|
||||
SudokuSolver.getSquareColCells = function(board, squareid, squarecol) {
|
||||
var cx, i, rb, result, _i, _ref;
|
||||
result = [];
|
||||
rb = Math.floor(squareid / board.dim) * board.dim;
|
||||
cx = squareid % board.dim * board.dim + squarecol;
|
||||
for (i = _i = 0, _ref = board.dim; _i < _ref; i = _i += 1) {
|
||||
result.push(board.cellAt(cx, rb + i));
|
||||
}
|
||||
return result;
|
||||
};
|
||||
|
||||
SudokuSolver.getSquareNonColCells = function(board, squareid, squarecol) {
|
||||
var cx, i, j, rb, result, _i, _j, _ref, _ref1;
|
||||
result = [];
|
||||
rb = Math.floor(squareid / board.dim) * board.dim;
|
||||
cx = squareid % board.dim * board.dim;
|
||||
for (i = _i = 0, _ref = board.dim; _i < _ref; i = _i += 1) {
|
||||
if (i === squarecol) {
|
||||
continue;
|
||||
}
|
||||
for (j = _j = 0, _ref1 = board.dim; _j < _ref1; j = _j += 1) {
|
||||
result.push(board.cellAt(cx + i, rb + j));
|
||||
}
|
||||
}
|
||||
return result;
|
||||
};
|
||||
|
||||
SudokuSolver.getNonSquareColCells = function(board, squareid, squarecol) {
|
||||
var cx, i, rb, result, _i, _j, _ref, _ref1, _results;
|
||||
result = [];
|
||||
rb = Math.floor(squareid / board.dim) * board.dim;
|
||||
cx = squareid % board.dim * board.dim + squarecol;
|
||||
for (i = _i = 0, _ref = board.dim2; _i < _ref; i = _i += 1) {
|
||||
if (__indexOf.call((function() {
|
||||
_results = [];
|
||||
for (var _j = rb, _ref1 = rb + board.dim; rb <= _ref1 ? _j < _ref1 : _j > _ref1; rb <= _ref1 ? _j++ : _j--){ _results.push(_j); }
|
||||
return _results;
|
||||
}).apply(this), i) >= 0) {
|
||||
continue;
|
||||
}
|
||||
result.push(board.cellAt(cx, i));
|
||||
}
|
||||
return result;
|
||||
};
|
||||
|
||||
SudokuSolver.getSquareRowCells = function(board, squareid, squarerow) {
|
||||
var cb, i, result, ry, _i, _ref;
|
||||
result = [];
|
||||
cb = squareid % board.dim * board.dim;
|
||||
ry = Math.floor(squareid / board.dim) * board.dim + squarerow;
|
||||
for (i = _i = 0, _ref = board.dim; _i < _ref; i = _i += 1) {
|
||||
result.push(board.cellAt(cb + i, ry));
|
||||
}
|
||||
return result;
|
||||
};
|
||||
|
||||
SudokuSolver.getSquareNonRowCells = function(board, squareid, squarerow) {
|
||||
var cb, i, j, result, ry, _i, _j, _ref, _ref1;
|
||||
result = [];
|
||||
cb = squareid % board.dim * board.dim;
|
||||
ry = Math.floor(squareid / board.dim) * board.dim;
|
||||
for (i = _i = 0, _ref = board.dim; _i < _ref; i = _i += 1) {
|
||||
if (i === squarerow) {
|
||||
continue;
|
||||
}
|
||||
for (j = _j = 0, _ref1 = board.dim; _j < _ref1; j = _j += 1) {
|
||||
result.push(board.cellAt(cb + j, ry + i));
|
||||
}
|
||||
}
|
||||
return result;
|
||||
};
|
||||
|
||||
SudokuSolver.getNonSquareRowCells = function(board, squareid, squarerow) {
|
||||
var cb, i, result, ry, _i, _j, _ref, _ref1, _results;
|
||||
result = [];
|
||||
cb = squareid % board.dim * board.dim;
|
||||
ry = Math.floor(squareid / board.dim) * board.dim + squarerow;
|
||||
for (i = _i = 0, _ref = board.dim2; _i < _ref; i = _i += 1) {
|
||||
if (__indexOf.call((function() {
|
||||
_results = [];
|
||||
for (var _j = cb, _ref1 = cb + board.dim; cb <= _ref1 ? _j < _ref1 : _j > _ref1; cb <= _ref1 ? _j++ : _j--){ _results.push(_j); }
|
||||
return _results;
|
||||
}).apply(this), i) >= 0) {
|
||||
continue;
|
||||
}
|
||||
result.push(board.cellAt(i, ry));
|
||||
}
|
||||
return result;
|
||||
};
|
||||
|
||||
SudokuSolver.runAllRows = function(board, func) {
|
||||
var i, rowcells, _i, _ref, _results;
|
||||
_results = [];
|
||||
@ -95,6 +187,50 @@
|
||||
return SudokuChecks[func](diag2);
|
||||
};
|
||||
|
||||
SudokuSolver.runSpecialColumns = function(board, func) {
|
||||
var blockCol, blockRest, c, colRest, s, _i, _ref, _results;
|
||||
blockCol = [];
|
||||
blockRest = [];
|
||||
colRest = [];
|
||||
_results = [];
|
||||
for (s = _i = 0, _ref = board.dim2; _i < _ref; s = _i += 1) {
|
||||
_results.push((function() {
|
||||
var _j, _ref1, _results1;
|
||||
_results1 = [];
|
||||
for (c = _j = 0, _ref1 = board.dim; _j < _ref1; c = _j += 1) {
|
||||
blockCol = this.getSquareColCells(board, s, c);
|
||||
blockRest = this.getSquareNonColCells(board, s, c);
|
||||
colRest = this.getNonSquareColCells(board, s, c);
|
||||
_results1.push(SudokuChecks[func](blockCol, blockRest, colRest));
|
||||
}
|
||||
return _results1;
|
||||
}).call(this));
|
||||
}
|
||||
return _results;
|
||||
};
|
||||
|
||||
SudokuSolver.runSpecialRows = function(board, func) {
|
||||
var blockRest, blockRow, r, rowRest, s, _i, _ref, _results;
|
||||
blockRow = [];
|
||||
blockRest = [];
|
||||
rowRest = [];
|
||||
_results = [];
|
||||
for (s = _i = 0, _ref = board.dim2; _i < _ref; s = _i += 1) {
|
||||
_results.push((function() {
|
||||
var _j, _ref1, _results1;
|
||||
_results1 = [];
|
||||
for (r = _j = 0, _ref1 = board.dim; _j < _ref1; r = _j += 1) {
|
||||
blockRow = this.getSquareRowCells(board, s, r);
|
||||
blockRest = this.getSquareNonRowCells(board, s, r);
|
||||
rowRest = this.getNonSquareRowCells(board, s, r);
|
||||
_results1.push(SudokuChecks[func](blockRow, blockRest, rowRest));
|
||||
}
|
||||
return _results1;
|
||||
}).call(this));
|
||||
}
|
||||
return _results;
|
||||
};
|
||||
|
||||
SudokuSolver.oneUnknownAll = function(board) {
|
||||
var c, cells, r, _i, _j, _ref, _ref1;
|
||||
cells = [];
|
||||
@ -138,6 +274,14 @@
|
||||
return this.runBothDiags(board, 'twoValPlaces');
|
||||
};
|
||||
|
||||
SudokuSolver.oneColumnForValue = function(board) {
|
||||
return this.runSpecialColumns(board, 'rowMatch');
|
||||
};
|
||||
|
||||
SudokuSolver.oneRowForValue = function(board) {
|
||||
return this.runSpecialRows(board, 'rowMatch');
|
||||
};
|
||||
|
||||
SudokuSolver.solveBoard = function(board) {
|
||||
var body, c, checks, description, i;
|
||||
checks = {
|
||||
@ -150,7 +294,9 @@
|
||||
'twoValPlacesRow': 'Only two possible places for pair in row.',
|
||||
'twoValPlacesColumn': 'Only two possible places for pair in column.',
|
||||
'twoValPlacesDiag': 'Only two possible places for pair in diagonale.',
|
||||
'oneUnknownAll': 'Only one possible value left.'
|
||||
'oneUnknownAll': 'Only one possible value left.',
|
||||
'oneColumnForValue': 'Only one possible column for value.',
|
||||
'oneRowForValue': 'Only one possible row for value.'
|
||||
};
|
||||
i = 1;
|
||||
while (true) {
|
||||
|
Reference in New Issue
Block a user