TENUKIS の回転チェック用スクリプト
回転法則を作り込もうと思ったら、ゲームの画面でやるのはちょい不便。
そこで、より簡易のチェックに便利なようにスクリプトを書きました。
チェックの手段としてはユニットテストを使うのも手なのですが、「この時こうなるはず」は抽象的にソースコードで定義するよりも、実際に回転させて見た方が判りやすいと思ったので、人力でチェックすることにしました。
ソースコードはこんな感じ ( public domain ) 。
# -*- coding:utf-8 -*- import pygame from pygame.locals import * from tenukis import * MINO_SET = [MinoT, MinoI, MinoO, MinoZ, MinoS, MinoL, MinoJ] def main(): pygame.init() # pygameの初期化 screen = pygame.display.set_mode( (150, 150) ) # 画面を作る pygame.display.set_caption('ROTATION CHECKER') # タイトル c = pygame.Color(128,128,128) screen.fill(c) field = [[None for i in range(7)] for j in range(6)] mino_of = 0 mino = (MINO_SET[mino_of])(field) mino.position = [0,0] while True: for event in pygame.event.get(): if (event.type == pygame.QUIT or (event.type == KEYDOWN and event.key == K_ESCAPE)): return elif event.type == KEYDOWN: if event.key == K_RIGHT: mino.move_r() elif event.key == K_LEFT: mino.move_l() elif event.key == K_UP: mino.position[1] -= 1 elif event.key == K_DOWN: mino.position[1] += 1 elif event.key == K_KP1: mino.rotate_l() elif event.key == K_KP2: mino.rotate_r() elif event.key == K_SPACE: mino_of = (mino_of +1) % len(MINO_SET) mino = (MINO_SET[mino_of])(field) elif event.type == MOUSEBUTTONDOWN: mp = [i/20 for i in event.pos] #event.pos から field座標に変換 field[mp[1]][mp[0]] = None if field[mp[1]][mp[0]] else 1 for line in xrange(len(field)): for masu in xrange(len(field[line])): if( field[line][masu] != None ): pygame.draw.rect(screen, (200,200,200), pygame.Rect( (20*masu, 20*line), (20, 20) )) else: pygame.draw.rect(screen, (0,0,0), pygame.Rect( (20*masu, 20*line), (20, 20) )) if mino: for block in mino.get_block_positions(): pygame.draw.rect(screen, (255,255,255), pygame.Rect( (20*block[0], 20*block[1]), (20,20))) pygame.display.flip() if __name__ == '__main__': main() # end of file
で、その結果、とりあえず回転ルールはこんな感じに。基底クラスを活かすようにしたので、割と書き換わってます。
class Mino: """ テトラミノの基底クラス """ blocks = None # blocksは左上を(0,0)とするブロックの配置 ( ( (x1,y1),(x2,y2)...),... ) の形式 appearance_at = (3,0) #出現場所 color_id = 1 def __init__(self, field): self.field = field self.position = [i for i in self.appearance_at] self.rotation = 0 #現在の回転位置 def get_blocks(self): """ 現在の回転位置に基づくblock """ return self.blocks[self.rotation] def get_block_positions(self): """ 現在の各blockのfield上の座標 """ return [(self.position[0]+block[0], self.position[1]+block[1]) for block in self.get_blocks()] def can_alive(self, blocks, position, field): """ position,blocks で定義されたブロック群が field で存在しうるか """ for block in blocks: p = (block[0]+position[0], block[1]+position[1]) if p[0]<0: return False try: b = field[p[1]][p[0]] if b != None: return False except IndexError: return False return True def rotate_r(self): """ selfを右回転させる。 """ if self.can_alive(self.blocks[(self.rotation+1)%len(self.blocks)], self.position, self.field): self.rotation = (self.rotation+1)%len(self.blocks) return True elif self.can_alive(self.blocks[(self.rotation+1)%len(self.blocks)], (self.position[0]+1, self.position[1]), self.field): self.position[0] += 1 self.rotation = (self.rotation+1)%len(self.blocks) return True elif self.can_alive(self.blocks[(self.rotation+1)%len(self.blocks)], (self.position[0]-1, self.position[1]), self.field): self.position[0] -= 1 self.rotation = (self.rotation+1)%len(self.blocks) return True else: return False def rotate_l(self): """ selfを左回転させる。 """ if self.can_alive(self.blocks[(self.rotation-1)%len(self.blocks)], self.position, self.field): self.rotation = (self.rotation-1)%len(self.blocks) return True elif self.can_alive(self.blocks[self.rotation-1], (self.position[0]+1, self.position[1]), self.field): self.position[0] += 1 self.rotation = (self.rotation-1)%len(self.blocks) return True elif self.can_alive(self.blocks[self.rotation-1], (self.position[0]-1, self.position[1]), self.field): self.position[0] -= 1 self.rotation = (self.rotation-1)%len(self.blocks) return True else: return False def move_r(self): if self.can_alive(self.blocks[self.rotation], (self.position[0]+1, self.position[1]), self.field): self.position[0] += 1 return True else: return False def move_l(self): if self.can_alive(self.blocks[self.rotation], (self.position[0]-1, self.position[1]), self.field): self.position[0] -= 1 return True else: return False def fall(self): fell = False # 1行でも落ちたか否か while self.can_alive( self.blocks[self.rotation], (self.position[0], self.position[1]+1), self.field): self.position[1] += 1 if not fell: fell = True return fell class MinoT(Mino): color_id = 0 blocks = (((0,1),(1,1),(2,1),(1,2)), #T ((1,0),(0,1),(1,1),(1,2)), ((1,1),(0,2),(1,2),(2,2)), ((1,0),(1,1),(2,1),(1,2))) #ト class MinoI(Mino): color_id = 1 blocks = (((0,1),(1,1),(2,1),(3,1)), ((2,0),(2,1),(2,2),(2,3))) def rotate_r(self): if self.can_alive(self.blocks[1-self.rotation], self.position, self.field): self.rotation = 1-self.rotation return True else: return False def rotate_l(self): return self.rotate_r() class MinoO(Mino): color_id = 2 appearance_at = (4,0) blocks = [[(0,0),(0,1),(1,0),(1,1)]] def rotate_r(self): return False def rotate_l(self): return False class MinoZ(Mino): color_id = 3 blocks = (((0,1),(1,1),(1,2),(2,2)), ((2,0),(1,1),(2,1),(1,2))) def rotate_r(self): if self.can_alive(self.blocks[1-self.rotation], self.position, self.field): self.rotation = 1-self.rotation return True elif self.can_alive(self.blocks[1-self.rotation], (self.position[0]-1,self.position[1]), self.field): self.position[0] -= 1 self.rotation = 1-self.rotation return True elif self.can_alive(self.blocks[1-self.rotation], (self.position[0]+1,self.position[1]), self.field): self.position[0] += 1 self.rotation = 1-self.rotation return True else: return False def rotate_l(self): return self.rotate_r() class MinoS(Mino): color_id = 4 blocks = (((1,1),(2,1),(0,2),(1,2)), ((0,0),(0,1),(1,1),(1,2))) def rotate_r(self): if self.can_alive(self.blocks[1-self.rotation], self.position, self.field): self.rotation = 1-self.rotation return True elif self.can_alive(self.blocks[1-self.rotation], (self.position[0]+1,self.position[1]), self.field): self.position[0] += 1 self.rotation = 1-self.rotation return True elif self.can_alive(self.blocks[1-self.rotation], (self.position[0]-1,self.position[1]), self.field): self.position[0] -= 1 self.rotation = 1-self.rotation return True else: return False def rotate_l(self): return self.rotate_r() class MinoL(Mino): color_id = 5 blocks = (((0,1),(1,1),(2,1),(0,2)), ((0,0),(1,0),(1,1),(1,2)), ((2,1),(0,2),(1,2),(2,2)), ((1,0),(1,1),(1,2),(2,2))) #L def rotate_r(self): if self.rotation == 0: if self.can_alive(self.blocks[1], self.position, self.field): self.rotation = 1 return True elif self.can_alive(self.blocks[1], (self.position[0]-1,self.position[1]), self.field): self.rotation = 1 self.position[0] -= 1 else: return False else: return Mino.rotate_r(self) def rotate_l(self): if self.rotation == 0: for i in xrange(3): if self.can_alive(self.blocks[3], (self.position[0]-i, self.position[1]), self.field): self.position[0] -= i self.rotation = 3 return True return False else: return Mino.rotate_l(self) class MinoJ(Mino): color_id = 6 blocks = (((0,1),(1,1),(2,1),(2,2)), ((1,0),(1,1),(0,2),(1,2)), # 」 ((0,1),(0,2),(1,2),(2,2)), ((1,0),(2,0),(1,1),(1,2))) #「 def rotate_r(self): if self.rotation == 0: for i in xrange(3): if self.can_alive(self.blocks[1], (self.position[0]+i, self.position[1]), self.field): self.position[0] += i self.rotation = 1 return True return False elif self.rotation == 3: if self.can_alive(self.blocks[0], self.position, self.field): self.rotation = 0 return True elif self.can_alive(self.blocks[3], (self.position[0]-1,self.position[1]), self.field): self.position[0] -= 1 self.rotation = 0 return True elif (self.can_alive(self.blocks[3], (self.position[0]+1,self.position[1]), self.field) and self.can_alive( [[2,2]], self.position, self.field )): self.position[0] += 1 self.rotation = 0 return True else: return False else: return Mino.rotate_r(self) def rotate_l(self): if self.rotation == 0: if self.can_alive(self.blocks[3], self.position, self.field): self.rotation = 3 return True elif self.can_alive(self.blocks[3], (self.position[0]+1,self.position[1]), self.field): self.rotation = 3 self.position[0] += 1 return True else: return False elif self.rotation == 1: if self.can_alive(self.blocks[0], self.position, self.field): self.rotation = 0 return True elif self.can_alive(self.blocks[0], (self.position[0]-1, self.position[1]), self.field): self.rotation = 0 self.position[0] -= 1 return True elif (self.can_alive(self.blocks[0], (self.position[0]+1, self.position[1]), self.field) and self.can_alive([[2,2]], self.position, self.field)): self.rotation = 0 self.position[0] += 1 return True else: return False else: return Mino.rotate_l(self)
で、試した動画がこんな感じ。