途中経過を表示しながら解くpentominoコマンドに仕上げる
前回までにc言語なら0.9秒(さらなる高速化を追記した)でペントミノパズル(6×10)の全解を出力できるようになった。1秒切ったので、高速化についてはこれで満足。しかし、何かまだ満たされないものがある。
最速を狙ったコマンドは1度試せばそれで満たされてしまう。たぶん、もう二度と実行することはなくなる。そうではなく、何度も使いたくなるpentominoコマンドにしておきたい。
追加する機能
使って楽しいコマンドを目指して、以下の機能を追加するのだ。
- 味気ないローマ字表現はやめて、カラフルなブロックにしたい。
- ブロックを置きながら試行錯誤する途中経過を見せたい。
- コマンドらしく、オプション指定やboardサイズも指定できるようにしておく。
面倒な処理がありそうなので使い慣れているRubyで書いてみる。
現状のコード
# coding: utf-8 BROW, BCOL = 10, 6 # すべてのピース形状をPieceオブジェクトの配列に保存する class Piece attr_accessor :used, :form, :loc_form, :letter def initialize(a, m, n, l) @used = false @form = [] @loc_form = [] @letter = l for i in (1..m) for j in (1..n) @form << [a, a.flatten.index(1)] a = a.transpose.reverse # rotate L end a = a.map(&:reverse) # flip LR end end end pp = [Piece.new([[0,1,0], [1,1,1], [0,1,0]], 1, 1, :X), Piece.new([[1,1,1], [1,0,1]] , 1, 4, :U), Piece.new([[1,1,0], [0,1,1], [0,0,1]], 1, 4, :W), Piece.new([[1,1,0], [0,1,1], [0,1,0]], 1, 2, :F), Piece.new([[1,1,0], [0,1,0], [0,1,1]], 2, 2, :Z), Piece.new([[1,1,1], [1,1,0]], 2, 4, :P), Piece.new([[1,1,1,0], [0,0,1,1]], 2, 4, :N), Piece.new([[1,1,1,1], [0,1,0,0]], 2, 4, :Y), Piece.new([[1,1,1], [0,1,0], [0,1,0]], 1, 4, :T), Piece.new([[1,1,1,1], [1,0,0,0]], 2, 4, :L), Piece.new([[1,1,1], [1,0,0], [1,0,0]], 1, 4, :V), Piece.new([[1,1,1,1,1]], 1, 2, :I)] pp.each_with_index do |piece, i| piece.form.each do |form| a = [] form[0].each_with_index do |row, r| row.each_with_index do |col, c| a << r * (BCOL + 1) + c - form[1] if col == 1 end end piece.loc_form << a end end # boardの初期化 board = Array.new((BROW + 1) * (BCOL + 1), 0) board.each_with_index do |b, i| board[i] = 100 if ((i + 1) % (BCOL + 1)) == 0 || i >= ((BCOL + 1) * BROW) end # パズルの解を求める def display_board(board, pp) $counter += 1 puts "No. #{$counter}" a = [] board.each_slice(BCOL + 1) do |line| a << line.reject {|i| i == 100}.map {|i| pp[i - 1].letter} end a[0..-2].transpose.each {|line| puts line.join} puts end def try_piece(board, pp, lvl) $try_counter += 1 x = board.index(0) pp.each_with_index do |piece, i| next if piece.used piece.loc_form.each do |blocks| next if board[x + blocks[0]]>0 || board[x + blocks[1]]>0 || board[x + blocks[2]]>0 || board[x + blocks[3]]>0 || board[x + blocks[4]]>0 # ピースを置く blocks.each {|b| board[x + b] = i + 1} piece.used = true # すべてのピースを置ききったらTrueを返す(recursiveコールの終了) if lvl == 11 then display_board(board, pp) # ピースを戻す blocks.each {|b| board[x + b] = 0} piece.used = false return end # 次のピースを試す try_piece(board, pp, lvl + 1) # ピースを戻す blocks.each {|b| board[x + b] = 0} piece.used = false end end end $counter = 0 $try_counter = 0 try_piece(board, pp, 0) puts "解合計: #{$counter}" puts "操作数: #{$try_counter}"
カラー表示
- ターミナルでカラー表示するためには、エスケープシーケンスで色を指定する必要がある。
- 例えば、以前jcalコマンドを作った時の色指定はこんな感じ。
$ ruby -e 'puts "\e[31mRed"' Red
- "\e[31m"の部分がエスケープシーケンスによる色の指定部分。
- 30-37の数値によって、8色の色が指定できる。
- ところが、今回のペントミノは全部で12ピースある。8色では足りない...。
- しかも、白と黒を除くと、使えるカラーは6色のみ。
- 減光の指定をすればどうにか12色の区別はできるが、色の選択の余地がない。
- カラフルにしたいのだけど、このままでは残念なカラーになりそうな予感...。
- 調べてみると、なんと今時のターミナルは256色表示に対応しているらしい!
- 以下のように指定すると、0-255の値でカラー指定ができる。
- 38は、フォアグラウンドカラーを意味し、(ちなみに、48=バックグラウンドカラーを意味する)
- 5は、0-255のカラーパレットコードを使うことを意味するようだ。
- 211は、ピンク色のカラーコード。
$ ruby -e 'puts "\e[38;5;211mPink"' Pink
- 256色すべてのカラーサンプルは、以下のワンライナーで出力された。
$ for c in {0..255}; do printf "\e[48;5;${c}m%8d\e[m" $c; done; echo
- これで色選択の自由は格段に向上した!自分好みの色を選択できそう。
- ピース形状をカラーブロックで表示するように変更してみた。
@@ -3,13 +3,14 @@ BROW, BCOL = 10, 6
# すべてのピース形状をPieceオブジェクトの配列に保存する
class Piece
- attr_accessor :used, :form, :loc_form, :letter
+ attr_accessor :used, :form, :loc_form, :letter, :color
- def initialize(a, m, n, l)
+ def initialize(a, m, n, l, c)
@used = false
@form = []
@loc_form = []
@letter = l
+ @color = c
for i in (1..m)
for j in (1..n)
@form << [a, a.flatten.index(1)]
@@ -20,18 +21,18 @@ class Piece
end
end
-pp = [Piece.new([[0,1,0], [1,1,1], [0,1,0]], 1, 1, :X),
- Piece.new([[1,1,1], [1,0,1]] , 1, 4, :U),
- Piece.new([[1,1,0], [0,1,1], [0,0,1]], 1, 4, :W),
- Piece.new([[1,1,0], [0,1,1], [0,1,0]], 1, 2, :F),
- Piece.new([[1,1,0], [0,1,0], [0,1,1]], 2, 2, :Z),
- Piece.new([[1,1,1], [1,1,0]], 2, 4, :P),
- Piece.new([[1,1,1,0], [0,0,1,1]], 2, 4, :N),
- Piece.new([[1,1,1,1], [0,1,0,0]], 2, 4, :Y),
- Piece.new([[1,1,1], [0,1,0], [0,1,0]], 1, 4, :T),
- Piece.new([[1,1,1,1], [1,0,0,0]], 2, 4, :L),
- Piece.new([[1,1,1], [1,0,0], [1,0,0]], 1, 4, :V),
- Piece.new(1,1,1,1,1, 1, 2, :I)]
+pp = [Piece.new([[0,1,0], [1,1,1], [0,1,0]], 1, 1, :X, 141),
+ Piece.new([[1,1,1], [1,0,1]] , 1, 4, :U, 6),
+ Piece.new([[1,1,0], [0,1,1], [0,0,1]], 1, 4, :W, 104),
+ Piece.new([[1,1,0], [0,1,1], [0,1,0]], 1, 2, :F, 172),
+ Piece.new([[1,1,0], [0,1,0], [0,1,1]], 2, 2, :Z, 211),
+ Piece.new([[1,1,1], [1,1,0]], 2, 4, :P, 70),
+ Piece.new([[1,1,1,0], [0,0,1,1]], 2, 4, :N, 121),
+ Piece.new([[1,1,1,1], [0,1,0,0]], 2, 4, :Y, 170),
+ Piece.new([[1,1,1], [0,1,0], [0,1,0]], 1, 4, :T, 42),
+ Piece.new([[1,1,1,1], [1,0,0,0]], 2, 4, :L, 3),
+ Piece.new([[1,1,1], [1,0,0], [1,0,0]], 1, 4, :V, 75),
+ Piece.new(1,1,1,1,1, 1, 2, :I, 217)]
pp.each_with_index do |piece, i|
piece.form.each do |form|
@@ -45,6 +46,8 @@ pp.each_with_index do |piece, i|
end
end
+BLOCK_COLOR = [250] + pp.map{|i| i.color} + [0]
+
# boardの初期化
@@ -55,13 +58,20 @@ end
+# エスケープシーケンス定義
+def bgcolor(nnn); "\e[48;5;#{nnn}m" ; end # 色指定の開始(nnn=0..255)
+def reset ; "\e[m" ; end # 色指定の終了
+
+# 出力コード生成
+def create_block(color); bgcolor(BLOCK_COLOR[color]) + " " + reset; end
+
# パズルの解を求める
def display_board(board, pp)
$counter += 1
puts "No. #{$counter}"
a = []
board.each_slice(BCOL + 1) do |line|
- a << line.reject {|i| i == 100}.map {|i| pp[i - 1].letter}
+ a << line.reject {|i| i == 100}.map {|i| create_block(i)}
end
a[0..-2].transpose.each {|line| puts line.join}
puts
カラーブロック表示の完了!
途中経過を見せる
- 途中経過を見せるには、pieceが置けたらその状態を出力すれば良いだけなので、以下のように変更してみた。
@@ -67,7 +67,6 @@ def create_block(color); bgcolor(BLOCK_COLOR[color]) + " " + reset; end
# パズルの解を求める
def display_board(board, pp)
- $counter += 1
puts "No. #{$counter}"
a = []
board.each_slice(BCOL + 1) do |line|
@@ -87,8 +86,10 @@ def try_piece(board, pp, lvl)
# ピースを置く
blocks.each {|b| board[x + b] = i + 1}
piece.used = true
+ display_board(board, pp)
# すべてのピースを置ききったらTrueを返す(recursiveコールの終了)
if lvl == 11 then
+ $counter += 1
display_board(board, pp)
# ピースを戻す
blocks.each {|b| board[x + b] = 0}
- しかし、これでは大量の途中経過によって、もの凄い速さでスクロールしてしまう...。
- 大量の途中経過の中に解が埋もれてしまって、肝心な解が見えなくなってしまう...。
途中経過の出力位置を固定する
- そこで、途中経過は位置を変えずに常に同じ位置で出力して、解が見つかった時だけ次の出力位置に移動するようにしたい。
- 通常、echoやputsで出力すると、出力位置は自動的に次の文字位置となるようにコントロールされている。
- 改行があれば、次の行の先頭に移動するようにコントロールされている。
- この出力位置を自分でコントロールできれば、途中経過の位置を変えずに常に同じ位置に出力できるのだ。
$ echo ABC; sleep 1; echo -e "\033[Axyz"
- \033[A の部分がエスケープシーケンス。
-
- A = 出力位置(カーソル位置)を1行上に移動する。
- 2行上に移動したい時は2Aと書く。
- 3行上に移動したい時は3Aと書く。
- 必要なエスケープシーケンスはあと二つ。
- \033[2J = 画面全体を消去、
- \033[H = 画面左上にカーソル移動。
- 以上のエスケープシーケンスを追加して、以下のように修正してみた。
@@ -59,23 +59,28 @@ end
# エスケープシーケンス定義
+def home ; "\e[H" ; end # カーソル位置を画面左上へ移動(ホームポジション)
+def clear(n=2) ; "\e[#{n}J" ; end # n=(0:画面先頭からカーソル位置まで消去, 1:カーソル位置から画面末尾まで消去, 2:画面全体を消去)
+def moveup(n) ; "\e[#{n}A" ; end # カーソルを上方向へn行移動
def bgcolor(nnn); "\e[48;5;#{nnn}m" ; end # 色指定の開始(nnn=0..255)
def reset ; "\e[m" ; end # 色指定の終了
# 出力コード生成
def create_block(color); bgcolor(BLOCK_COLOR[color]) + " " + reset; end
+def reset_screen ; home + clear ; end
+def next_screen ; "\n" * (BCOL + 2) ; end
-# パズルの解を求める
+# boardを表示
def display_board(board, pp)
- puts "No. #{$counter}"
+ puts moveup(BCOL + 1) + "No. #{$counter}"
a = []
board.each_slice(BCOL + 1) do |line|
a << line.reject {|i| i == 100}.map {|i| create_block(i)}
end
a[0..-2].transpose.each {|line| puts line.join}
- puts
end
+# パズルの解を求める
def try_piece(board, pp, lvl)
$try_counter += 1
x = board.index(0)
@@ -91,6 +96,7 @@ def try_piece(board, pp, lvl)
if lvl == 11 then
$counter += 1
display_board(board, pp)
+ puts next_screen
# ピースを戻す
blocks.each {|b| board[x + b] = 0}
piece.used = false
@@ -107,6 +113,7 @@ end
$counter = 0
$try_counter = 0
+puts reset_screen
try_piece(board, pp, 0)
puts "解合計: #{$counter}"
puts "操作数: #{$try_counter}"
コマンドオプションを解析する
- ここまで基本的な機能はほぼ完成したので、コマンドらしくオプション指定できるようにしておく。
- -qオプションは途中経過を表示しない指定。解だけを素早く出力してくれる。
- また、3から8の引数を指定することで、boardのサイズも変更できる。
- 3×20、4×15、5×12、6×10、7×9-3、8×8-4。
- 7×9-3、8×8-4は中央に穴が空いたドーナツ型のboard。
- 以上のオプション仕様にして、以下のように追記した。
@@ -1,5 +1,46 @@
+#!/usr/bin/ruby
# coding: utf-8
-BROW, BCOL = 10, 6
+
+require 'optparse'
+
+# オプション解析
+$options = {}
+OptionParser.new do |opt|
+ opt.banner = 'Usage: pentomino [options] [board size(3-8)]'
+ opt.on('-q', 'Hide progress putting a piece on board.(quiet mode)') {|v| $options[:quiet] = v}
+ opt.separator('')
+ opt.on('board size:',
+ ' [3] x 20',
+ ' [4] x 15',
+ ' [5] x 12',
+ ' [6] x 10 (Default)',
+ ' [7] x 9 - 3',
+ ' [8] x 8 - 4',
+ )
+ opt.separator('')
+ opt.on('example:',
+ ' 6 x 10 7 x 9 - 3 8 x 8 - 4',
+ '11 12 13 14 15 16 17 18 19 1A 11 12 13 14 15 16 17 18 19 11 12 13 14 15 16 17 18',
+ '21 22 23 24 25 26 27 28 29 2A 21 22 23 24 25 26 27 28 29 21 22 23 24 25 26 27 28',
+ '31 32 33 34 35 36 37 38 39 3A 31 32 33 34 35 36 37 38 39 31 32 33 34 35 36 37 38',
+ '41 42 43 44 45 46 47 48 49 4A 41 42 43 47 48 49 41 42 43 46 47 48',
+ '51 52 53 54 55 56 57 58 59 5A 51 52 53 54 55 56 57 58 59 51 52 53 56 57 58',
+ '61 62 63 64 65 66 67 68 69 6A 61 62 63 64 65 66 67 68 69 61 62 63 64 65 66 67 68',
+ ' 71 72 73 74 75 76 77 78 79 71 72 73 74 75 76 77 78',
+ ' 81 82 83 84 85 86 87 88',
+ )
+ begin
+ opt.parse!(ARGV)
+ BCOL = (ARGV[0] || 6).to_i
+ BROW = 64 / BCOL
+ raise "Invalid board size: #{BCOL}" if BCOL < 3 || 8 < BCOL
+ rescue => e
+ puts e
+ exit
+ end
+end
+
+
# すべてのピース形状をPieceオブジェクトの配列に保存する
class Piece
@@ -55,6 +96,8 @@ board = Array.new((BROW + 1) * (BCOL + 1), 0)
board.each_with_index do |b, i|
board[i] = 100 if ((i + 1) % (BCOL + 1)) == 0 || i >= ((BCOL + 1) * BROW)
end
+board[30], board[31], board[39], board[40] = 13, 13, 13, 13 if BCOL == 8
+board[27], board[35], board[43] = 13, 13, 13 if BCOL == 7
@@ -91,7 +134,7 @@ def try_piece(board, pp, lvl)
# ピースを置く
blocks.each {|b| board[x + b] = i + 1}
piece.used = true
- display_board(board, pp)
+ display_board(board, pp) if !$options[:quiet]
# すべてのピースを置ききったらTrueを返す(recursiveコールの終了)
if lvl == 11 then
$counter += 1
- 実行権限を追加して、ヘルプ表示してみた。
$ chmod a+x pentomino.rb $ ./pentomino.rb -h Usage: pentomino [options] [board size(3-8)] -q Hide progress putting a piece on board.(quiet mode) board size: [3] x 20 [4] x 15 [5] x 12 [6] x 10 (Default) [7] x 9 - 3 [8] x 8 - 4 example: 6 x 10 7 x 9 - 3 8 x 8 - 4 11 12 13 14 15 16 17 18 19 1A 11 12 13 14 15 16 17 18 19 11 12 13 14 15 16 17 18 21 22 23 24 25 26 27 28 29 2A 21 22 23 24 25 26 27 28 29 21 22 23 24 25 26 27 28 31 32 33 34 35 36 37 38 39 3A 31 32 33 34 35 36 37 38 39 31 32 33 34 35 36 37 38 41 42 43 44 45 46 47 48 49 4A 41 42 43 47 48 49 41 42 43 46 47 48 51 52 53 54 55 56 57 58 59 5A 51 52 53 54 55 56 57 58 59 51 52 53 56 57 58 61 62 63 64 65 66 67 68 69 6A 61 62 63 64 65 66 67 68 69 61 62 63 64 65 66 67 68 71 72 73 74 75 76 77 78 79 71 72 73 74 75 76 77 78 81 82 83 84 85 86 87 88
- ./pentomino.rb 引数なしで6×10のペントミノパズルを解き始める。
- ./pentomino.rb 8 とすれば、8×8-4のドーナツ型のペントミノパズルを解き始める。
- 途中経過を見せずに素早く解を知りたい時は、./pentomino.rb -q 8。
修正後のコード
- さらに幾つかの細々した修正をして、
* zariganitosh 37b694c 最初と最後にboardサイズを出力する
* zariganitosh 320cdce boardサイズの算出式を修正
* zariganitosh ecc0da9 display_boardにタイトル表示の引数を追加する
* zariganitosh 94c4616 8x8正方形のboardは90度回転対称の重複解も除外する
- 現在のコードは以下の姿になった。
#!/usr/bin/ruby # coding: utf-8 require 'optparse' # オプション解析 $options = {} OptionParser.new do |opt| opt.banner = 'Usage: pentomino [options] [board size(3-8)]' opt.on('-q', 'Hide progress putting a piece on board.(quiet mode)') {|v| $options[:quiet] = v} opt.separator('') opt.on('board size:', ' [3] x 20', ' [4] x 15', ' [5] x 12', ' [6] x 10 (Default)', ' [7] x 9 - 3', ' [8] x 8 - 4', ) opt.separator('') opt.on('example:', ' 6 x 10 7 x 9 - 3 8 x 8 - 4', '11 12 13 14 15 16 17 18 19 1A 11 12 13 14 15 16 17 18 19 11 12 13 14 15 16 17 18', '21 22 23 24 25 26 27 28 29 2A 21 22 23 24 25 26 27 28 29 21 22 23 24 25 26 27 28', '31 32 33 34 35 36 37 38 39 3A 31 32 33 34 35 36 37 38 39 31 32 33 34 35 36 37 38', '41 42 43 44 45 46 47 48 49 4A 41 42 43 47 48 49 41 42 43 46 47 48', '51 52 53 54 55 56 57 58 59 5A 51 52 53 54 55 56 57 58 59 51 52 53 56 57 58', '61 62 63 64 65 66 67 68 69 6A 61 62 63 64 65 66 67 68 69 61 62 63 64 65 66 67 68', ' 71 72 73 74 75 76 77 78 79 71 72 73 74 75 76 77 78', ' 81 82 83 84 85 86 87 88', ) begin opt.parse!(ARGV) BCOL = (ARGV[0] || 6).to_i BROW = (60.0 / BCOL).round raise "Invalid board size: #{BCOL}" if BCOL < 3 || 8 < BCOL rescue => e puts e exit end end # すべてのピース形状をPieceオブジェクトの配列に保存する class Piece attr_accessor :used, :form, :loc_form, :letter, :color def initialize(a, m, n, l, c) @used = false @form = [] @loc_form = [] @letter = l @color = c for i in (1..m) for j in (1..n) @form << [a, a.flatten.index(1)] a = a.transpose.reverse # rotate L end a = a.map(&:reverse) # flip LR end end end r = BCOL == 8 ? 1 : 2 pp = [Piece.new([[0,1,0], [1,1,1], [0,1,0]], 1, 1, :X, 141), Piece.new([[1,1,1], [1,0,1]] , 1, 4, :U, 6), Piece.new([[1,1,0], [0,1,1], [0,0,1]], 1, 4, :W, 104), Piece.new([[1,1,0], [0,1,1], [0,1,0]], 1, r, :F, 172), Piece.new([[1,1,0], [0,1,0], [0,1,1]], 2, 2, :Z, 211), Piece.new([[1,1,1], [1,1,0]], 2, 4, :P, 70), Piece.new([[1,1,1,0], [0,0,1,1]], 2, 4, :N, 121), Piece.new([[1,1,1,1], [0,1,0,0]], 2, 4, :Y, 170), Piece.new([[1,1,1], [0,1,0], [0,1,0]], 1, 4, :T, 42), Piece.new([[1,1,1,1], [1,0,0,0]], 2, 4, :L, 3), Piece.new([[1,1,1], [1,0,0], [1,0,0]], 1, 4, :V, 75), Piece.new([[1,1,1,1,1]], 1, 2, :I, 217)] pp.each_with_index do |piece, i| piece.form.each do |form| a = [] form[0].each_with_index do |row, r| row.each_with_index do |col, c| a << r * (BCOL + 1) + c - form[1] if col == 1 end end piece.loc_form << a end end BLOCK_COLOR = [250] + pp.map{|i| i.color} + [0] # boardの初期化 board = Array.new((BROW + 1) * (BCOL + 1), 0) board.each_with_index do |b, i| board[i] = 100 if ((i + 1) % (BCOL + 1)) == 0 || i >= ((BCOL + 1) * BROW) end board[30], board[31], board[39], board[40] = 13, 13, 13, 13 if BCOL == 8 board[27], board[35], board[43] = 13, 13, 13 if BCOL == 7 # エスケープシーケンス定義 def home ; "\e[H" ; end # カーソル位置を画面左上へ移動(ホームポジション) def clear(n=2) ; "\e[#{n}J" ; end # n=(0:画面先頭からカーソル位置まで消去, 1:カーソル位置から画面末尾まで消去, 2:画面全体を消去) def moveup(n) ; "\e[#{n}A" ; end # カーソルを上方向へn行移動 def bgcolor(nnn); "\e[48;5;#{nnn}m" ; end # 色指定の開始(nnn=0..255) def reset ; "\e[m" ; end # 色指定の終了 # 出力コード生成 def create_block(color); bgcolor(BLOCK_COLOR[color]) + " " + reset; end def reset_screen ; home + clear ; end def next_screen ; "\n" * (BCOL + 2) ; end # boardを表示 def display_board(board, pp, title='') puts moveup(BCOL + 1) + title a = [] board.each_slice(BCOL + 1) do |line| a << line.reject {|i| i == 100}.map {|i| create_block(i)} end a[0..-2].transpose.each {|line| puts line.join} end # パズルの解を求める def try_piece(board, pp, lvl) $try_counter += 1 x = board.index(0) pp.each_with_index do |piece, i| next if piece.used piece.loc_form.each do |blocks| next if board[x + blocks[0]]>0 || board[x + blocks[1]]>0 || board[x + blocks[2]]>0 || board[x + blocks[3]]>0 || board[x + blocks[4]]>0 # ピースを置く blocks.each {|b| board[x + b] = i + 1} piece.used = true display_board(board, pp) if !$options[:quiet] # すべてのピースを置ききったらTrueを返す(recursiveコールの終了) if lvl == 11 then $counter += 1 display_board(board, pp, "No. #{$counter} (TRY: #{$try_counter})") puts next_screen # ピースを戻す blocks.each {|b| board[x + b] = 0} piece.used = false return end # 次のピースを試す try_piece(board, pp, lvl + 1) # ピースを戻す blocks.each {|b| board[x + b] = 0} piece.used = false end end end $counter = 0 $try_counter = 0 puts reset_screen puts "Pentomino #{BCOL}x#{BROW}" puts next_screen try_piece(board, pp, 0) puts "Pentomino #{BCOL}x#{BROW}" puts "解合計: #{$counter}" puts "操作数: #{$try_counter}"
ひとまず完成。あとでgemに公開する予定。