《付録》puzzle.py

# -*- coding: utf-8 -*-
#===============================================================================
#    Copyright (C) 2000-2008, 小泉ひよ子とタマゴ倶楽部
#
# History: 15 puzzle
#    1988/05, Smalltalk
#    1995/10, Objective-C
#    2000/12, Object Pascal
#    2004/09, Java
#    2005/02, C#
#    2005/03, Jython
#===============================================================================

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

#===============================================================================
class Puzzle15Frame(DefaultFrame):

    def initialize(self):
        self.panel = PuzzlePanel()

    def initializeComponent(self):
        self.layout = BorderLayout()
        self.add(self.panel)

#===============================================================================
class PuzzlePanel(GameBoardPanel):
    dim = 4
    dim2 = dim*dim

    def __init__(self):
        GameBoardPanel.__init__(self)
        self.shuffle(1000)

    def locateItems(self):
        for y in range(self.dim):
            for x in range(self.dim):
                value = x + y*self.dim + 1
                if value == self.dim2: break
                self.items.append(Tile(x, y, value))
        self.items.append(Null)

    def shuffle(self, count):
        for e in range(count):
            r = randint(0, self.dim2-1)
            self.detect(r%self.dim, r/self.dim).move()

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

    def this_mouseClicked(self, e):
        tile = self.detectTile(e)
        print ">>>", tile
        if tile.move(): self.repaint()

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

    def nullObject(self):
        return Null

#===============================================================================
class Tile(GameItem):

    def __init__(self, x, y, value):
        GameItem.__init__(self, x, y)
        self.value = value

    def __repr__(self):
        return "%r%s"%(`self.value`, GameItem.__repr__(self))

    def dim(self): return PuzzlePanel.dim

    def paintBackground(self, g):
        width = self.width(g)
        height = self.height(g)
        x = self.x*width;
        y = self.y*height;
        g.color = self.backgroundColor()
        g.fillRect(x, y, width, height)

    def backgroundColor(self):
        return Color.white

    def paintItem(self, g):
        width = self.width(g)
        height = self.height(g)
        x = self.x*width;
        y = self.y*height;
        g.color = Color.black
        g.drawRect(x, y, width, height)
        self.drawValue(g, x, y);

    def drawValue(self, g, x, y):
        g.drawString(`self.value`, x+10, y+20)

    def move(self):
        b = self.isInContactWith(Null)
        if b: self.swap()
        return b

    def isInContactWith(t1, t2):
        dx = t1.x - t2.x
        dy = t1.y - t2.y
        return dx*dx + dy*dy == 1

    def swap(self):
        self.x, Null.x = Null.x, self.x
        self.y, Null.y = Null.y, self.y

N = PuzzlePanel.dim - 1;
Null = Tile(N, N, 0)
Null.drawValue       = lambda g, x, y: None
Null.backgroundColor = lambda: Color.lightGray

#===============================================================================
def example():
    Puzzle15Frame("Puzzle 15", (200, 200))

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