Edited at

ぷよぷよ

More than 1 year has passed since last update.

puyopuyo.gif

(beep(えいっ!) beep(ファイヤー) beep(アイスストーム) beep(ダイヤキュート) beep(ブレインダムド) beep(ジュゲム) beep(ばよえーん))

質素なテトリスと違い、ぷよぷよには可愛らしい絵や音がある

それらを取り除いた、ただのパズルゲームを作るのはそう難しくない

と思って作り始めると休日が終わっていた、ナンテコッタイ


おさらい

wikipedia


各作品によってルールの細部は異なる。ここでは基本的なルールのみを記す。

フィールドは縦12マス×横6マスの格子で構成される。格子の1マスにつき1個のブロック(ぷよぷよ略してぷよ)を置くことができる。ただし、上方向は、画面外に1マス分だけぷよを置くことができる。

上からぷよが2つ1組で落下してくる(「組ぷよ」と呼ばれる[注 4])。ぷよは種類ごとに色が異なり、色は3-5色(通常は4色)ある。プレイヤーはぷよに対して回転、横移動、高速落下のいずれかの操作を行う。

次に落下するぷよはフィールドの枠外にNEXTぷよとして予告される。配られるぷよの配分は麻雀のツモに例えられている。

落下してきたぷよがフィールドの床やほかのぷよに衝突すると、その位置にぷよが固定される。ただし、組ぷよを横にして置いたりなどして、ぷよに1マス分でも下方向に空白がある場合は、強制的にそのぷよだけ落下する。

固定されたぷよと同色の'ぷよ'が周囲4方向にいる場合、それらは互いにくっつく。

ぷよが4個以上くっつくと消滅し得点となる。

ぷよの消滅により上にあった'ぷよ'が落下する。このとき再びぷよが4個以上くっつくと消滅し、連鎖が起きる。なお、普通に4つ色を並べて消す行為だけでも1連鎖と考え、消滅した回数(○回)に応じて○連鎖と呼ばれる。複数色を同時に消した場合でも、1連鎖扱いとなる。

ぷよを消したときに入る得点は、消したぷよの数に、設定された「連鎖倍率」を掛けることで計算できる。

左から3列目が一番上まで埋まると"窒息して"ゲームオーバー。


今回はNEXTぷよとゲームオーバーは未実装、色は4色


PuyoPuyo

テトリス

これをベースにします

変更点は主に落下と消去

スコアやコンボ判定を追加

class PuyoPuyo 

attr_accessor :puyo, :board
def initialize(y,x)
@board = Array.new(y) { Array.new(x) { 0 } }
@puyo = rand_puyo
@score = 0
@comb = 0
end

def rand_puyo
[[rand(1..4), [0,@board.size[0]/2]], [rand(1..4), [1,@board.size[0]/2]]]
end

def move?(ps)
ps.all? do |y,x|
@board.size > y && 0 <= y ?
@board[y].size > x && 0 <= x ?
@board[y][x] == 0 :
false :
false
end
end

def rotate
r = Math::PI / 2
cy = @puyo.map { |c,(y,x)| y }.reduce(:+) / 2
cx = @puyo.map { |c,(y,x)| x }.reduce(:+) / 2
ps = @puyo.map do |c,(y,x)|
[
(cy + (x - cx) * Math.sin(r) + (y - cy) * Math.cos(r)).round,
(cx + (x - cx) * Math.cos(r) - (y - cy) * Math.sin(r)).round
]
end
p ps

if move?(ps)
@puyo[0][1] = ps[0]
@puyo[1][1] = ps[1]
end
end

def down
ps = @puyo.map { |c,(y,x)| [y + 1, x] }
if move?(ps)
@puyo[0][1] = ps[0]
@puyo[1][1] = ps[1]
end
end

def right
ps = @puyo.map { |c,(y,x)| [y, x + 1] }
if move?(ps)
@puyo[0][1] = ps[0]
@puyo[1][1] = ps[1]
end
end

def left
ps = @puyo.map { |c,(y,x)| [y, x - 1] }
if move?(ps)
@puyo[0][1] = ps[0]
@puyo[1][1] = ps[1]
end
end

def puyo_fall
ps = @puyo.map { |c,(y,x)| [y + 1, x] }
if move?(ps)
@puyo[0][1] = ps[0]
@puyo[1][1] = ps[1]
else
@board[@puyo[0][1][0]][@puyo[0][1][1]] = @puyo[0][0]
@board[@puyo[1][1][0]][@puyo[1][1][1]] = @puyo[1][0]
@puyo = rand_puyo
end
end

def board_fall
for y in (@board.size - 1).downto(0)
for x in 0 .. @board[y].size - 1
if @board[y][x] == 0
a = 0
for yy in y.downto(0)
if @board.size > yy && 0 <= yy && @board[yy][x] > 0
@board[y-a][x] = @board[yy][x]
@board[yy][x] = 0
a += 1
end
end
end
end
end
end

def board_delete
for y in 0 .. @board.size - 1
for x in 0 .. @board[y].size - 1
if @board[y][x] > 0
ss = [[y,x]]
ds = [[y,x]]
while !ss.empty?
sy,sx = ss.pop
for ay,ax in [[-1,0],[1,0],[0,-1],[0,1]]
yy = ay + sy
xx = ax + sx
if @board.size > yy && 0 <= yy && @board[yy].size > xx && 0 <= xx &&
@board[yy][xx] == @board[y][x] && !ds.any? { |a| a == [yy,xx] }
ss.push([yy,xx])
ds.push([yy,xx])
end
end
end

if ds.size >= 4
for dy,dx in ds
@board[dy][dx] = 0
end
@comb += 1
@score += ds.size * @comb
end
end
end
end
end

require "curses"
C = Curses

def controller(c)
case c
when "w"
rotate
when "s"
down
when "d"
right
when "a"
left
when "q"
C.close_screen
exit
else
nil
end
end

def display_init
C.init_screen
C.start_color
C.use_default_colors
C.noecho
C.curs_set(0)

[
C::COLOR_BLACK,
C::COLOR_RED,
C::COLOR_GREEN,
C::COLOR_YELLOW,
C::COLOR_BLUE,
].each.with_index do |c,i|
C.init_pair(i, C::COLOR_BLACK, c)
end
end

def display
C.clear
C.addstr("-" * (@board[0].size + 2))
C.addstr("\n")
for y in 0 .. @board.size - 1
C.addstr("|")
for x in 0 .. @board[y].size - 1
c = @puyo[0][1] == [y,x] ? @puyo[0][0] :
@puyo[1][1] == [y,x] ? @puyo[1][0] : @board[y][x]
C.attron(C.color_pair(c))
C.addstr(" ")
C.attroff(C.color_pair(c))
end
C.addstr("|")
C.addstr("\n")
end
C.addstr("-" * (@board[0].size + 2))
C.addstr("\nscore: #{@score}\ncomb: #{@comb}\n")
C.refresh
end

def run
display_init
display

m = Mutex.new

def delete
@comb = 0
c = @comb
board_delete
while @comb != c
#C.flash
C.beep
c = @comb
board_fall
display

sleep 0.5
board_delete
display
end
end

Thread.new do
loop do
sleep 1
m.synchronize do
puyo_fall
board_fall
display
sleep 0.5
delete
display
end
end
end

loop do
c = C.getch.to_s
m.synchronize do
controller(c)
board_fall
display
delete
display
end
end
end
end

pp = PuyoPuyo.new(12,6)

#board = <<END
#4
#1
#4
#32132
#21321
#321321
#321321
#344242
#423122
#142314
#142314
#142314
#END
#
#pp.puyo = [[1,[0,5]],[1,[1,5]]]
#
#bs = board.split(/\n/).map { |b| b.split(//) }
#bs.each_with_index do |b,y|
# b.each_with_index do |c,x|
# pp.board[y][x] = c.to_i
# end
#end
#

pp.run


end

cpu対戦やネットワーク対戦があるとだいぶ楽しくなりそう(作らない)