diff --git a/nikoli.rb b/nikoli.rb index 8a35645..4e422db 100755 --- a/nikoli.rb +++ b/nikoli.rb @@ -7,7 +7,7 @@ require 'coffee-script' require 'slim' require 'sass' -GAMES = %i{nurikabe sudoku} +GAMES = %i{hitori nurikabe sudoku} get('/application.css') { scss :application } get('/application.js') { coffee :application } diff --git a/views/application.scss b/views/application.scss index d16f334..b875c90 100644 --- a/views/application.scss +++ b/views/application.scss @@ -69,6 +69,12 @@ ul { background-color: #aaa; } +.hitori { + .black { + opacity: 0.1; + } +} + .sudoku { $sudoku-separation: 5px; diff --git a/views/hitori.coffee b/views/hitori.coffee new file mode 100644 index 0000000..645b099 --- /dev/null +++ b/views/hitori.coffee @@ -0,0 +1,93 @@ +window.Hitori = class Nurikabe + constructor: (@board) -> + @board.classList.add 'hitori' + + @grid = document.createElement 'div' + @grid.classList.add 'game-container' + @board.appendChild @grid + + buttons_div = document.createElement 'div' + buttons = {check: 'Check', reset: 'Reset', newgame: 'New game', help: '?'} + + for k,v of buttons + button = document.createElement 'button' + button.innerHTML = v + button.classList.add k + + buttons_div.appendChild button + + @board.appendChild buttons_div + + @board.querySelector('.check').addEventListener('click', @check.bind(this)) + @board.querySelector('.reset').addEventListener('click', @reset.bind(this)) + + check: -> + errors = @errors() + + if errors.length == 0 + alert 'Congratulations!' + else + alert errors.map((el) -> el.message).join() + + errors: -> + solution = @toArray() + errors = [] + processed_cells = [] + white_stream = new Nikoli.Stream(solution) + + for i in [0...solution.length] + row = solution[i] + for j in [0...row.length] + cell = solution[i][j] + + if cell >= 0 + white_stream.calculate({x: i, y: j}) if white_stream.empty() + + if !white_stream.include({x: i, y: j}) + errors.push {row: i, column: j, message: 'The stream must be continuous'} + # TODO check for duplicates in rows and columns + else + adjacent_cells = [ + {x: i+1, y: j}, + {x: i-1, y: j}, + {x: i, y: j+1}, + {x: i, y: j-1} + ] + if adjacent_cells.some((el) -> + 0 <= el.x < solution.length && 0 <= el.y < solution[el.x].length && solution[el.x][el.y] == -1) + errors.push {row: i, column: j, message: 'Adjacent filled-in cells'} + + errors + + generate: (game, solution = false) -> + @game = game if game? + @grid.innerHTML = @game.map((row) -> + '