《付録》othello.py

# -*- coding: utf-8 -*-
#===============================================================================
#    Copyright (C) 2000-2008, 小泉ひよ子とタマゴ倶楽部
#
# History: Othello Game
#    1988/05, Smalltalk
#    2004/09, Java
#    2005/02, C#
#    2005/03, Jython
#===============================================================================

#===============================================================================
#    配列と別れる50の方法
#===============================================================================
from game import *

#===============================================================================
class OthelloFrame(DefaultFrame):
    def initialize(self):
        self.panel = OthelloPanel()
        
    def initializeComponent(self):
        self.layout = BorderLayout()
        self.add(self.panel, BorderLayout.CENTER)

#===============================================================================
class OthelloPanel(GameBoardPanel):
    dim = 8
    black = False
    white = not black
    
    def __init__ (self):
        GameBoardPanel.__init__(self)
        self.mode = self.black
        
    def locateItems(self):
        points = [(x, y)
            for y in range(-1, self.dim+1)
            for x in range(-1, self.dim+1)]
        for x, y in points:
            self.items.append(NullStone(x, y, None))
        self.place(Stone(3, 3, self.white))
        self.place(Stone(3, 4, self.black))
        self.place(Stone(4, 3, self.black))
        self.place(Stone(4, 4, self.white))

    def prepare(self):
        self.__class__.itemExtent = (
            self.width/self.dim, self.height/self.dim)

    def this_mouseClicked(self, e):
        stone = self.detectStone(e)
        print ">>> %s"%stone
        if stone: return

        self.reversed = False
        self.reverse(stone)
        if not self.reversed: return
        
        self.place(Stone(stone.x, stone.y, self.mode))
        self.mode = not self.mode
        self.repaint()

    def detectStone(self, e):
        return self.detect(
            self.dim*e.x/self.width, 
            self.dim*e.y/self.height)

    def nullObject(self):
        return nullStone
                    
    def reverse(self, stone):
        bounds = [(x, y)
            for x in range(-1, 2)
            for y in range(-1, 2)]
        for x, y in bounds:
            e = self.detect(stone.x+x, stone.y+y)
            if e.state == (not self.mode):
                self.reverseStones(e, x, y)

    def reverseStones(self, stone, x, y):
        stones = [stone]
        for i in range(1, self.dim):
            e = self.detect(stone.x+x*i, stone.y+y*i)
            if e.state == None:
                stones = []; break
            if e.state == self.mode:
                break
            if e.state == (not self.mode):
                stones.append(e)
        if not stones: return
        for e in stones:
            e.state = self.mode
        self.reversed = True
        print stones
        
    def place(self, stone):
        null = self.detect(stone.x, stone.y)
        self.items.remove(null)
        self.items.append(stone)

#===============================================================================
class Stone(GameItem):
    def __init__(self, x, y, state):
        GameItem.__init__(self, x, y)
        self.state = state
        
    def __repr__(self):
        if self.state == None:
            s = self.state
        else:
            s = ("black", "white")[not self.state]
        return "(%s,%s)"%(GameItem.__repr__(self), s)
    
    def __nonzero__(self): return True

    def dim(self): return OthelloPanel.dim

    def paintBackground(self, g):
        width = self.width(g)
        height = self.height(g)
        x = self.x * width
        y = self.y * height
        g.color = Color.green
        g.fillRect(x, y, width, height)
        g.color = Color.black
        g.drawRect(x, y, width, height)

    def paintItem(self, g):
        width = self.width(g)
        height = self.height(g)
        x = self.x * width
        y = self.y * height
        color = (Color.black, Color.white)[self.state]
        g.color = color
        g.fillOval(x, y, width, height)
        g.color = Color.black
        g.drawOval(x, y, width, height)

class NullStone(Stone):
    def __nonzero__(self): return False
    def paintItem(self, g): pass
        
N = OthelloPanel.dim + 1
nullStone = NullStone(None, None, None)
        
#===============================================================================
def example():
    OthelloFrame("Othello", (200, 222))

#===============================================================================
from _jython2_ import *
signature("-", __file__, '1.0.1')
#===============================================================================