Ruby で任意サイズの数独の解答例をやや真面目に作る

どうせやるならちゃんと作れという指令がきたので,仕方なくやや真面目にシャッフルするようにしてみた.長くなるからやだったのに.

# -*- coding: utf-8 -*-

def makeBoard(n)
  z = n * n
  arr = []
  seed = []

  # [1,2,3,....,z] という配列を作る
  (1..z).each do |x|
    seed.push x
    arr.push []
  end

  # 配列の中身を適当にシャッフルする
  (1..z*100).each do
    i = rand(z)
    j = rand(z)
    t = seed[i]
    seed[i] = seed[j]
    seed[j] = t
  end
  
  # seed を1行目として2行目以降を作る
  (0..z-1).each do |x|
    (0..z-1).each do |y|
      arr[x][y] = seed[(y + (x%n)*n + (x/n))%z]
    end
  end

  # 行をランダムに入れかえる (i..i+n-1の間)
  (1..z*100).each do
    i = rand(n)
    j = rand(n)
    k = rand(n)
    next if j == k
    l = i*n
    t = arr[l+j]
    arr[l+j] = arr[l+k]
    arr[l+k] = t
  end

  # n 行単位で行をランダムに入れかえる 
  (1..z*100).each do
    j = rand(n)
    k = rand(n)
    next if j == k
    (0..n-1).each do |y|
      t = arr[y+j*3]
      arr[y+j*3] = arr[y+k*3]
      arr[y+k*3] = t
    end
  end

  # 列をランダムに入れかえる (i..i+n-1の間)
  (1..z*100).each do
    i = rand(n)
    j = rand(n)
    k = rand(n)
    next if j == k
    (0..z-1).each do |x|
      l = i*n
      t = arr[x][l+j]
      arr[x][l+j] = arr[x][l+k]
      arr[x][l+k] = t
    end
  end

  # n 列単位で列をランダムに入れかえる
  (1..z*100).each do
    j = rand(n)
    k = rand(n)
    next if j == k
    (0..n-1).each do |y|
      (0..z-1).each do |x|
        t = arr[x][y+j*3]
        arr[x][y+j*3] = arr[x][y+k*3]
        arr[x][y+k*3] = t
      end
    end
  end
    
  return arr
end

arr = makeBoard 3
arr.each do |x|
  print x.join(',')
  print "\n"
end

これでもまだ規則性はのこる.たとえば下の例だと 7,4 が 3x3 のマスで見たとき,必ず同じ列にあらわれる.9, 8 とかもそう.他もそう.そうか,seed から 2 行目以降をつくるときにちょっと手を加えれば (ry

実行例 (3x3)

3,1,5,8,6,7,2,9,4
2,9,4,1,3,5,6,8,7
6,8,7,9,2,4,3,1,5
7,2,9,3,4,1,5,6,8
4,3,1,6,5,8,7,2,9
5,6,8,2,7,9,4,3,1
9,4,3,5,1,6,8,7,2
1,5,6,7,8,2,9,4,3
8,7,2,4,9,3,1,5,6