Initial Zeug
authormail <mail@joachim-breitner.de>
Fri, 27 Apr 2007 13:06:22 +0000 (13:06 +0000)
committermail <mail@joachim-breitner.de>
Fri, 27 Apr 2007 13:06:22 +0000 (13:06 +0000)
cairoboard.py [new file with mode: 0644]
engine.py [new file with mode: 0644]
ozeanien.py [new file with mode: 0644]

diff --git a/cairoboard.py b/cairoboard.py
new file mode 100644 (file)
index 0000000..b13aa0e
--- /dev/null
@@ -0,0 +1,358 @@
+#!/usr/bin/python
+
+
+import pygtk
+pygtk.require('2.0')
+import gtk
+import gobject
+import cairo
+import math
+import random
+
+# Constants
+
+GRIDWIDTH = 70
+SCALE = GRIDWIDTH/2
+GRIDPAD = 30
+
+PILE_X = 2 * GRIDPAD + 10 * GRIDWIDTH
+PILE_Y = 3 * GRIDWIDTH
+
+BH_X = 2 * GRIDPAD + 10*GRIDWIDTH
+BH_Y = 5 * GRIDWIDTH
+
+class CairoBoard(gtk.DrawingArea):
+    def __init__(self,board):
+        assert board
+        self.board = board
+
+        self.base_pixmap = None
+        self.hand_x = 0
+        self.hand_y = 0
+        
+        self.highlighted_slot = None
+
+        gtk.DrawingArea.__init__(self)
+        self.add_events(gtk.gdk.BUTTON_PRESS_MASK |
+                gtk.gdk.BUTTON_RELEASE_MASK |
+                gtk.gdk.LEAVE_NOTIFY_MASK |
+                gtk.gdk.EXPOSURE_MASK |
+                gtk.gdk.POINTER_MOTION_MASK)
+        self.connect_after("expose-event",self.do_expose_event)
+        self.connect("motion-notify-event",self.hover)
+
+        self.set_size_request(
+            2 * GRIDPAD + 9 * GRIDWIDTH + 2 * GRIDWIDTH,
+            2 * GRIDPAD + 6 * GRIDWIDTH
+        )
+        
+        self.reset()
+
+    def reset(self):
+        self.queue_draw()
+
+    def do_expose_event(self,widget,event):
+        gc = self.window.new_gc()
+        gc.set_clip_rectangle(event.area)
+        cr = self.window.cairo_create()
+        # set a clip region for the expose event
+        cr.rectangle(event.area.x, event.area.y, event.area.width, event.area.height)
+        cr.clip()
+
+        self.draw_board(self.board, self.window)
+
+    def hover(self, widget, event):
+        self.hand_x = event.x
+        self.hand_y = event.y
+        if not self.board.hand.is_empty():
+            self.queue_draw()
+
+        slot = self.event2slot(event)
+        if self.highlighted_slot and self.highlighted_slot != slot: 
+            self.highlighted_slot.highlighted = False
+            self.highlighted_slot = None
+            self.queue_draw()
+        if slot:
+            slot.highlighted = True
+            self.highlighted_slot = slot
+            self.queue_draw()
+
+
+    def pileclick(self, event):
+        return (2*abs(event.x - PILE_X) < GRIDWIDTH and
+                2*abs(event.y - PILE_Y + 3*SCALE) < GRIDWIDTH)
+
+    def pilerotclick(self, event):
+        return PILE_Y + GRIDWIDTH/2 <= event.y <= PILE_Y + GRIDWIDTH and\
+               PILE_X + GRIDWIDTH/4 <= event.x <= PILE_X + GRIDWIDTH 
+
+    def event2slot(self, event):
+        x = int((event.x - GRIDPAD) // GRIDWIDTH)
+        y = int((event.y - GRIDPAD) // GRIDWIDTH)
+        if 0 <= x < len(self.board.slots) and 0 <= y < len(self.board.slots[x]):
+            return self.board.slots[x][y]
+        elif (2*abs(event.x - PILE_X) < GRIDWIDTH and
+              2*abs(event.y - PILE_Y) < GRIDWIDTH):
+            return self.board.pile
+        elif (2*abs(event.x - BH_X) < GRIDWIDTH and
+              2*abs(event.y - BH_Y) < GRIDWIDTH):
+            return self.board.bh
+        else:
+            return None
+
+    def draw_board(self, board, window):
+        self.draw_base(window)
+
+        for col in board.slots:
+            for slot in col:
+                self.draw_boardslot(slot,window)
+
+        self.draw_bh(board.bh, window)
+        self.draw_points(board.points, window)
+        self.draw_pile(board.pile, window)
+        self.draw_hand(board.hand, window, self.hand_x, self.hand_y)
+
+    
+    def draw_pile(self, pile, window):
+        cr = window.cairo_create()
+        cr.translate(PILE_X, PILE_Y)
+        cr.scale(SCALE, SCALE)
+
+        cr.set_source_rgb(0.8, 0.8, 0.8)
+        cr.rectangle(-1, -1, 2, 2)
+        cr.fill()
+
+        cr.arc(1, 1, 0.5, 0, math.pi/2)
+        cr.set_source_rgb(0, 0, 0)
+        cr.set_line_width(0.1)
+        cr.set_line_cap(cairo.LINE_CAP_ROUND)
+        cr.move_to(1,    1.5)
+        cr.line_to(0.75, 1.5)
+        cr.move_to(0.75, 1.5)
+        cr.line_to(1   , 1.75)
+        cr.move_to(0.75, 1.5)
+        cr.line_to(1   , 1.25)
+        cr.stroke()
+
+        cr.set_line_cap(cairo.LINE_CAP_SQUARE)
+        cr.translate(0,-3)
+        if pile.cards:
+            cr.set_source_rgb(0, 0, 0.5)
+            cr.rectangle(-1, -1, 2, 2)
+            cr.fill()
+        else:
+            cr.set_source_rgb(0, 0, 0)
+            cr.set_line_width(0.05)
+            cr.rectangle(-1, -1, 2, 2)
+            cr.stroke()
+
+        cr.set_font_size(1)
+        cr.set_source_rgb(1,1,1)
+        (_,_,w,h,_,_) = cr.text_extents(str(len(pile.cards)))
+
+        cr.move_to(-w/2, h/2)
+        cr.show_text(str(len(pile.cards)))
+        cr.fill()
+
+        self.draw_slot(pile, window, PILE_X, PILE_Y)
+
+    def draw_points(self, points, window):
+        cr = window.cairo_create()
+        cr.translate(2 * GRIDPAD + 10*GRIDWIDTH, 6 * GRIDWIDTH)
+        cr.scale(SCALE, SCALE)
+
+        txt = "%ip" % points
+
+        cr.set_font_size(1)
+        cr.set_source_rgb(0,0,0)
+        (_,_,w,h,_,_) = cr.text_extents(txt)
+
+        cr.move_to(-w/2, h/2)
+        cr.show_text(txt)
+        cr.fill()
+
+    def draw_bh(self, bh, window):
+        cr = window.cairo_create()
+        cr.translate(BH_X, BH_Y)
+        cr.scale(SCALE, SCALE)
+
+        cr.rectangle(-1, -1, 2, 2)
+        cr.clip()
+
+        cr.set_source_rgb(0,0,0)
+        cr.arc(0, 0, 0.8, 0, 2*math.pi)
+        cr.fill()
+        
+        cr.set_font_size(1)
+        cr.set_source_rgb(1,1,1)
+        (_,_,w,h,_,_) = cr.text_extents(str(bh.count))
+
+        cr.move_to(-w/2, h/2)
+        cr.show_text(str(bh.count))
+        cr.fill()
+
+    def draw_boardslot(self, slot, window):
+        self.draw_slot(slot, window,
+            GRIDPAD + (slot.x+0.5) * GRIDWIDTH,
+            GRIDPAD + (slot.y+0.5) * GRIDWIDTH)
+
+    def draw_slot(self, slot, window, x, y):
+        if slot.card or slot.ship:
+            cr = window.cairo_create()
+            cr.translate(x, y)
+            cr.scale(SCALE, SCALE)
+
+            cr.rectangle(-1, -1, 2, 2)
+            cr.clip()
+
+            matrix = cr.get_matrix()
+            if slot.card:
+                self.draw_card(slot.card, cr)
+                cr.set_matrix(matrix)
+            if slot.ship:
+                self.draw_ship(slot.ship, cr)
+                cr.set_matrix(matrix)
+
+            if slot.highlighted:
+                cr.set_source_rgba(1, 1, 1, 0.5)
+                cr.rectangle(-1, -1, 2, 2)
+                cr.fill()
+
+    def draw_ship(self, ship, cr):
+        cr.move_to(0.9, 0)
+        cr.arc(0, 0, 0.3, math.pi, 0) 
+        cr.line_to(-0.9,0)
+        cr.line_to(-0.6, 0.6)
+        cr.line_to( 0.6, 0.6)
+
+        cr.set_source_rgb(1, 0, 0)
+        cr.fill()
+
+    draw_hand = draw_slot
+
+    def draw_card(self, card, cr):
+        cr.rotate(-(card.rotation * math.pi / 2))
+
+        # Meer
+        cr.set_source_rgb(0, 0, 1)
+        cr.rectangle(-1, -1, 2, 2)
+        cr.fill()
+
+        cr.set_source_rgb(0, 1, 0)
+        cr.set_line_cap(cairo.LINE_CAP_ROUND)
+        cr.set_line_width(0.9)
+
+        p2c = [ (1,0), (0,-1), (-1,0), (0,1) ]
+
+        # Land
+        for island in card.islands:
+            point = island[0]
+            cr.move_to( *p2c[point] )
+            for point in island[1:] + island[0:1]:
+                cr.line_to( *p2c[point] )
+            cr.stroke()
+        
+        # Border
+        cr.set_source_rgb(0, 0, 0)
+        cr.set_line_cap(cairo.LINE_CAP_ROUND)
+        cr.set_line_width(0.05)
+        cr.rectangle(-1, -1, 2, 2)
+        cr.stroke()
+
+    def draw_base(self,window):
+        if not self.base_pixmap:
+            self.base_pixmap = gtk.gdk.Pixmap(window,
+                    2*GRIDPAD + 9*GRIDWIDTH, 2*GRIDPAD + 6*GRIDWIDTH)
+
+            self.base_pixmap.draw_drawable(self.base_pixmap.new_gc(), window, 0, 0, 0, 0,
+                    2*GRIDPAD + 9*GRIDWIDTH, 2*GRIDPAD + 6*GRIDWIDTH)
+
+            cr = self.base_pixmap.cairo_create()
+
+
+            cr.translate(GRIDPAD, GRIDPAD)
+            cr.scale(GRIDWIDTH, GRIDWIDTH)
+
+            # Sea Background
+            # Unten
+            pat = cairo.LinearGradient (0, 5, 0, 5.5)
+            pat.add_color_stop_rgba(0, 0, 0, 1,1)
+            pat.add_color_stop_rgba(1, 0, 0, 1,0)
+            cr.rectangle(1, 5, 7, 0.5)
+            cr.set_source(pat)
+            cr.fill()
+
+            # Oben
+            pat = cairo.LinearGradient (0, 0, 0, -0.5)
+            pat.add_color_stop_rgba(0, 0, 0, 1,1)
+            pat.add_color_stop_rgba(1, 0, 0, 1,0)
+            cr.rectangle(1, -0.5, 7, 0.5)
+            cr.set_source(pat)
+            cr.fill()
+
+            # Links
+            pat = cairo.LinearGradient (1, 0, 0.5, 0)
+            pat.add_color_stop_rgba(0, 0, 0, 1,1)
+            pat.add_color_stop_rgba(1, 0, 0, 1,0)
+            cr.rectangle(0.5, 0, 0.5, 5)
+            cr.set_source(pat)
+            cr.fill()
+
+            # Rechts
+            pat = cairo.LinearGradient (8, 0, 8.5, 0)
+            pat.add_color_stop_rgba(0, 0, 0, 1,1)
+            pat.add_color_stop_rgba(1, 0, 0, 1,0)
+            cr.rectangle(8, 0, 0.5, 5)
+            cr.set_source(pat)
+            cr.fill()
+
+            # Oben Links
+            pat = cairo.RadialGradient(1,0,0, 1,0, 0.5)
+            pat.add_color_stop_rgba(0, 0, 0, 1, 1)
+            pat.add_color_stop_rgba(1, 0, 0, 1, 0)
+            cr.rectangle(0.5, -0.5, 0.5, 0.5)
+            cr.set_source(pat)
+            cr.fill()
+
+            # Oben Rechts
+            pat = cairo.RadialGradient(8,0,0, 8,0, 0.5)
+            pat.add_color_stop_rgba(0, 0, 0, 1, 1)
+            pat.add_color_stop_rgba(1, 0, 0, 1, 0)
+            cr.rectangle(8, -0.5, 8.5, 0.5)
+            cr.set_source(pat)
+            cr.fill()
+
+            # Unten Rechts
+            pat = cairo.RadialGradient(8,5,0, 8,5, 0.5)
+            pat.add_color_stop_rgba(0, 0, 0, 1, 1)
+            pat.add_color_stop_rgba(1, 0, 0, 1, 0)
+            cr.rectangle(8, 5, 8.5, 5.5)
+            cr.set_source(pat)
+            cr.fill()
+
+            # Unten Links
+            pat = cairo.RadialGradient(1,5,0, 1,5, 0.5)
+            pat.add_color_stop_rgba(0, 0, 0, 1, 1)
+            pat.add_color_stop_rgba(1, 0, 0, 1, 0)
+            cr.rectangle(0.5, 5, 1, 5.5)
+            cr.set_source(pat)
+            cr.fill()
+
+
+            # Frame
+            cr.set_source_rgb(1,1,1)
+            cr.set_line_width(0.05)
+            cr.set_line_cap(cairo.LINE_CAP_ROUND)
+            for x in range(0,8):
+                cr.move_to(1+x, 0)
+                cr.line_to(1+x, 5.5)
+                cr.stroke()
+            for y in range(0,6):
+                cr.move_to(0.5, y)
+                cr.line_to(8.5, y)
+                cr.stroke()
+
+        window.draw_drawable(window.new_gc(), self.base_pixmap, 0, 0, 0, 0,
+                2*GRIDPAD + 9*GRIDWIDTH, 2*GRIDPAD + 6*GRIDWIDTH)
+
+# vim:ts=4:sw=4:sts=4:et
diff --git a/engine.py b/engine.py
new file mode 100644 (file)
index 0000000..aecbfbc
--- /dev/null
+++ b/engine.py
@@ -0,0 +1,429 @@
+# Spielregelklasse
+# encoding:utf8
+
+SHIPPING = 1
+PLACING  = 2
+
+import gobject
+import math
+import random
+
+DEBUG = 1
+
+
+# Global Variables (Buh! Buh! Pfui!)
+state = SHIPPING
+
+
+class Ship:
+    def __init__(self):
+        pass
+
+class Slot:
+    def __init__(self):
+        self.x = None
+        self.y = None
+        self.rotateable = None
+        self.card = None
+        self.ship = None
+        self.is_ocean = False
+        self.highlighted = False
+
+    def is_empty(self):
+        return not self.card and not self.ship
+
+    def set_card(self, card):
+        assert not self.card
+        self.card = card
+
+
+    def set_ship(self, ship):
+        assert not self.ship
+        self.ship = ship
+
+class BoardSlot(Slot):
+    def __init__(self, x, y, is_ocean):
+        Slot.__init__(self)
+        self.x = x
+        self.y = y
+        self.rotateable = True
+        self.is_ocean = is_ocean
+        self.is_reachable = not is_ocean
+
+    def can_drop_ship(self):
+        if not self.is_reachable:
+            return False
+        for neigh in self.adj:
+            if neigh and neigh.is_ocean and not neigh.card:
+                return True
+        return False
+        
+    def can_drop_card(self, card):
+        if not self.is_ocean:
+            return False
+        if self.card:
+            return False
+
+        # Fits?
+        # Land?
+        for dir in card.land_conn():
+            neigh = self.adj[dir]
+            if neigh:
+                if not neigh.is_ocean:
+                    return False
+                if neigh.card:
+                    if (dir + 2)%4 not in neigh.card.land_conn():
+                        return False
+            else: # Border is not land
+                return False
+        # Sea?
+        for dir in card.sea_conn():
+            neigh = self.adj[dir]
+            if neigh and neigh.card:
+                if (dir + 2)%4 not in neigh.card.sea_conn():
+                    return False
+
+        # Ship close and connected through sea?
+        ship_nearby = False
+        for dir in card.sea_conn():
+            if self.adj[dir] and self.adj[dir].ship:
+                ship_nearby = True
+        if not ship_nearby:
+            return False
+
+        return True
+
+    def set_card(self, card):
+        Slot.set_card(self, card)
+
+        self.card.placed = True
+
+        # Reachable
+        for dir in card.sea_conn():
+            neigh = self.adj[dir]
+            if neigh and neigh.is_reachable:
+                if not neigh.is_ocean:
+                    self.is_reachable = True
+                if neigh.card and (dir + 2)%4 in neigh.card.sea_conn():
+                    self.is_reachable = True
+
+        # Move Ship
+        if self.is_reachable:
+            for neigh in self.adj:
+                if neigh and neigh.ship:
+                    self.set_ship( neigh.ship )
+                    neigh.ship = None
+
+        # Auto-Fill neighbors
+        for neigh in self.adj:
+            if neigh and neigh.is_ocean and not neigh.card:
+                neigh.autofill()
+
+        # Time to set the ship
+        global state
+        state = SHIPPING
+
+
+    def autofill(self):
+        land = []
+        surrounded = True
+        for dir in range(4):
+            neigh = self.adj[dir]
+            if neigh and neigh.is_ocean:
+                if not neigh.card:
+                    surrounded = False
+                else:
+                    if (dir + 2)%4 in neigh.card.land_conn():
+                        land.append(dir)
+                
+        if not surrounded:
+            self.autofill_land()
+            return
+        
+        card = Card()
+        if not land:
+            card.islands = []
+        elif len(land) == 2 and (land[0] + 2) % 4 == (land[1] % 4):
+            # Separated Land Strips
+            card.islands = [ [x] for x in land ]
+        else:
+            # Connected Land Strips
+            card.islands = [land]
+
+        self.card = card
+
+    def autofill_land(self):
+        seen = []
+        todo = [self]
+
+        while todo:
+            slot = todo.pop()
+            for dir in range(4):
+                neigh = slot.adj[dir]
+                if not neigh:
+                    # Border = no Land
+                    return
+                if neigh.card:
+                    if (dir+2)%4 in neigh.card.sea_conn():
+                        # Still sea-connection
+                        return
+                else:
+                    if neigh not in seen:
+                        todo.append(neigh)
+            seen.append(slot)
+
+        for slot in seen:
+            card = Card()
+            card.islands = [ [0,1,2,3] ]
+            slot.card = card
+
+
+class BlackHole(Slot):
+    def __init__(self):
+        Slot.__init__(self)
+        self.count = 0
+
+    def set_card(self,card):
+        self.count += 1
+        # Time to set the ship
+        global state
+        state = SHIPPING
+
+
+    def can_drop_card(self,card):
+        return True
+
+class Pile(Slot):
+    def __init__(self):
+        Slot.__init__(self)
+        self.rotateable = True
+        self.setup()
+
+    def setup(self):
+        self.cards = []
+        # Wasser Wasser Land Land
+        for i in range(11):
+            card = Card()
+            card.rotation= random.randint(0,3)
+            card.islands = [ [0, 1] ]
+            self.cards.append(card)
+
+        # Wasser Land Wasser Land
+        for i in range(7):
+            card = Card()
+            card.rotation= random.randint(0,3)
+            card.islands = [ [0], [2] ]
+            self.cards.append(card)
+
+        # Wasser Wasser Wasser Land
+        for i in range(7):
+            card = Card()
+            card.rotation= random.randint(0,3)
+            card.islands = [ [1] ]
+            self.cards.append(card)
+
+        # Wasser Wasser Wasser Wasser
+        for i in range(7):
+            card = Card()
+            card.rotation= random.randint(0,3)
+            card.islands = [ ]
+            self.cards.append(card)
+
+        # Wasser Land Land Land
+        for i in range(3):
+            card = Card()
+            card.rotation= random.randint(0,3)
+            card.islands = [ [0,1,2] ]
+            self.cards.append(card)
+
+        random.shuffle(self.cards)
+        del self.cards[32:]
+        assert len(self.cards) == 32
+
+    def can_flip_card(self):
+        return self.cards and not self.card
+
+    def flip_card(self):
+        global state
+
+        assert self.cards
+        assert not self.card
+        assert state == SHIPPING
+        state = PLACING
+        self.card = self.cards.pop()
+
+    def can_drop_card(self, card):
+        return False
+
+    def can_drop_ship(self):
+        return False
+
+
+    def rotate(self):
+        if self.card:
+            self.card.rotate_right()
+        
+class HandSlot(Slot):
+    def __init__(self):
+        Slot.__init__(self)
+        self.rotateable = False
+
+    def move_to(self,x,y):
+        self.x = x
+        self.y = y
+
+    def set_card(self, card):
+        assert not self.ship
+        Slot.set_card(self,card)
+
+    def set_ship(self, ship):
+        assert not self.card
+        Slot.set_ship(self,ship)
+
+class Card:
+    def __init__(self):
+        self.islands = [] 
+        self.rotation = 0
+        self.placed = False
+        # Example:
+        # Island top, right, bottom, with R and B connected:
+        #self.islands = [ [0], [1,2] ] 
+
+    def sea_conn(self):
+        conn = []
+        for dir in range(4):
+            sea = True
+            for island in self.rot_islands():
+                if dir in island:
+                    sea = False
+            if sea:
+                conn.append(dir)
+        return conn
+
+    def land_conn(self):
+        conn = []
+        sea = self.sea_conn()
+        for dir in range(4):
+            if dir not in sea:
+                conn.append(dir)
+        return conn
+
+    def has_sea(self):
+        return len(self.sea_conn()) > 0
+
+    def rot_islands(self):
+        return map( lambda i: map (lambda d: (d + self.rotation)%4, i), self.islands)
+
+    def rotate_right(self):
+        self.rotation = (self.rotation - 1) % 4
+
+    def rotate_left(self):
+        self.rotation = (self.rotation + 1) % 4
+
+class Board:
+    def __init__(self):
+        self.slots = []
+
+        for x in range(9):
+            col = []
+            for y in range(6):
+               col.append(
+                    BoardSlot(
+                        x,
+                        y,
+                        0 < x < 8 and y < 5 # Border Fields
+                    ))
+            self.slots.append(col)
+        for x in range(9):
+            for y in range(6):
+                self.slots[x][y].adj = []
+                if (x+1) < 9:
+                    self.slots[x][y].adj.append( self.slots[x+1][y] )
+                else:
+                    self.slots[x][y].adj.append( None )
+                if (y-1) >= 0:
+                    self.slots[x][y].adj.append( self.slots[x][y-1] )
+                else:
+                    self.slots[x][y].adj.append( None )
+                if (x-1) >= 0:
+                    self.slots[x][y].adj.append( self.slots[x-1][y] )
+                else:
+                    self.slots[x][y].adj.append( None )
+                if (y+1) < 6:
+                    self.slots[x][y].adj.append( self.slots[x][y+1] )
+                else:
+                    self.slots[x][y].adj.append( None )
+                assert len(self.slots[x][y].adj) == 4
+        self.hand = HandSlot()
+        self.pile = Pile()
+        self.bh = BlackHole()
+        self.points = 0
+
+        self.slots[0][0].set_ship(Ship())
+
+        self.calc_points()
+
+    def get_state(self):
+        return state
+
+    def calc_points(self):
+        points = 0
+
+        # Non-Placed Fields
+        for col in self.slots:
+            for slot in col:
+                if slot.is_ocean and not slot.card:
+                    points += -20
+
+        # Islands
+        seen = [] # Tupel: (slot,dir)
+        for col in self.slots:
+            for slot in col:
+                if slot.card:
+                    for dir in slot.card.land_conn():
+                        if (slot,dir) not in seen:
+                            # For every unchecked land connection
+                            ok = True
+                            todo = [(slot,dir)]
+                            seen_now = []
+                            slots = []
+                            while ok and todo:
+                                (slot,dir) = todo.pop()
+
+                                # Not Land, No Points
+                                if not slot.card or not dir in slot.card.land_conn():
+                                    ok = False
+                                    continue
+
+                                # Been there, Done that
+                                if (slot,dir) not in seen_now:
+                                    seen_now.append((slot,dir))
+
+                                    # Check Neighbor:
+                                    assert slot.adj[dir], "Land to Border? Huh"
+                                    if (slot.adj[dir], (dir + 2)%4) not in seen_now:
+                                        todo.append((slot.adj[dir], (dir + 2)%4))
+
+                                    # Count this slot
+                                    if slot not in slots:
+                                        slots.append(slot)
+
+                                    # Other connections on this land
+                                    for island in slot.card.rot_islands():
+                                        if dir in island:
+                                            for other_dir in island:
+                                                if other_dir != dir:
+                                                    if (slot,other_dir) not in seen_now:
+                                                        todo.append((slot, other_dir))
+
+                            if ok:
+                                points += len(slots) * len(slots)
+                            seen.extend(seen_now)
+
+
+       self.points = points
+        #self.pd.set_points(points)
+
+
+
+# vim:ts=4:sw=4:sts=4:et
diff --git a/ozeanien.py b/ozeanien.py
new file mode 100644 (file)
index 0000000..747a788
--- /dev/null
@@ -0,0 +1,110 @@
+#!/usr/bin/python
+# encoding:utf8
+
+
+import pygtk
+pygtk.require('2.0')
+import gtk
+import gobject
+import cairo
+import math
+import random
+
+from engine import * 
+from cairoboard import CairoBoard
+
+
+DEBUG = 1
+
+def dbg(txt):
+    if DEBUG:
+        print txt
+
+
+class Game:
+    def destroy(self, widget, data=None):
+        gtk.main_quit()
+
+    def __init__(self):
+        self.board = Board()
+        self.drag_from = None
+
+        self.boarddraw = CairoBoard(self.board)
+        self.boarddraw.connect("button-press-event",   self.press)
+        self.boarddraw.connect("button-release-event", self.release)
+
+        self.window = gtk.Window(gtk.WINDOW_TOPLEVEL)
+        self.window.set_title("Ozeanien")
+        self.window.set_border_width(2)
+        self.window.set_resizable(False)
+        self.window.connect("destroy", self.destroy)
+        self.window.add(self.boarddraw)
+
+        self.window.show_all()
+
+    def press(self, widget, event):
+        assert not self.drag_from
+
+        # Doppelclick ignorieren
+        if event.type != gtk.gdk.BUTTON_PRESS:
+            return
+
+        slot = self.boarddraw.event2slot(event)
+
+        if self.board.get_state() == SHIPPING:
+            if slot:
+                if slot.ship:
+                    self.drag_from = slot
+                    self.board.hand.set_ship(slot.ship)
+                    slot.ship = None
+            elif self.boarddraw.pileclick(event):
+                if self.board.pile.can_flip_card():
+                    self.board.pile.flip_card()
+
+        elif self.board.get_state() == PLACING:
+            if slot:
+                if slot.card and not slot.card.placed:
+                    self.drag_from = slot
+                    self.board.hand.set_card(slot.card)
+                    slot.card = None
+
+        if self.boarddraw.pilerotclick(event):
+            self.board.pile.rotate()
+
+        self.boarddraw.queue_draw()
+
+
+    def release(self, widget, event):
+        slot = self.boarddraw.event2slot(event)
+        if self.board.hand.ship:
+            if slot and slot.can_drop_ship():
+                slot.set_ship(self.board.hand.ship)
+                self.board.hand.ship = None
+                self.drag_from = None
+            else:
+                self.drag_from.set_ship(self.board.hand.ship)
+                self.board.hand.ship = None
+                self.drag_from = None
+
+        if self.board.hand.card:
+            if slot and slot.can_drop_card(self.board.hand.card):
+                slot.set_card(self.board.hand.card)
+                self.board.hand.card = None
+                self.drag_from = None
+            else:
+                self.drag_from.set_card(self.board.hand.card)
+                self.board.hand.card = None
+                self.drag_from = None
+
+        self.boarddraw.queue_draw()
+        self.board.calc_points()
+
+    def main(self):
+        gtk.main()
+
+if __name__ == "__main__":
+    game = Game()
+    game.main()
+
+
+# vim:ts=4:sw=4:sts=4:et