腹立ちまぎれに

数独を解くナニを無理やり作ったら動いた。腹立ちまきれな上、相当に酔ってるんですが。
仕事な現実トウヒとして色々試してたんですが、動かなかったこれまでの試行錯誤は無駄ではなかったにせよ、何なんだという思いは強い。
# これはこれで腹立つな。(こらー

とりあえず、数え上げなナニでの手法はデキた (デキたのか?) ので、もう少し洗練されたアレな手法を試したいな、と。
# Solve Sudoku (Without even thinking!) ってカンジのナニ

読んでばかりだとストレスがタマる。crash 使ってみ、というエントリを発見しているんですが、もう少し現実逃避にハシる予定ッス。
で、とりあえずコードを晒してみる事にする。第一段階の総当たり方式。処理にかかる時間も結構かかっている模様。あと、速度的なナニは別として手を入れるトコは結構ありそうな感じなんですが、とりあえず。
基本的には、最初バージョンってコトで、OK, Sudokuになるべく手を入れない形で作成しています。あ、あと project.rb はOK, Sudokuと同じなので略します。

require 'project.rb'

class TC_MyTest < Test::Unit::TestCase

 def setup
 end

 def test_cells
   game = Game.test_game
   (0..80).each do | i |
     assert_equal(i, game.cell(i))
   end
 end

 def test_row_three
   game = Game.test_game
   assert_equal([27, 28, 29, 30, 31, 32, 33, 34, 35], game.row(3))
 end

 def test_row_eight
   game = Game.test_game
   assert_equal([72, 73, 74, 75, 76, 77, 78, 79, 80], game.row(8))
 end

 def test_column_three
   game = Game.test_game
   assert_equal([3, 12, 21, 30, 39, 48, 57, 66, 75], game.column(3))
 end

 def test_square_four
   game = Game.test_game
   assert_equal( [30, 31, 32, 39, 40, 41, 48, 49, 50], game.square(4))
 end

 def test_square_eight
   game = Game.test_game
   assert_equal( [60, 61, 62, 69, 70, 71, 78, 79, 80], game.square(8))
 end

 def data4test
   [nil, 6, nil, 1, nil, 4, nil, 5, nil,
    nil, nil, 8, 3, nil, 5, 6, nil, nil,
    2, nil, nil, nil, nil, nil, nil, nil, 1,
    8, nil, nil, 4, nil, 7, nil, nil, 6,
    nil, nil, 6, nil, nil, nil, 3, nil, nil,
    7, nil, nil, 9, nil, 1, nil, nil, 4,
    5, nil, nil, nil, nil, nil, nil, nil, 2,
    nil, nil, 7, 2, nil, 6, 9, nil, nil,
    nil, 4, nil, 5, nil, 8, nil, 7, nil]
 end

 def test_cells
   obj = Game::test_game

   tbl = []
   (0..80).each do | i |
     tbl << i
   end

   assert_equal(tbl, obj.cells)
 end

 def test_cells_init
   obj = Game.new
   assert(!obj.cells_init([]))

   obj.cells_init(data4test)
   assert_equal(data4test, obj.cells)
 end

 def test_row_integrate?
   obj = Game.new
   obj.cells_init(data4test)

   assert(obj.row_integrate?)

   tbl = data4test
   tbl[0] = 6
   obj.cells_init(tbl)
   assert_not_equal(obj.cells, data4test)
   assert(!obj.row_integrate?)
 end

 def test_col_integrate?
   obj = Game.new
   obj.cells_init(data4test)

   assert(obj.col_integrate?)

   tbl = data4test
   tbl[0] = 2
   obj.cells_init(tbl)
   assert_not_equal(obj.cells, data4test)
   assert(!obj.col_integrate?)
 end

 def test_square_integrate?
   obj = Game.new
   obj.cells_init(data4test)

   assert(obj.square_integrate?)

   tbl = data4test
   tbl[0] = 2
   obj.cells_init(tbl)
   assert_not_equal(obj.cells, data4test)
   assert(!obj.square_integrate?)
 end

 def test_integrate?
   obj = Game.new
   obj.cells_init(data4test)

   assert(obj.integrate?)

   tbl = data4test
   tbl[80] = 2
   obj.cells_init(tbl)
   assert_not_equal(obj.cells, data4test)
   assert(!obj.integrate?)

   tbl = data4test
   tbl[0] = 2
   obj.cells_init(tbl)
   assert_not_equal(obj.cells, data4test)
   assert(!obj.integrate?)

   tbl = data4test
   tbl[0] = 6
   obj.cells_init(tbl)
   assert_not_equal(obj.cells, data4test)
   assert(!obj.integrate?)
 end

 def test_nilElements
   obj = Game.new
   obj.cells_init(data4test)

   tbl = [0, 2, 4, 6, 8,
          9, 10, 13, 16, 17,
          19, 20, 21, 22, 23, 24, 25,
          28, 29, 31, 33, 34,
          36, 37, 39, 40, 41, 43, 44,
          46, 47, 49, 51, 52,
          55, 56, 57, 58, 59, 60, 61,
          63, 64, 67, 70, 71,
          72, 74, 76, 78, 80]

   assert_equal(tbl, obj.nilElements)
 end

 def test_candidacy
   obj = Game.new
   obj.cells_init(data4test)

   assert_equal([3, 9], obj.candidacy(0))
 end

 def test_getRowNumber
   obj = Game.new
   (0..80).each do | i |
     assert_equal(i / 9, obj.getRowNumber(i))
   end
 end

 def test_getColumnNumber
   obj = Game.new
   (0..80).each do | i |
     assert_equal(i % 9, obj.getColumnNumber(i))
   end
 end

 def test_getSquareNumber
   tbl = [0, 0, 0, 1, 1, 1, 2, 2, 2,
          0, 0, 0, 1, 1, 1, 2, 2, 2,
          0, 0, 0, 1, 1, 1, 2, 2, 2,
          3, 3, 3, 4, 4, 4, 5, 5, 5,
          3, 3, 3, 4, 4, 4, 5, 5, 5,
          3, 3, 3, 4, 4, 4, 5, 5, 5,
          6, 6, 6, 7, 7, 7, 8, 8, 8,
          6, 6, 6, 7, 7, 7, 8, 8, 8,
          6, 6, 6, 7, 7, 7, 8, 8, 8]

   obj = Game.new
   (0..80).each do | i |
     assert_equal(tbl[i], obj.getSquareNumber(i))
   end
 end

 def test_solve
   obj = Game.new
   obj.cells_init(data4test)

   obj.solve
   obj.output
 end

end

class Result
  attr_accessor :result_list

  def initialize
    @result_list = []
  end
end

class Game
 def initialize
   @result = Result.new
 end

 def Game::test_game
   game = Game.new
   game.test_game
   game
 end

 def test_game
   @cells = []
   for i in 0..80
     @cells.push i
   end
 end

 def cells_init(obj)
   @cells = Array.new(81)
   unless obj.size == 81
     return false
   end

   (0..80).each do | i |
     @cells[i] = obj[i]
   end
 end

 def cell(i)
   @cells[i]
 end

 def cells
   @cells.collect { | item | item }
 end

 def row(row_number)
   row_start = row_number*9
   @cells[row_start, 9]
 end

 def column(column_number)
   column_indexes(column_number).collect { | c | cell(c) }
 end

 def column_indexes(column_number)
   (0..8).collect { | row | column_number+row*9 }
 end

 def square(square_number)
   square_indexes(square_number).collect { | c | cell(c) }
 end

 def square_indexes(square_number)
   start_cell = start_cell(square_number)
   raw_square.collect { | offset | start_cell + offset }
 end

 def raw_square
   [0, 1, 2, 9, 10, 11, 18, 19, 20]
 end

 def start_cell(square_number)
   first_row = square_number / 3 * 3
   first_column = (square_number % 3) * 3
   first_row * 9 + first_column
 end

 def row_integrate?
   (0..8).each do | i |
     unless row(i).compact.size == row(i).compact.uniq.size
       return false
     end
   end
   true
 end

 def col_integrate?
   (0..8).each do | i |
     unless column(i).compact.size == column(i).compact.uniq.size
       return false
     end
   end
   true
 end

 def square_integrate?
   (0..8).each do | i |
     unless square(i).compact.size == square(i).compact.uniq.size
       return false
     end
   end
   true
 end

 def integrate?
   row_integrate? && col_integrate? && square_integrate?
 end

 def getRowNumber(idx)
   idx / 9
 end

 def getColumnNumber(idx)
   idx % 9
 end

 def getSquareNumber(idx)
   (idx / 3 % 3) + (idx / 27 * 3)
 end

 def fullElements
   [1, 2, 3, 4, 5, 6, 7, 8, 9]
 end

 def nilElements
   tbl = []
   @cells.each_with_index do | itm, idx |
     if itm == nil
       tbl << idx
     end
   end
   tbl
 end

 def candidacy(idx)
   tmp = fullElements - row(getRowNumber(idx))
   tmp -= column(getColumnNumber(idx))
   tmp -= square(getSquareNumber(idx))
 end

 def solve
   unless integrate?
     return
   else
     if nilElements == []
       @result.result_list << @cells
       return
     end
   end

   idx = nilElements.first
   candidacy(idx).collect do | item |
     tmp = self.dup
     cells = @cells
     cells[idx] = item
     tmp.cells_init(cells)
     tmp.solve
   end
 end

 def output
   @result.result_list.collect do | item |
     str = ""
     (0..80).each do |i|
       if 0 == i % 9
         p str
         str = ""
       end
       str += item[i].to_s + " "
     end
     p str
    end
 end

end 

識者のコメント求む。(って全然ダメ、とか強烈なダメが入りそうだなぁ)
output とか超手抜き。
あと、再起メソッドの test ってどうやって書くんでしょうね。