wxPythonで簡単なオセロ
wxPythonで簡単なオセロを実装してみた。NPCなし。一人でぽちぽち遊ぶ。
UI部分が煩雑でちょっと面倒
# coding: utf-8 # wxPython Reversi game from copy import deepcopy WHITE = -1 BLANK = 0 BLACK = 1 class Reversi(object): def __init__(self): self.board = [[0]*8 for x in range(8)] self.board[3][3] = WHITE self.board[4][4] = WHITE self.board[3][4] = BLACK self.board[4][3] = BLACK self.turns = 1 # turn counter self.current = BLACK # current player self.nstone = [2, 60, 2] # white, blank, black self.nreversed = 0 self.passed = None self.over = False def __getitem__(self, i): return self.board[i] def stones(self, s): return self.nstone[1 + s] def reverseline(self, x, y, dx, dy): if not (0<=x<8) or not (0<=y<8): return False elif self[x][y] == BLANK: return False elif self[x][y] == self.current: return True elif self[x][y] == -self.current: ret = self.reverseline(x+dx, y+dy, dx, dy) if ret: self[x][y] *= -1 # reverse self.nreversed += 1 return ret def put(self, x, y, validation=False): if self.over or self[x][y] != BLANK: return False backup = self[x][y] self[x][y] = self.current self.nreversed = 0 for dx in [-1, 0, 1]: for dy in [-1, 0, 1]: self.reverseline(x+dx, y+dy, dx, dy) if self.nreversed == 0: self[x][y] = backup return False if validation: # despress changing state but only self.board return True self.nstone[1 + BLANK] -= 1 self.nstone[1 + self.current] += self.nreversed + 1 self.nstone[1 - self.current] -= self.nreversed self.turns += 1 self.current *= -1 # change turn # check game is over or not for s in [WHITE, BLANK, BLACK]: if self.stones(s) == 0: self.over = True return True for i in range(8): for j in range(8): if self.available(i, j): self.passed = None return True self.passed = self.current self.current *= -1 for i in range(8): for j in range(8): if self.available(i, j): return True self.current *= -1 self.over = True return True def available(self, x, y): if self.over: return False # backup board backup = deepcopy(self.board) ret = self.put(x, y, True) # restore board self.board = backup return ret import wx def notify(caption, message): dialog = wx.MessageDialog(None, message=message, caption=caption, style=wx.OK) dialog.ShowModal() dialog.Destroy() class Frame(wx.Frame): def __init__(self): wx.Frame.__init__(self, None, -1, "wxpyreversi") # panel self.panel = wx.Panel(self, size=(400,600)) self.panel.Bind(wx.EVT_LEFT_DOWN, self.tryput) self.panel.Bind(wx.EVT_PAINT, self.refresh) self.newgame(None) # menubar menu = wx.Menu() menu.Append(1, u"new game") menu.AppendSeparator() menu.Append(2, u"quit") menubar = wx.MenuBar() menubar.Append(menu, u"menu") self.SetMenuBar(menubar) self.Bind(wx.EVT_MENU, self.newgame, id=1) self.Bind(wx.EVT_MENU, self.quit, id=2) # status bar self.CreateStatusBar() # ban resize self.Bind(wx.EVT_SIZE, lambda e:e) def quit(self, event): self.Close() def newgame(self, event): # initialize reversi and refresh screen self.reversi = Reversi() self.panel.Refresh() def tryput(self, event): if self.reversi.over: return # calculate coordinate from window coordinate winx,winy = event.GetX(), event.GetY() w,h = self.panel.GetSize() x = winx / (w/8) y = winy / (h/8) if not self.reversi.available(x, y): return ret = self.reversi.put(x, y) self.panel.Refresh() # if game is over then display dialog if self.reversi.over: black = self.reversi.stones(BLACK) white = self.reversi.stones(WHITE) mes = "black: %d\nwhite: %d\n" % (black, white) if black == white: mes += "** draw **" else: mes += "winner: %s" % ["black", "white"][black < white] notify("game is over", mes) elif self.reversi.passed != None: notify("passing turn", "pass") def refresh(self, event): dc = wx.PaintDC(self.panel) self.SetStatusText("current player is " + ["White", "Black"][self.reversi.current==BLACK]) w,h = self.panel.GetSize() # background dc.SetBrush(wx.Brush("#228b22")) dc.DrawRectangle(0,0,w,h) # grid dc.SetBrush(wx.Brush("black")) px,py = w/8,h/8 for i in range(8): dc.DrawLine(i*px,0, i*px, h) dc.DrawLine(0, i*py, w, i*py) dc.DrawLine(w-1, 0, w-1, h-1) dc.DrawLine(0, h-1, w-1, h-1) # stones brushes = {WHITE: wx.Brush("white"), BLACK: wx.Brush("black")} for i in range(8): for j in range(8): c = self.reversi[i][j] if c != BLANK: dc.SetBrush(brushes[c]) dc.DrawEllipse(i*px, j*py, px, py) elif self.reversi.available(i, j): dc.SetBrush(wx.Brush("red")) dc.DrawCircle(i*px+px/2, j*py+py/2, 3) if __name__ == '__main__': app = wx.PySimpleApp() Frame().Show() app.MainLoop()