Rubyでぷよぷよ19連鎖
http://okajima.air-nifty.com/b/2011/01/2011-ffac.html にある、連鎖するプログラムを書けというやつ。
大きな方針として、最初から以下のようにすべきだった。オブジェクトは各種状態を1つだけ表現するようにして、次々と状態が隣接状態を作るという。やっぱりオブジェクト指向がよく分からない。データと手続きを一緒にまとめられるので、やっぱり自分自身を書き換えたくなるように思うんだけど、それは非常に良くない感じがする。そう言われてみれば、Rubyの標準ライブラリではビックリマークのある破壊的メソッドは少数派だし、あまり使う気がしないのだった。同様に、自分でクラスを作るときもそうすればいいだけなのか。インスタンスメソッドの最後で、ThatSameClass.newを返すというのを何となくあまり見ないような気がするんだけど、なぜだろうか。
途中で機能を足したからコンストラクタが汚い。こうやってファクトリパターンは生まれたのかと思った。
class Board attr_accessor :height, :width, :state, :new_state def initialize(text_or_state) case text_or_state when String @text = text_or_state @state = [] @text.each_line do |l| next if l =~ /^$/ @state << l.chomp.split(//) end when Array @state = text_or_state end @new_state = Marshal.load(Marshal.dump(@state)) @height = @state.size @width = @state.map(&:size).max visited_reset end def visited_reset @visited = Array.new(@height) {Array.new(@width, "o")} end def remove @state.each do |y| y.map!{|c| c == "#" ? " ":c} end Board.new(@state) end def fall new_line = [] @new_state = Array.new(@height) {Array.new(@width, " ")} (0..(@width - 1)).each do |x| (0..(@height - 1)).to_a.reverse.each do |y| next if @state[y][x] == " " new_line << @state[y][x] end (0..(@height - 1)).to_a.reverse.each do |y| break if new_line.size == 0 @new_state[y][x] = new_line.shift end end Board.new(@new_state) end def all_delete (0..(@height - 1)).each do |y| (0..(@width - 1)).each do |x| delete(y, x) end end if !@new_state.flatten.include?("#") nil else Board.new(@new_state) end end private def delete(y, x) return if @state[y][x] == "#" same = find_same(y, x, []) visited_reset if same.size >= 4 same.each do |pos| @new_state[pos[0]][pos[1]] = "#" end end end def find_same(y, x, pos) pos << [y, x] @visited[y][x] = "." col = @state[y][x] return pos if col == " " if (y > 0) && (@visited[y - 1][x] != ".") && (@state[y - 1][x] == col) find_same(y - 1, x, pos) end if (y < @height - 1) && (@visited[y + 1][x] != ".") && (@state[y + 1][x] == col) find_same(y + 1, x, pos) end if (x > 0) && (@visited[y][x - 1] != ".") && (@state[y][x - 1] == col) find_same(y, x - 1, pos) end if (x < @width - 1) && (@visited[y][x + 1] != ".") && (@state[y][x + 1] == col) find_same(y, x + 1, pos) end pos end def to_s @state.inject(""){|s, l| s += ((l.join) + "\n")} + "-" * @width end end b = Board.new(File.open(ARGV.shift).read) rensa = 0 p b; sleep 1 loop do b = b.all_delete break if b.nil? p b; sleep 0.3 b = b.remove p b; sleep 0.3 b = b.fall p b; sleep 0.3 rensa += 1 end print "rensa: #{rensa}\n"
ファクトリパターンで書き換えると、こんな感じか。
class BoardFactory def self.create(text_or_state) case text_or_state when String text = text_or_state state = [] text.each_line do |l| next if l =~ /^$/ state << l.chomp.split(//) end when Array state = text_or_state end Board.new(state) end end class Board attr_accessor :height, :width, :state, :new_state def initialize(state) @state = state @new_state = Marshal.load(Marshal.dump(@state)) @height = @state.size @width = @state.map(&:size).max visited_reset end : : b = BoardFactory.create(File.open(ARGV.shift).read)
% cat p2.txt GYRR RYYGYG GYGYRR RYGYRG YGYRYG GYRYRG YGYRYR YGYRYR YRRGRG RYGYGG GRYGYR GRYGYR GRYGYR % ruby puyo.rb p2.txt GYRR RYYGYG GYGYRR RYGYRG YGYRYG GYRYRG YGYRYR YGYRYR YRRGRG RYGYGG GRYGYR GRYGYR GRYGYR ------ GYRR R##GYG G#GYRR R#GYRG YGYRYG GYRYRG YGYRYR YGYRYR YRRGRG RYGYGG GRYGYR GRYGYR GRYGYR ------ GYRR R GYG G GYRR R GYRG YGYRYG GYRYRG YGYRYR YGYRYR YRRGRG RYGYGG GRYGYR GRYGYR GRYGYR ------ YRR R GGYG G GYRR R GYRG YGYRYG GYRYRG YGYRYR YGYRYR YRRGRG RYGYGG GRYGYR GRYGYR GRYGYR ------ YRR R ##YG G #YRR R #YRG YGYRYG GYRYRG YGYRYR YGYRYR YRRGRG RYGYGG GRYGYR GRYGYR GRYGYR ------ YRR R YG G YRR R YRG YGYRYG GYRYRG YGYRYR YGYRYR YRRGRG RYGYGG GRYGYR GRYGYR GRYGYR ------ RR R YYG G YRR R YRG YGYRYG GYRYRG YGYRYR YGYRYR YRRGRG RYGYGG GRYGYR GRYGYR GRYGYR ------ RR R ##G G #RR R #RG YGYRYG GYRYRG YGYRYR YGYRYR YRRGRG RYGYGG GRYGYR GRYGYR GRYGYR ------ RR R G G RR R RG YGYRYG GYRYRG YGYRYR YGYRYR YRRGRG RYGYGG GRYGYR GRYGYR GRYGYR ------ R R RG G RR R RG YGYRYG GYRYRG YGYRYR YGYRYR YRRGRG RYGYGG GRYGYR GRYGYR GRYGYR ------ R R #G G ## R #G YGYRYG GYRYRG YGYRYR YGYRYR YRRGRG RYGYGG GRYGYR GRYGYR GRYGYR ------ R R G G R G YGYRYG GYRYRG YGYRYR YGYRYR YRRGRG RYGYGG GRYGYR GRYGYR GRYGYR ------ R R G G R G YGYRYG GYRYRG YGYRYR YGYRYR YRRGRG RYGYGG GRYGYR GRYGYR GRYGYR ------ R R G # R # YGYRY# GYRYR# YGYRYR YGYRYR YRRGRG RYGYGG GRYGYR GRYGYR GRYGYR ------ R R G R YGYRY GYRYR YGYRYR YGYRYR YRRGRG RYGYGG GRYGYR GRYGYR GRYGYR ------ R G R YGYRY GYRYRR YGYRYR YGYRYR YRRGRG RYGYGG GRYGYR GRYGYR GRYGYR ------ R G R YGYRY GYRY## YGYRY# YGYRY# YRRGRG RYGYGG GRYGYR GRYGYR GRYGYR ------ R G R YGYRY GYRY YGYRY YGYRY YRRGRG RYGYGG GRYGYR GRYGYR GRYGYR ------ R G R YGYR GYRYY YGYRY YGYRY YRRGRG RYGYGG GRYGYR GRYGYR GRYGYR ------ R G R YGYR GYR## YGYR# YGYR# YRRGRG RYGYGG GRYGYR GRYGYR GRYGYR ------ R G R YGYR GYR YGYR YGYR YRRGRG RYGYGG GRYGYR GRYGYR GRYGYR ------ R G R YGY GYRR YGYR YGYR YRRGRG RYGYGG GRYGYR GRYGYR GRYGYR ------ R G R YGY GY## YGY# YGY# YRRGRG RYGYGG GRYGYR GRYGYR GRYGYR ------ R G R YGY GY YGY YGY YRRGRG RYGYGG GRYGYR GRYGYR GRYGYR ------ R G R YG GYY YGY YGY YRRGRG RYGYGG GRYGYR GRYGYR GRYGYR ------ R G R YG G## YG# YG# YRRGRG RYGYGG GRYGYR GRYGYR GRYGYR ------ R G R YG G YG YG YRRGRG RYGYGG GRYGYR GRYGYR GRYGYR ------ R G R Y GG YG YG YRRGRG RYGYGG GRYGYR GRYGYR GRYGYR ------ R G R Y ## Y# Y# YRRGRG RYGYGG GRYGYR GRYGYR GRYGYR ------ R G R Y Y Y YRRGRG RYGYGG GRYGYR GRYGYR GRYGYR ------ R G R Y Y Y YRRGRG RYGYGG GRYGYR GRYGYR GRYGYR ------ R G R # # # #RRGRG RYGYGG GRYGYR GRYGYR GRYGYR ------ R G R RRGRG RYGYGG GRYGYR GRYGYR GRYGYR ------ R G RRRGRG RYGYGG GRYGYR GRYGYR GRYGYR ------ R G ###GRG #YGYGG GRYGYR GRYGYR GRYGYR ------ R G GRG YGYGG GRYGYR GRYGYR GRYGYR ------ R GRG GYGYGG GRYGYR GRYGYR GRYGYR ------ R GRG #YGYGG #RYGYR #RYGYR #RYGYR ------ R GRG YGYGG RYGYR RYGYR RYGYR ------ GRG YGYGG RYGYR RYGYR RRYGYR ------ GRG YGYGG #YGYR #YGYR ##YGYR ------ GRG YGYGG YGYR YGYR YGYR ------ GRG GYGG YGYR YGYR YYGYR ------ GRG GYGG #GYR #GYR ##GYR ------ GRG GYGG GYR GYR GYR ------ GRG YGG GYR GYR GGYR ------ GRG YGG #YR #YR ##YR ------ GRG YGG YR YR YR ------ RG GG YR GYR YYR ------ RG GG #R G#R ##R ------ RG GG R G R R ------ G G R RR GGR ------ G G # ## GG# ------ G G GG ------ G GGG ------ # ### ------ ------ ------ rensa: 19