Rewrote everything to CoffeeScript.
This commit is contained in:
parent
177e929693
commit
74149c2d41
32
Makefile
Normal file
32
Makefile
Normal file
@ -0,0 +1,32 @@
|
||||
CC=coffee
|
||||
SRCDIR=coffee
|
||||
BUILDDIR=js
|
||||
ALL_SRC_FILES := $(wildcard $(SRCDIR)/*)
|
||||
ALL_OTHER_SRC_FILES := $(filter-out %.coffee, $(ALL_SRC_FILES))
|
||||
ALL_OTHER_FILES := $(ALL_OTHER_SRC_FILES:$(SRCDIR)/%=$(BUILDDIR)/%)
|
||||
|
||||
SRC=$(wildcard $(SRCDIR)/*.coffee)
|
||||
BUILD=$(SRC:$(SRCDIR)/%.coffee=$(BUILDDIR)/%.js)
|
||||
|
||||
all: coffee other
|
||||
|
||||
# coffeescript files
|
||||
|
||||
coffee: $(BUILD)
|
||||
|
||||
$(BUILDDIR)/%.js: $(SRCDIR)/%.coffee
|
||||
$(CC) -o $(BUILDDIR)/ -c $<
|
||||
|
||||
# other files
|
||||
|
||||
other: $(ALL_OTHER_FILES)
|
||||
|
||||
$(ALL_OTHER_FILES): $(BUILDDIR)/%: $(SRCDIR)/%
|
||||
cp $< $@
|
||||
|
||||
# cleanup
|
||||
|
||||
.PHONY: clean
|
||||
clean:
|
||||
-rm $(BUILD)
|
||||
-rm $(ALL_OTHER_FILES)
|
74
coffee/SudokuBoard.class.coffee
Normal file
74
coffee/SudokuBoard.class.coffee
Normal file
@ -0,0 +1,74 @@
|
||||
class @SudokuBoard
|
||||
BASE_SET: '123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ'
|
||||
|
||||
constructor: (dim) ->
|
||||
@dim = Number(dim)
|
||||
@dim2 = @dim * @dim
|
||||
@set = @BASE_SET.substr(0, @dim2)
|
||||
@board = new Array(@dim2)
|
||||
@checkDiags = false
|
||||
@changed = false
|
||||
|
||||
for r in [0...@dim2] by 1
|
||||
@board[r] = new Array(@dim2)
|
||||
for c in [0...@dim2] by 1
|
||||
@board[r][c] = new SudokuCell(0, @)
|
||||
|
||||
loadString: (boarddef, alsoCheckDiags) ->
|
||||
boardString = ''
|
||||
for i in [0...boarddef.length] by 1
|
||||
continue if boarddef.charAt(i) isnt '.' and @set.indexOf(boarddef.charAt(i)) is -1
|
||||
boardString += boarddef.charAt(i)
|
||||
if boardString.length isnt @dim2*@dim2
|
||||
console.error('Bad board definition! (Need %d chars, got %d.)', (@dim2*@dim2), boardString.length)
|
||||
document.write('Bad board definition! (Need ' + (@dim2*@dim2) + ' chars, got ' + boardString.length + '.)')
|
||||
return false
|
||||
for i in [0...boardString.length] by 1
|
||||
r = Math.floor(i / @dim2)
|
||||
c = i % @dim2
|
||||
@board[r][c].setValue(boardString.charAt(i))
|
||||
@board[r][c].resetChangeFlag()
|
||||
@setCheckDiags(alsoCheckDiags)
|
||||
console.log('Board loaded.')
|
||||
|
||||
setCheckDiags: (newValue) ->
|
||||
@checkDiags = ( newValue )
|
||||
|
||||
cellAt: (r, c) ->
|
||||
return @board[r][c]
|
||||
|
||||
resetChangeFlags: ->
|
||||
for r in [0...@dim2] by 1
|
||||
for c in [0...@dim2] by 1
|
||||
@cellAt(r, c).resetChangeFlag()
|
||||
@changed = false
|
||||
|
||||
hasChanged: ->
|
||||
return @changed
|
||||
|
||||
print: ->
|
||||
html = ''
|
||||
html += '<table class="sudoku">'
|
||||
for r in [0...@dim2] by 1
|
||||
html += '<tr>'
|
||||
for c in [0...@dim2] by 1
|
||||
cssclass = ''
|
||||
cssclasses = []
|
||||
cssclasses.push('tborder') if r % @dim is 0
|
||||
cssclasses.push('lborder') if c % @dim is 0
|
||||
cssclasses.push('changed') if @cellAt(r, c).hasChanged()
|
||||
value = @cellAt(r, c).getValue()
|
||||
if value is '.'
|
||||
value = ''
|
||||
mask = @cellAt(r, c).getMask()
|
||||
for m in [0...@dim2]
|
||||
testm = 1 << m
|
||||
if testm & mask
|
||||
value += '<div class="hint-square hint' + (m+1) + '"></div>'
|
||||
cssclasses.push('mask' + mask)
|
||||
cssclass = ' class="' + cssclasses.join(' ') + '"' if cssclasses.length > 0
|
||||
html += "<td#{cssclass}>#{value}</td>"
|
||||
html += '</tr>'
|
||||
html += '</table>'
|
||||
body = document.getElementsByTagName('body')
|
||||
body[0].innerHTML += html
|
48
coffee/SudokuCell.class.coffee
Normal file
48
coffee/SudokuCell.class.coffee
Normal file
@ -0,0 +1,48 @@
|
||||
class @SudokuCell
|
||||
constructor: (initVal, boardObj) ->
|
||||
@boardObj = boardObj
|
||||
@changed = false
|
||||
@value = 0
|
||||
@set = (1 << @boardObj.dim2) - 1 # all
|
||||
@setValue(initVal) # init cell
|
||||
|
||||
setMask: (newSet) ->
|
||||
if newSet isnt @set
|
||||
@set = newSet
|
||||
@changed = true
|
||||
@boardObj.changed = true
|
||||
|
||||
setValue: (newValue) ->
|
||||
return false if newValue is @value
|
||||
setidx = @boardObj.set.indexOf(newValue)
|
||||
if setidx isnt -1
|
||||
@value = newValue
|
||||
@setMask(1 << setidx)
|
||||
@changed = true
|
||||
@boardObj.changed = true
|
||||
return true
|
||||
else if newValue is -1
|
||||
@value = 0
|
||||
@setMask((1 << @boardObj.dim2) - 1) # all
|
||||
@changed = true
|
||||
@boardObj.changed = true
|
||||
return false
|
||||
|
||||
getValue: ->
|
||||
return '.' if @value is 0
|
||||
return @value
|
||||
|
||||
getMask: ->
|
||||
return @set
|
||||
|
||||
getUnknownsCount: ->
|
||||
result = 0
|
||||
for n in [0...@boardObj.dim2] by 1
|
||||
result++ if ((1 << n) & @set)
|
||||
return result
|
||||
|
||||
hasChanged: ->
|
||||
return @changed
|
||||
|
||||
resetChangeFlag: ->
|
||||
@changed = false
|
71
coffee/SudokuChecks.class.coffee
Normal file
71
coffee/SudokuChecks.class.coffee
Normal file
@ -0,0 +1,71 @@
|
||||
class @SudokuChecks
|
||||
@unique: (board, r, c) ->
|
||||
set = ~board.cellAt(r, c).getMask()
|
||||
|
||||
# row / column / diagonale
|
||||
for i in [0...board.dim2] by 1
|
||||
if i isnt c # row
|
||||
board.cellAt(r, i).setMask(board.cellAt(r, i).getMask() & set)
|
||||
if i isnt r # column
|
||||
board.cellAt(i, c).setMask(board.cellAt(i, c).getMask() & set)
|
||||
if board.checkDiags
|
||||
if r is c and i isnt r # diagonale \
|
||||
board.cellAt(i, i).setMask(board.cellAt(i, i).getMask() & set)
|
||||
if r is board.dim2-c-1 and i isnt r # diagonale /
|
||||
board.cellAt(i, board.dim2-i-1).setMask(board.cellAt(i, board.dim2-i-1).getMask() & set)
|
||||
|
||||
# square
|
||||
rb = Math.floor(r / board.dim) * board.dim; # row base for this square
|
||||
cb = Math.floor(c / board.dim) * board.dim; # col base for this square
|
||||
for i in [rb...rb+board.dim] by 1
|
||||
for j in [cb...cb+board.dim] by 1
|
||||
if i isnt r || j isnt c
|
||||
board.cellAt(i, j).setMask(board.cellAt(i, j).getMask() & set )
|
||||
return true
|
||||
|
||||
@onePlace: (cells) ->
|
||||
return if not cells[0]
|
||||
for i in [0...cells[0].boardObj.dim2] by 1 # walk all possible values
|
||||
n = 0
|
||||
p = (1 << i)
|
||||
x = -1
|
||||
for k of cells
|
||||
if cells[k].getValue() is '.' and (p & cells[k].getMask())
|
||||
n++
|
||||
x = k
|
||||
if n is 1
|
||||
cells[x].setMask(p)
|
||||
cells[x].setValue(cells[0].boardObj.set.charAt(Math.log(p) / Math.log(2)))
|
||||
return true
|
||||
|
||||
@oneUnknown: (cells) ->
|
||||
for c of cells
|
||||
if cells[c].getValue() is '.' and cells[c].getUnknownsCount() is 1
|
||||
valid = cells[c].getMask()
|
||||
val = cells[c].boardObj.set.charAt(Math.log(valid) / Math.log(2))
|
||||
cells[c].setValue(val)
|
||||
return true
|
||||
|
||||
@twoValPlaces: (cells) ->
|
||||
return if not cells[0]
|
||||
dim2 = cells[0].boardObj.dim2
|
||||
console.group('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
|
||||
p = (1 << i) | (1 << j)
|
||||
console.log('Now checking (%o, %o) mask: %o', i+1, j+1, p)
|
||||
for k of cells
|
||||
if cells[k].getValue() is '.' and cells[k].getMask() & p is p
|
||||
n++
|
||||
console.log('%d: %d, %d (%o, %o)', n, p, cells[k].getMask(), (p & cells[k].getMask()), ((p & cells[k].getMask()) is p))
|
||||
console.info('Have %d matches.', n) if n > 0
|
||||
if n is 2
|
||||
console.warn('Two matches!')
|
||||
for k of cells
|
||||
if cells[k].getValue() is '.' and cells[k].getMask() is p
|
||||
cells[k].setMask(p)
|
||||
else if cells[k].getValue() is '.'
|
||||
cells[k].setMask(cells[k].getMask() & ~p)
|
||||
console.groupEnd()
|
||||
return true
|
105
coffee/SudokuSolver.class.coffee
Normal file
105
coffee/SudokuSolver.class.coffee
Normal file
@ -0,0 +1,105 @@
|
||||
class @SudokuSolver
|
||||
|
||||
@uniqueAll: (board) ->
|
||||
for r in [0...board.dim2] by 1
|
||||
for c in [0...board.dim2] by 1
|
||||
SudokuChecks.unique(board, r, c) if board.cellAt(r, c).getValue() isnt '.'
|
||||
return true
|
||||
|
||||
# returns all cells for the square of the specified cell
|
||||
@getSquareCellsForCell: (board, r, c) ->
|
||||
sqrid = Math.floor(r / board.dim) * board.dim + Math.floor(c / board.dim)
|
||||
return @getSquareCells(board, sqrid)
|
||||
|
||||
@getSquareCells: (board, squareid) ->
|
||||
result = []
|
||||
rb = Math.floor(squareid / board.dim) * board.dim # base row for square
|
||||
cb = squareid % board.dim * board.dim # base col for square
|
||||
for i in [0...board.dim2] by 1
|
||||
result.push(board.cellAt(rb + Math.floor(i / board.dim), cb + (i % board.dim)))
|
||||
return result
|
||||
|
||||
@getRowCells: (board, row) ->
|
||||
result = []
|
||||
for i in [0...board.dim2] by 1
|
||||
result.push(board.cellAt(row, i))
|
||||
return result
|
||||
|
||||
@getColCells: (board, col) ->
|
||||
result = []
|
||||
for i in [0...board.dim2] by 1
|
||||
result.push(board.cellAt(i, col))
|
||||
return result
|
||||
|
||||
@runAllRows: (board, func) ->
|
||||
for i in [0...board.dim2] by 1 # walk all rows
|
||||
rowcells = @getRowCells(board, i)
|
||||
SudokuChecks[func](rowcells)
|
||||
|
||||
@runAllColumns: (board, func) ->
|
||||
for i in [0...board.dim2] by 1 # walk all columns
|
||||
colcells = @getColCells(board, i)
|
||||
SudokuChecks[func](colcells)
|
||||
|
||||
@runAllSquares: (board, func) ->
|
||||
for i in [0...board.dim2] by 1 # walk all squares
|
||||
sqrcells = @getSquareCells(board, i)
|
||||
SudokuChecks[func](sqrcells)
|
||||
|
||||
@runBothDiags: (board, func) ->
|
||||
return if not board.checkDiags
|
||||
diag1 = []
|
||||
diag2 = []
|
||||
for i in [0...board.dim2] by 1
|
||||
diag1.push(board.cellAt(i, i))
|
||||
diag2.push(board.cellAt(i, board.dim2-i-1))
|
||||
SudokuChecks[func](diag1)
|
||||
SudokuChecks[func](diag2)
|
||||
|
||||
@oneUnknownAll: (board) ->
|
||||
cells = []
|
||||
for r in [0...board.dim2] by 1
|
||||
for c in [0...board.dim2] by 1
|
||||
cells.push(board.cellAt(r, c))
|
||||
SudokuChecks.oneUnknown(cells)
|
||||
|
||||
@onePlaceRow: (board) -> @runAllRows(board, 'onePlace')
|
||||
@onePlaceColumn: (board) -> @runAllColumns(board, 'onePlace')
|
||||
@onePlaceSquare: (board) -> @runAllSquares(board, 'onePlace')
|
||||
@onePlaceDiag: (board) -> @runBothDiags(board, 'onePlace')
|
||||
@twoValPlacesSquare: (board) -> @runAllSquares(board, 'twoValPlaces')
|
||||
@twoValPlacesRow: (board) -> @runAllRows(board, 'twoValPlaces')
|
||||
@twoValPlacesColumn: (board) -> @runAllColumns(board, 'twoValPlaces')
|
||||
@twoValPlacesDiag: (board) -> @runBothDiags(board, 'twoValPlaces')
|
||||
|
||||
@solveBoard: (board) ->
|
||||
checks =
|
||||
'uniqueAll': 'Value must be unique in row, column' + if board.checkDiags then ', square and diagonales.' else ' and square.'
|
||||
'onePlaceSquare': 'Value has only one place in square.'
|
||||
'onePlaceRow': 'Value has only one place in row.'
|
||||
'onePlaceColumn': 'Value has only one place in column.'
|
||||
'onePlaceDiag': 'Value has only one place in diagonale.'
|
||||
'twoValPlacesSquare': 'Only two possible places for pair in square.'
|
||||
'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.'
|
||||
|
||||
i = 1
|
||||
while true
|
||||
console.time('Checking board.')
|
||||
board.resetChangeFlags()
|
||||
description = ''
|
||||
for c of checks
|
||||
description = checks[c]
|
||||
@[c](board)
|
||||
break if board.hasChanged()
|
||||
if board.hasChanged()
|
||||
console.info('Board was changed by "%s".', description)
|
||||
body = document.getElementsByTagName('body')
|
||||
body[0].innerHTML += i + '. ' + description + '<br />'
|
||||
board.print()
|
||||
i++
|
||||
console.timeEnd('Checking board.')
|
||||
break unless board.hasChanged() && i<100
|
||||
return 0
|
@ -1,86 +1,114 @@
|
||||
function SudokuBoard( dim ) {
|
||||
this.dim = Number( dim );
|
||||
this.dim2 = this.dim * this.dim;
|
||||
this.BASE_SET = '123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ';
|
||||
this.set = this.BASE_SET.substr(0, this.dim2);
|
||||
this.board = new Array( this.dim2 );
|
||||
this.checkDiags = false;
|
||||
this.changed = false;
|
||||
// Generated by CoffeeScript 1.6.3
|
||||
(function() {
|
||||
this.SudokuBoard = (function() {
|
||||
SudokuBoard.prototype.BASE_SET = '123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ';
|
||||
|
||||
for (var r=0; r<this.dim2; r++) {
|
||||
this.board[r] = new Array( this.dim2 );
|
||||
for (var c=0; c<this.dim2; c++) {
|
||||
this.board[r][c] = new SudokuCell(0, this);
|
||||
function SudokuBoard(dim) {
|
||||
var c, r, _i, _j, _ref, _ref1;
|
||||
this.dim = Number(dim);
|
||||
this.dim2 = this.dim * this.dim;
|
||||
this.set = this.BASE_SET.substr(0, this.dim2);
|
||||
this.board = new Array(this.dim2);
|
||||
this.checkDiags = false;
|
||||
this.changed = false;
|
||||
for (r = _i = 0, _ref = this.dim2; _i < _ref; r = _i += 1) {
|
||||
this.board[r] = new Array(this.dim2);
|
||||
for (c = _j = 0, _ref1 = this.dim2; _j < _ref1; c = _j += 1) {
|
||||
this.board[r][c] = new SudokuCell(0, this);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
this.loadString = function( boarddef, alsoCheckDiags ) {
|
||||
var boardString = '';
|
||||
for ( var i=0; i<boarddef.length; i++ ) {
|
||||
if ( boarddef.charAt(i) != '.' && this.set.indexOf( boarddef.charAt(i) ) == -1 ) continue;
|
||||
boardString += boarddef.charAt(i);
|
||||
SudokuBoard.prototype.loadString = function(boarddef, alsoCheckDiags) {
|
||||
var boardString, c, i, r, _i, _j, _ref, _ref1;
|
||||
boardString = '';
|
||||
for (i = _i = 0, _ref = boarddef.length; _i < _ref; i = _i += 1) {
|
||||
if (boarddef.charAt(i) !== '.' && this.set.indexOf(boarddef.charAt(i)) === -1) {
|
||||
continue;
|
||||
}
|
||||
if ( boardString.length != this.dim2 * this.dim2 ) {
|
||||
console.error( 'Bad board definition! (Need %d chars, got %d.)', (this.dim2*this.dim2), boardString.length );
|
||||
document.write( 'Bad board definition! (Need ' + (this.dim2*this.dim2) + ' chars, got ' + boardString.length + '.)' );
|
||||
return false;
|
||||
boardString += boarddef.charAt(i);
|
||||
}
|
||||
if (boardString.length !== this.dim2 * this.dim2) {
|
||||
console.error('Bad board definition! (Need %d chars, got %d.)', this.dim2 * this.dim2, boardString.length);
|
||||
document.write('Bad board definition! (Need ' + (this.dim2 * this.dim2) + ' chars, got ' + boardString.length + '.)');
|
||||
return false;
|
||||
}
|
||||
for (i = _j = 0, _ref1 = boardString.length; _j < _ref1; i = _j += 1) {
|
||||
r = Math.floor(i / this.dim2);
|
||||
c = i % this.dim2;
|
||||
this.board[r][c].setValue(boardString.charAt(i));
|
||||
this.board[r][c].resetChangeFlag();
|
||||
}
|
||||
this.setCheckDiags(alsoCheckDiags);
|
||||
return console.log('Board loaded.');
|
||||
};
|
||||
|
||||
SudokuBoard.prototype.setCheckDiags = function(newValue) {
|
||||
return this.checkDiags = newValue;
|
||||
};
|
||||
|
||||
SudokuBoard.prototype.cellAt = function(r, c) {
|
||||
return this.board[r][c];
|
||||
};
|
||||
|
||||
SudokuBoard.prototype.resetChangeFlags = function() {
|
||||
var c, r, _i, _j, _ref, _ref1;
|
||||
for (r = _i = 0, _ref = this.dim2; _i < _ref; r = _i += 1) {
|
||||
for (c = _j = 0, _ref1 = this.dim2; _j < _ref1; c = _j += 1) {
|
||||
this.cellAt(r, c).resetChangeFlag();
|
||||
}
|
||||
for ( var i=0;i<boardString.length; i++ ) {
|
||||
var r = Math.floor( i / this.dim2 );
|
||||
var c = i % this.dim2;
|
||||
this.board[r][c].setValue( boardString.charAt(i) );
|
||||
this.board[r][c].resetChangeFlag();
|
||||
}
|
||||
this.checkDiags = ( alsoCheckDiags );
|
||||
console.log( 'Board loaded.' );
|
||||
}
|
||||
}
|
||||
return this.changed = false;
|
||||
};
|
||||
|
||||
this.setCheckDiags = function( newValue ) {
|
||||
this.checkDiags = ( newValue );
|
||||
}
|
||||
SudokuBoard.prototype.hasChanged = function() {
|
||||
return this.changed;
|
||||
};
|
||||
|
||||
this.cellAt = function( r, c ) {
|
||||
return this.board[r][c];
|
||||
}
|
||||
|
||||
this.resetChangeFlags = function() {
|
||||
for ( var r=0; r<this.dim2; r++ ) {
|
||||
for ( var c=0; c<this.dim2; c++ ) {
|
||||
this.cellAt( r, c ).resetChangeFlag();
|
||||
SudokuBoard.prototype.print = function() {
|
||||
var body, c, cssclass, cssclasses, html, m, mask, r, testm, value, _i, _j, _k, _ref, _ref1, _ref2;
|
||||
html = '';
|
||||
html += '<table class="sudoku">';
|
||||
for (r = _i = 0, _ref = this.dim2; _i < _ref; r = _i += 1) {
|
||||
html += '<tr>';
|
||||
for (c = _j = 0, _ref1 = this.dim2; _j < _ref1; c = _j += 1) {
|
||||
cssclass = '';
|
||||
cssclasses = [];
|
||||
if (r % this.dim === 0) {
|
||||
cssclasses.push('tborder');
|
||||
}
|
||||
if (c % this.dim === 0) {
|
||||
cssclasses.push('lborder');
|
||||
}
|
||||
if (this.cellAt(r, c).hasChanged()) {
|
||||
cssclasses.push('changed');
|
||||
}
|
||||
value = this.cellAt(r, c).getValue();
|
||||
if (value === '.') {
|
||||
value = '';
|
||||
mask = this.cellAt(r, c).getMask();
|
||||
for (m = _k = 0, _ref2 = this.dim2; 0 <= _ref2 ? _k < _ref2 : _k > _ref2; m = 0 <= _ref2 ? ++_k : --_k) {
|
||||
testm = 1 << m;
|
||||
if (testm & mask) {
|
||||
value += '<div class="hint-square hint' + (m + 1) + '"></div>';
|
||||
}
|
||||
}
|
||||
cssclasses.push('mask' + mask);
|
||||
}
|
||||
if (cssclasses.length > 0) {
|
||||
cssclass = ' class="' + cssclasses.join(' ') + '"';
|
||||
}
|
||||
html += "<td" + cssclass + ">" + value + "</td>";
|
||||
}
|
||||
this.changed = false;
|
||||
}
|
||||
html += '</tr>';
|
||||
}
|
||||
html += '</table>';
|
||||
body = document.getElementsByTagName('body');
|
||||
return body[0].innerHTML += html;
|
||||
};
|
||||
|
||||
this.hasChanged = function() {
|
||||
return this.changed;
|
||||
}
|
||||
return SudokuBoard;
|
||||
|
||||
this.print = function() {
|
||||
var html = '';
|
||||
html += '<table class="sudoku">';
|
||||
for ( var r=0; r<this.dim2; r++ ) {
|
||||
html += '<tr>';
|
||||
for ( var c=0; c<this.dim2; c++ ) {
|
||||
cssclass = '';
|
||||
if ( r%this.dim == 0 ) cssclass = 'tborder';
|
||||
if ( c%this.dim == 0 ) cssclass += ' lborder';
|
||||
if ( this.cellAt( r, c).hasChanged() ) cssclass += ' changed';
|
||||
if ( cssclass.length > 0 ) cssclass = ' class="' + cssclass + '"';
|
||||
background = '';
|
||||
value = this.cellAt( r, c ).getValue();
|
||||
if ( value == '.' ) {
|
||||
background = ' background="cellMask.php?dim=' + this.dim + '&mask=' + this.cellAt(r,c).getMask();
|
||||
if ( this.cellAt( r, c ).hasChanged() ) background += '&changed=1';
|
||||
background += '"';
|
||||
value = '';
|
||||
}
|
||||
html += '<td' + cssclass + background + '>' + value + '</td>';
|
||||
}
|
||||
html += '</tr>';
|
||||
}
|
||||
html += '</table>';
|
||||
var body = document.getElementsByTagName( 'body' );
|
||||
body[0].innerHTML += html;
|
||||
}
|
||||
}
|
||||
})();
|
||||
|
||||
}).call(this);
|
||||
|
@ -1,59 +1,75 @@
|
||||
function SudokuCell( initVal, boardObj ) {
|
||||
this.boardObj = boardObj;
|
||||
this.changed = false;
|
||||
this.value = 0;
|
||||
this.set = ( 1 << this.boardObj.dim2 ) - 1; // all
|
||||
|
||||
this.setMask = function( newSet ) {
|
||||
if ( newSet != this.set ) {
|
||||
this.set = newSet;
|
||||
this.changed = true;
|
||||
this.boardObj.changed = true;
|
||||
}
|
||||
// Generated by CoffeeScript 1.6.3
|
||||
(function() {
|
||||
this.SudokuCell = (function() {
|
||||
function SudokuCell(initVal, boardObj) {
|
||||
this.boardObj = boardObj;
|
||||
this.changed = false;
|
||||
this.value = 0;
|
||||
this.set = (1 << this.boardObj.dim2) - 1;
|
||||
this.setValue(initVal);
|
||||
}
|
||||
|
||||
this.setValue = function( newValue ) {
|
||||
if ( newValue == this.value ) return false;
|
||||
setidx = this.boardObj.set.indexOf( newValue );
|
||||
if ( setidx != -1 ) {
|
||||
this.value = newValue;
|
||||
this.setMask( 1 << setidx );
|
||||
this.changed = true;
|
||||
this.boardObj.changed = true;
|
||||
return true;
|
||||
} else if ( newValue == -1 ) {
|
||||
this.value = 0;
|
||||
this.setMask( ( 1 << this.boardObj.dim2 ) - 1 ); // all
|
||||
this.changed = true;
|
||||
this.boardObj.changed = true;
|
||||
}
|
||||
SudokuCell.prototype.setMask = function(newSet) {
|
||||
if (newSet !== this.set) {
|
||||
this.set = newSet;
|
||||
this.changed = true;
|
||||
return this.boardObj.changed = true;
|
||||
}
|
||||
};
|
||||
|
||||
SudokuCell.prototype.setValue = function(newValue) {
|
||||
var setidx;
|
||||
if (newValue === this.value) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
setidx = this.boardObj.set.indexOf(newValue);
|
||||
if (setidx !== -1) {
|
||||
this.value = newValue;
|
||||
this.setMask(1 << setidx);
|
||||
this.changed = true;
|
||||
this.boardObj.changed = true;
|
||||
return true;
|
||||
} else if (newValue === -1) {
|
||||
this.value = 0;
|
||||
this.setMask((1 << this.boardObj.dim2) - 1);
|
||||
this.changed = true;
|
||||
this.boardObj.changed = true;
|
||||
}
|
||||
return false;
|
||||
};
|
||||
|
||||
this.setValue( initVal ); // init cell
|
||||
SudokuCell.prototype.getValue = function() {
|
||||
if (this.value === 0) {
|
||||
return '.';
|
||||
}
|
||||
return this.value;
|
||||
};
|
||||
|
||||
this.getValue = function() {
|
||||
if ( this.value == 0 ) return '.';
|
||||
return this.value;
|
||||
}
|
||||
SudokuCell.prototype.getMask = function() {
|
||||
return this.set;
|
||||
};
|
||||
|
||||
this.getMask = function() {
|
||||
return this.set;
|
||||
}
|
||||
|
||||
this.getUnknownsCount = function() {
|
||||
var result = 0;
|
||||
for (var n=0; n<this.boardObj.dim2; n++) {
|
||||
if ( (1 << n) & this.set ) result++;
|
||||
SudokuCell.prototype.getUnknownsCount = function() {
|
||||
var n, result, _i, _ref;
|
||||
result = 0;
|
||||
for (n = _i = 0, _ref = this.boardObj.dim2; _i < _ref; n = _i += 1) {
|
||||
if ((1 << n) & this.set) {
|
||||
result++;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
}
|
||||
return result;
|
||||
};
|
||||
|
||||
this.hasChanged = function() {
|
||||
return this.changed;
|
||||
}
|
||||
SudokuCell.prototype.hasChanged = function() {
|
||||
return this.changed;
|
||||
};
|
||||
|
||||
this.resetChangeFlag = function() {
|
||||
this.changed = false;
|
||||
}
|
||||
}
|
||||
SudokuCell.prototype.resetChangeFlag = function() {
|
||||
return this.changed = false;
|
||||
};
|
||||
|
||||
return SudokuCell;
|
||||
|
||||
})();
|
||||
|
||||
}).call(this);
|
||||
|
@ -1,93 +1,113 @@
|
||||
var SudokuChecks = {
|
||||
// Generated by CoffeeScript 1.6.3
|
||||
(function() {
|
||||
this.SudokuChecks = (function() {
|
||||
function SudokuChecks() {}
|
||||
|
||||
'unique' : function( board, r, c ) {
|
||||
var set = ~board.cellAt( r, c).getMask();
|
||||
|
||||
// row / column / diagonale
|
||||
for ( var i=0; i<board.dim2; i++) {
|
||||
if ( i != c ) { // row
|
||||
board.cellAt( r, i ).setMask( board.cellAt( r, i ).getMask() & set );
|
||||
}
|
||||
if ( i != r ) { // column
|
||||
board.cellAt( i, c ).setMask( board.cellAt( i, c ).getMask() & set );
|
||||
}
|
||||
if ( board.checkDiags ) {
|
||||
if ( r == c && i != r ) { // diagonale \
|
||||
board.cellAt( i, i ).setMask( board.cellAt( i, i ).getMask() & set );
|
||||
}
|
||||
if ( r == board.dim2-c-1 && i != r ) { // diagonale /
|
||||
board.cellAt( i, board.dim2-i-1 ).setMask ( board.cellAt( i, board.dim2-i-1 ).getMask() & set );
|
||||
}
|
||||
}
|
||||
SudokuChecks.unique = function(board, r, c) {
|
||||
var cb, i, j, rb, set, _i, _j, _k, _ref, _ref1, _ref2;
|
||||
set = ~board.cellAt(r, c).getMask();
|
||||
for (i = _i = 0, _ref = board.dim2; _i < _ref; i = _i += 1) {
|
||||
if (i !== c) {
|
||||
board.cellAt(r, i).setMask(board.cellAt(r, i).getMask() & set);
|
||||
}
|
||||
|
||||
// square
|
||||
var rb = Math.floor( r / board.dim ) * board.dim; // row base for this square
|
||||
var cb = Math.floor( c / board.dim ) * board.dim; // col base for this square
|
||||
for ( var i=rb; i<rb+board.dim; i++ ) {
|
||||
for ( var j=cb; j<cb+board.dim; j++ ) {
|
||||
if ( i != r || j != c ) {
|
||||
board.cellAt( i, j ).setMask( board.cellAt( i, j ).getMask() & set );
|
||||
}
|
||||
}
|
||||
if (i !== r) {
|
||||
board.cellAt(i, c).setMask(board.cellAt(i, c).getMask() & set);
|
||||
}
|
||||
},
|
||||
|
||||
'onePlace' : function( cells ) {
|
||||
if ( !cells[0] ) return;
|
||||
for ( var i=0; i<cells[0].boardObj.dim2; i++ ) { // walk all possible values
|
||||
var n = 0;
|
||||
var p = (1 << i);
|
||||
var x = -1;
|
||||
for ( var k in cells ) {
|
||||
if ( ( cells[k].getValue() == '.' ) && ( p & cells[k].getMask() ) ) {
|
||||
n++;
|
||||
x = k;
|
||||
}
|
||||
}
|
||||
if ( n == 1 ) {
|
||||
cells[x].setMask( p );
|
||||
cells[x].setValue( cells[0].boardObj.set.charAt( Math.log(p)/Math.log(2) ) );
|
||||
}
|
||||
if (board.checkDiags) {
|
||||
if (r === c && i !== r) {
|
||||
board.cellAt(i, i).setMask(board.cellAt(i, i).getMask() & set);
|
||||
}
|
||||
if (r === board.dim2 - c - 1 && i !== r) {
|
||||
board.cellAt(i, board.dim2 - i - 1).setMask(board.cellAt(i, board.dim2 - i - 1).getMask() & set);
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
'oneUnknown' : function( cells ) {
|
||||
for ( var c in cells ) {
|
||||
if ( cells[c].getValue() == '.' && cells[c].getUnknownsCount() == 1 ) {
|
||||
var valid = cells[c].getMask();
|
||||
var val = cells[c].boardObj.set.charAt( Math.log( valid ) / Math.log( 2 ) );
|
||||
cells[c].setValue( val );
|
||||
}
|
||||
}
|
||||
rb = Math.floor(r / board.dim) * board.dim;
|
||||
cb = Math.floor(c / board.dim) * board.dim;
|
||||
for (i = _j = rb, _ref1 = rb + board.dim; _j < _ref1; i = _j += 1) {
|
||||
for (j = _k = cb, _ref2 = cb + board.dim; _k < _ref2; j = _k += 1) {
|
||||
if (i !== r || j !== c) {
|
||||
board.cellAt(i, j).setMask(board.cellAt(i, j).getMask() & set);
|
||||
}
|
||||
}
|
||||
},
|
||||
}
|
||||
return true;
|
||||
};
|
||||
|
||||
'twoValPlaces' : function( cells ) {
|
||||
if ( !cells[0] ) return;
|
||||
console.group( 'twoValPlaces: %o', cells );
|
||||
for ( var i=0; i<cells[0].boardObj.dim2-1; i++ ) { // walk all possible 2s combinations
|
||||
for ( var j=i+1; j<cells[0].boardObj.dim2; j++ ) {
|
||||
var n = 0;
|
||||
var p = (1 << i) | (1 << j);
|
||||
console.log( 'Now checking mask: %o', p );
|
||||
for ( var k in cells ) {
|
||||
if ( ( cells[k].getValue() == '.' ) && ( cells[k].getMask() & p == p ) ) {
|
||||
n++;
|
||||
console.log( '%d: %d, %d (%o, %o)', n, p, cells[k].getMask(), ( p & cells[k].getMask() ), ( ( p & cells[k].getMask() ) == p ) );
|
||||
}
|
||||
}
|
||||
if ( n > 0 ) console.info( 'Have %d matches.', n );
|
||||
if ( n == 2 ) {
|
||||
for ( var k in cells ) {
|
||||
if ( ( cells[k].getValue() == '.' ) && ( cells[k].getMask() == p ) ) {
|
||||
cells[k].setMask( p );
|
||||
} else if ( cells[k].getValue() == '.' ) {
|
||||
cells[k].setMask( cells[k].getMask() & ~p );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
SudokuChecks.onePlace = function(cells) {
|
||||
var i, k, n, p, x, _i, _ref;
|
||||
if (!cells[0]) {
|
||||
return;
|
||||
}
|
||||
for (i = _i = 0, _ref = cells[0].boardObj.dim2; _i < _ref; i = _i += 1) {
|
||||
n = 0;
|
||||
p = 1 << i;
|
||||
x = -1;
|
||||
for (k in cells) {
|
||||
if (cells[k].getValue() === '.' && (p & cells[k].getMask())) {
|
||||
n++;
|
||||
x = k;
|
||||
}
|
||||
}
|
||||
console.groupEnd();
|
||||
}
|
||||
};
|
||||
if (n === 1) {
|
||||
cells[x].setMask(p);
|
||||
cells[x].setValue(cells[0].boardObj.set.charAt(Math.log(p) / Math.log(2)));
|
||||
}
|
||||
}
|
||||
return true;
|
||||
};
|
||||
|
||||
SudokuChecks.oneUnknown = function(cells) {
|
||||
var c, val, valid;
|
||||
for (c in cells) {
|
||||
if (cells[c].getValue() === '.' && cells[c].getUnknownsCount() === 1) {
|
||||
valid = cells[c].getMask();
|
||||
val = cells[c].boardObj.set.charAt(Math.log(valid) / Math.log(2));
|
||||
cells[c].setValue(val);
|
||||
}
|
||||
}
|
||||
return true;
|
||||
};
|
||||
|
||||
SudokuChecks.twoValPlaces = function(cells) {
|
||||
var dim2, i, j, k, n, p, _i, _j, _ref, _ref1;
|
||||
if (!cells[0]) {
|
||||
return;
|
||||
}
|
||||
dim2 = cells[0].boardObj.dim2;
|
||||
console.group('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;
|
||||
p = (1 << i) | (1 << j);
|
||||
console.log('Now checking (%o, %o) mask: %o', i + 1, j + 1, p);
|
||||
for (k in cells) {
|
||||
if (cells[k].getValue() === '.' && cells[k].getMask() & p === p) {
|
||||
n++;
|
||||
console.log('%d: %d, %d (%o, %o)', n, p, cells[k].getMask(), p & cells[k].getMask(), (p & cells[k].getMask()) === p);
|
||||
}
|
||||
}
|
||||
if (n > 0) {
|
||||
console.info('Have %d matches.', n);
|
||||
}
|
||||
if (n === 2) {
|
||||
console.warn('Two matches!');
|
||||
for (k in cells) {
|
||||
if (cells[k].getValue() === '.' && cells[k].getMask() === p) {
|
||||
cells[k].setMask(p);
|
||||
} else if (cells[k].getValue() === '.') {
|
||||
cells[k].setMask(cells[k].getMask() & ~p);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
console.groupEnd();
|
||||
return true;
|
||||
};
|
||||
|
||||
return SudokuChecks;
|
||||
|
||||
})();
|
||||
|
||||
}).call(this);
|
||||
|
@ -1,132 +1,186 @@
|
||||
var SudokuSolver = {
|
||||
// Generated by CoffeeScript 1.6.3
|
||||
(function() {
|
||||
this.SudokuSolver = (function() {
|
||||
function SudokuSolver() {}
|
||||
|
||||
'uniqueAll' : function( board ) {
|
||||
for ( var r=0; r<board.dim2; r++ ) {
|
||||
for ( var c=0; c<board.dim2; c++ ) {
|
||||
if ( board.cellAt( r, c ).getValue() != '.' ) {
|
||||
SudokuChecks.unique( board, r, c );
|
||||
}
|
||||
}
|
||||
SudokuSolver.uniqueAll = function(board) {
|
||||
var c, r, _i, _j, _ref, _ref1;
|
||||
for (r = _i = 0, _ref = board.dim2; _i < _ref; r = _i += 1) {
|
||||
for (c = _j = 0, _ref1 = board.dim2; _j < _ref1; c = _j += 1) {
|
||||
if (board.cellAt(r, c).getValue() !== '.') {
|
||||
SudokuChecks.unique(board, r, c);
|
||||
}
|
||||
}
|
||||
},
|
||||
}
|
||||
return true;
|
||||
};
|
||||
|
||||
// returns all cells for the square of the specified cell
|
||||
'getSquareCellsForCell' : function( board, r, c ) {
|
||||
var sqrid = Math.floor( r / board.dim ) * board.dim + Math.floor( c / board.dim );
|
||||
return this.getSquareCells( board, sqrid );
|
||||
},
|
||||
SudokuSolver.getSquareCellsForCell = function(board, r, c) {
|
||||
var sqrid;
|
||||
sqrid = Math.floor(r / board.dim) * board.dim + Math.floor(c / board.dim);
|
||||
return this.getSquareCells(board, sqrid);
|
||||
};
|
||||
|
||||
'getSquareCells' : function( board, squareid ) {
|
||||
var result = new Array();
|
||||
var rb = Math.floor( squareid / board.dim ) * board.dim; // base row for square
|
||||
var cb = squareid % board.dim * board.dim; // base col for square
|
||||
for ( var i=0; i<board.dim2; i++ ) {
|
||||
result.push( board.cellAt( rb+Math.floor( i/board.dim ), cb+(i % board.dim) ) );
|
||||
SudokuSolver.getSquareCells = function(board, squareid) {
|
||||
var cb, i, rb, result, _i, _ref;
|
||||
result = [];
|
||||
rb = Math.floor(squareid / board.dim) * board.dim;
|
||||
cb = squareid % board.dim * board.dim;
|
||||
for (i = _i = 0, _ref = board.dim2; _i < _ref; i = _i += 1) {
|
||||
result.push(board.cellAt(rb + Math.floor(i / board.dim), cb + (i % board.dim)));
|
||||
}
|
||||
return result;
|
||||
};
|
||||
|
||||
SudokuSolver.getRowCells = function(board, row) {
|
||||
var i, result, _i, _ref;
|
||||
result = [];
|
||||
for (i = _i = 0, _ref = board.dim2; _i < _ref; i = _i += 1) {
|
||||
result.push(board.cellAt(row, i));
|
||||
}
|
||||
return result;
|
||||
};
|
||||
|
||||
SudokuSolver.getColCells = function(board, col) {
|
||||
var i, result, _i, _ref;
|
||||
result = [];
|
||||
for (i = _i = 0, _ref = board.dim2; _i < _ref; i = _i += 1) {
|
||||
result.push(board.cellAt(i, col));
|
||||
}
|
||||
return result;
|
||||
};
|
||||
|
||||
SudokuSolver.runAllRows = function(board, func) {
|
||||
var i, rowcells, _i, _ref, _results;
|
||||
_results = [];
|
||||
for (i = _i = 0, _ref = board.dim2; _i < _ref; i = _i += 1) {
|
||||
rowcells = this.getRowCells(board, i);
|
||||
_results.push(SudokuChecks[func](rowcells));
|
||||
}
|
||||
return _results;
|
||||
};
|
||||
|
||||
SudokuSolver.runAllColumns = function(board, func) {
|
||||
var colcells, i, _i, _ref, _results;
|
||||
_results = [];
|
||||
for (i = _i = 0, _ref = board.dim2; _i < _ref; i = _i += 1) {
|
||||
colcells = this.getColCells(board, i);
|
||||
_results.push(SudokuChecks[func](colcells));
|
||||
}
|
||||
return _results;
|
||||
};
|
||||
|
||||
SudokuSolver.runAllSquares = function(board, func) {
|
||||
var i, sqrcells, _i, _ref, _results;
|
||||
_results = [];
|
||||
for (i = _i = 0, _ref = board.dim2; _i < _ref; i = _i += 1) {
|
||||
sqrcells = this.getSquareCells(board, i);
|
||||
_results.push(SudokuChecks[func](sqrcells));
|
||||
}
|
||||
return _results;
|
||||
};
|
||||
|
||||
SudokuSolver.runBothDiags = function(board, func) {
|
||||
var diag1, diag2, i, _i, _ref;
|
||||
if (!board.checkDiags) {
|
||||
return;
|
||||
}
|
||||
diag1 = [];
|
||||
diag2 = [];
|
||||
for (i = _i = 0, _ref = board.dim2; _i < _ref; i = _i += 1) {
|
||||
diag1.push(board.cellAt(i, i));
|
||||
diag2.push(board.cellAt(i, board.dim2 - i - 1));
|
||||
}
|
||||
SudokuChecks[func](diag1);
|
||||
return SudokuChecks[func](diag2);
|
||||
};
|
||||
|
||||
SudokuSolver.oneUnknownAll = function(board) {
|
||||
var c, cells, r, _i, _j, _ref, _ref1;
|
||||
cells = [];
|
||||
for (r = _i = 0, _ref = board.dim2; _i < _ref; r = _i += 1) {
|
||||
for (c = _j = 0, _ref1 = board.dim2; _j < _ref1; c = _j += 1) {
|
||||
cells.push(board.cellAt(r, c));
|
||||
}
|
||||
return result;
|
||||
},
|
||||
}
|
||||
return SudokuChecks.oneUnknown(cells);
|
||||
};
|
||||
|
||||
'getRowCells' : function( board, row ) {
|
||||
var result = new Array();
|
||||
for ( var i=0; i<board.dim2; i++ ) {
|
||||
result.push( board.cellAt( row, i ) );
|
||||
SudokuSolver.onePlaceRow = function(board) {
|
||||
return this.runAllRows(board, 'onePlace');
|
||||
};
|
||||
|
||||
SudokuSolver.onePlaceColumn = function(board) {
|
||||
return this.runAllColumns(board, 'onePlace');
|
||||
};
|
||||
|
||||
SudokuSolver.onePlaceSquare = function(board) {
|
||||
return this.runAllSquares(board, 'onePlace');
|
||||
};
|
||||
|
||||
SudokuSolver.onePlaceDiag = function(board) {
|
||||
return this.runBothDiags(board, 'onePlace');
|
||||
};
|
||||
|
||||
SudokuSolver.twoValPlacesSquare = function(board) {
|
||||
return this.runAllSquares(board, 'twoValPlaces');
|
||||
};
|
||||
|
||||
SudokuSolver.twoValPlacesRow = function(board) {
|
||||
return this.runAllRows(board, 'twoValPlaces');
|
||||
};
|
||||
|
||||
SudokuSolver.twoValPlacesColumn = function(board) {
|
||||
return this.runAllColumns(board, 'twoValPlaces');
|
||||
};
|
||||
|
||||
SudokuSolver.twoValPlacesDiag = function(board) {
|
||||
return this.runBothDiags(board, 'twoValPlaces');
|
||||
};
|
||||
|
||||
SudokuSolver.solveBoard = function(board) {
|
||||
var body, c, checks, description, i;
|
||||
checks = {
|
||||
'uniqueAll': 'Value must be unique in row, column' + (board.checkDiags ? ', square and diagonales.' : ' and square.'),
|
||||
'onePlaceSquare': 'Value has only one place in square.',
|
||||
'onePlaceRow': 'Value has only one place in row.',
|
||||
'onePlaceColumn': 'Value has only one place in column.',
|
||||
'onePlaceDiag': 'Value has only one place in diagonale.',
|
||||
'twoValPlacesSquare': 'Only two possible places for pair in square.',
|
||||
'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.'
|
||||
};
|
||||
i = 1;
|
||||
while (true) {
|
||||
console.time('Checking board.');
|
||||
board.resetChangeFlags();
|
||||
description = '';
|
||||
for (c in checks) {
|
||||
description = checks[c];
|
||||
this[c](board);
|
||||
if (board.hasChanged()) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
return result;
|
||||
},
|
||||
|
||||
'getColCells' : function( board, col ) {
|
||||
var result = new Array();
|
||||
for ( var i=0; i<board.dim2; i++ ) {
|
||||
result.push( board.cellAt( i, col ) );
|
||||
if (board.hasChanged()) {
|
||||
console.info('Board was changed by "%s".', description);
|
||||
body = document.getElementsByTagName('body');
|
||||
body[0].innerHTML += i + '. ' + description + '<br />';
|
||||
board.print();
|
||||
}
|
||||
return result;
|
||||
},
|
||||
|
||||
'runAllRows' : function( board, func ) {
|
||||
for ( var i=0; i<board.dim2; i++ ) { // walk all rows
|
||||
var rowcells = this.getRowCells( board, i );
|
||||
SudokuChecks[func]( rowcells );
|
||||
i++;
|
||||
console.timeEnd('Checking board.');
|
||||
if (!(board.hasChanged() && i < 100)) {
|
||||
break;
|
||||
}
|
||||
},
|
||||
}
|
||||
return 0;
|
||||
};
|
||||
|
||||
'runAllColumns' : function( board, func ) {
|
||||
for ( var i=0; i<board.dim2; i++ ) { // walk all columns
|
||||
var colcells = this.getColCells( board, i );
|
||||
SudokuChecks[func]( colcells );
|
||||
}
|
||||
},
|
||||
return SudokuSolver;
|
||||
|
||||
'runAllSquares' : function( board, func ) {
|
||||
for ( var i=0; i<board.dim2; i++ ) { // walk all squares
|
||||
var sqrcells = this.getSquareCells( board, i );
|
||||
SudokuChecks[func]( sqrcells );
|
||||
}
|
||||
},
|
||||
})();
|
||||
|
||||
'runBothDiags' : function( board, func ) {
|
||||
if ( !board.checkDiags ) return;
|
||||
var diag1 = new Array();
|
||||
var diag2 = new Array();
|
||||
for ( var i=0; i<board.dim2; i++ ) {
|
||||
diag1.push( board.cellAt( i, i ) );
|
||||
diag2.push( board.cellAt( i, board.dim2-i-1 ) );
|
||||
}
|
||||
SudokuChecks[func]( diag1 );
|
||||
SudokuChecks[func]( diag2 );
|
||||
},
|
||||
|
||||
'oneUnknownAll' : function( board ) {
|
||||
var cells = new Array();
|
||||
for ( var r=0; r<board.dim2; r++ ) {
|
||||
for ( var c=0; c<board.dim2; c++ ) {
|
||||
cells.push( board.cellAt( r, c ) );
|
||||
}
|
||||
}
|
||||
SudokuChecks.oneUnknown( cells );
|
||||
},
|
||||
|
||||
'onePlaceRow' : function( board ) { this.runAllRows( board, 'onePlace' ); },
|
||||
'onePlaceColumn' : function( board ) { this.runAllColumns( board, 'onePlace' ); },
|
||||
'onePlaceSquare' : function( board ) { this.runAllSquares( board, 'onePlace' ); },
|
||||
'onePlaceDiag' : function( board ) { this.runBothDiags( board, 'onePlace' ); },
|
||||
'twoValPlacesSquare' : function( board ) { this.runAllSquares( board, 'twoValPlaces' ); },
|
||||
'twoValPlacesRow' : function( board ) { this.runAllRows( board, 'twoValPlaces' ); },
|
||||
'twoValPlacesColumn' : function( board ) { this.runAllColumns( board, 'twoValPlaces' ); },
|
||||
'twoValPlacesDiag' : function( board ) { this.runBothDiags( board, 'twoValPlaces' ); },
|
||||
|
||||
'solveBoard' : function( board ) {
|
||||
var checks = {
|
||||
'uniqueAll': 'Value must be unique in row, column' + ((board.checkDiags)?', square and diagonales.':' and square.'),
|
||||
'onePlaceSquare': 'Value has only one place in square.',
|
||||
'onePlaceRow': 'Value has only one place in row.',
|
||||
'onePlaceColumn': 'Value has only one place in column.',
|
||||
'onePlaceDiag': 'Value has only one place in diagonale.',
|
||||
'twoValPlacesSquare': 'Only two possible places for pair in square.',
|
||||
'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.'
|
||||
};
|
||||
|
||||
var i = 1;
|
||||
do {
|
||||
console.time( 'Checking board.' );
|
||||
board.resetChangeFlags();
|
||||
var description = '';
|
||||
for ( var c in checks ) {
|
||||
description = checks[c];
|
||||
this[c]( board );
|
||||
if ( board.hasChanged() ) break;
|
||||
}
|
||||
if ( board.hasChanged() ) {
|
||||
console.info( 'Board was changed by "%s".', description );
|
||||
var body = document.getElementsByTagName( 'body' );
|
||||
body[0].innerHTML += i + '. ' + description + '<br />';
|
||||
board.print();
|
||||
}
|
||||
i++;
|
||||
console.timeEnd( 'Checking board.' );
|
||||
} while ( board.hasChanged() && i<100);
|
||||
}
|
||||
|
||||
};
|
||||
}).call(this);
|
||||
|
Reference in New Issue
Block a user