Actually commit stuff from ages ago
[progcomp2013.git] / qchess / src / board.py
index 0d96d1a..5f75d39 100644 (file)
@@ -1,5 +1,7 @@
 [w,h] = [8,8] # Width and height of board(s)
 
+always_reveal_states = False
+
 # Class to represent a quantum chess board
 class Board():
        # Initialise; if master=True then the secondary piece types are assigned
@@ -11,9 +13,15 @@ class Board():
                self.grid = [[None] * w for _ in range(h)] # 2D List (you can get arrays in python, somehow, but they scare me)
                self.unrevealed_types = {"white" : piece_types.copy(), "black" : piece_types.copy()}
                self.king = {"white" : None, "black" : None} # We need to keep track of the king, because he is important
+               self.max_moves = None
+               self.moves = 0
+               self.move_stack = []
                for c in ["black", "white"]:
                        del self.unrevealed_types[c]["unknown"]
 
+               if style == "empty":
+                       return
+
                # Add all the pieces with known primary types
                for i in range(0, 2):
                        
@@ -25,7 +33,6 @@ class Board():
                        c.append(Piece(s, 1, y, ["knight"]))
                        c.append(Piece(s, 2, y, ["bishop"]))
                        k = Piece(s, 3, y, ["king", "king"]) # There can only be one ruler!
-                       k.types_revealed[1] = True
                        k.current_type = "king"
                        self.king[s] = k
                        c.append(k)
@@ -63,11 +70,10 @@ class Board():
                                        types_left[choice] -= 1
                                        if types_left[choice] <= 0:
                                                del types_left[choice]
-                                       piece.types.append(choice)
+                                       piece.types.append('?' + choice)
                                elif style == "classical":
                                        piece.types.append(piece.types[0])
                                        piece.current_type = piece.types[0]
-                                       piece.types_revealed[1] = True
                                        piece.choice = 0
 
        def clone(self):
@@ -77,6 +83,40 @@ class Board():
 
                for i in range(len(mypieces)):
                        newpieces[i].init_from_copy(mypieces[i])
+       
+       # Reset the board from a string
+       def reset_board(self, s):
+               self.pieces = {"white" : [], "black" : []}
+               self.king = {"white" : None, "black" : None}
+               self.grid = [[None] * w for _ in range(h)]
+               for x in range(w):
+                       for y in range(h):
+                               self.grid[x][y] = None
+
+               for line in s.split("\n"):
+                       if line == "":
+                               continue
+                       if line[0] == "#":
+                               continue
+
+                       tokens = line.split(" ")
+                       [x, y] = map(int, tokens[len(tokens)-1].split(","))
+                       current_type = tokens[1]
+                       types = map(lambda e : e.strip(" '[],"), line.split('[')[1].split(']')[0].split(','))
+                       
+                       target = Piece(tokens[0], x, y, types)
+                       target.current_type = current_type
+                       
+                       try:
+                               target.choice = types.index(current_type)
+                       except:
+                               target.choice = -1
+
+                       self.pieces[tokens[0]].append(target)
+                       if target.current_type == "king":
+                               self.king[tokens[0]] = target
+
+                       self.grid[x][y] = target
                        
 
        def display_grid(self, window = None, grid_sz = [80,80]):
@@ -142,15 +182,23 @@ class Board():
                                del self.unrevealed_types[piece.colour][state]
 
                piece.types[type_index] = state
-               piece.types_revealed[type_index] = True
                piece.current_type = state
 
                if len(self.possible_moves(piece)) <= 0:
                        piece.deselect() # Piece can't move; deselect it
+                       
+               # Piece needs to recalculate moves
+               piece.possible_moves = None
                
        # Update the board when a piece has been moved
        def update_move(self, x, y, x2, y2):
+                               
                piece = self.grid[x][y]
+               #print "Moving " + str(x) + "," + str(y) + " to " + str(x2) + "," + str(y2) + "; possible_moves are " + str(self.possible_moves(piece))
+               
+               if not [x2,y2] in self.possible_moves(piece):
+                       raise Exception("ILLEGAL move " + str(x2)+","+str(y2))
+               
                self.grid[x][y] = None
                taken = self.grid[x2][y2]
                if taken != None:
@@ -173,7 +221,13 @@ class Board():
                        piece.current_type = "queen"
 
                piece.deselect() # Uncollapse (?) the wavefunction!
-               self.verify()   
+               self.moves += 1
+               
+               # All other pieces need to recalculate moves
+               for p in self.pieces["white"] + self.pieces["black"]:
+                       p.possible_moves = None
+               
+               #self.verify()  
 
        # Update the board from a string
        # Guesses what to do based on the format of the string
@@ -230,7 +284,7 @@ class Board():
                        if prob > 0:
                                result.update({p : prob})
                
-               self.verify()
+               #self.verify()
                return result
 
 
@@ -255,7 +309,7 @@ class Board():
                for i in range(len(p.types)):
                        t = p.types[i]
                        prob = 0.5
-                       if t == "unknown" or p.types_revealed[i] == False:
+                       if t == "unknown" or p.types[i][0] == '?':
                                total_types = 0
                                for t2 in self.unrevealed_types[p.colour].keys():
                                        total_types += self.unrevealed_types[p.colour][t2]
@@ -271,7 +325,7 @@ class Board():
                                for point in self.possible_moves(p, reject_allied):
                                        result[point[0]][point[1]] += prob
                
-               self.verify()
+               #self.verify()
                p.current_type = "unknown"
                return result
 
@@ -283,7 +337,7 @@ class Board():
                        if t == state:
                                result += prob
                                continue        
-                       if t == "unknown" or p.types_revealed[i] == False:
+                       if t == "unknown" or p.types[i][0] == '?':
                                total_prob = 0
                                for t2 in self.unrevealed_types[p.colour].keys():
                                        total_prob += self.unrevealed_types[p.colour][t2]
@@ -297,10 +351,25 @@ class Board():
        # This is probably inefficient, but I looked at some sample chess games and they seem to actually do things this way
        # reject_allied indicates whether squares occupied by allied pieces will be removed
        # (set to false to check for defense)
-       def possible_moves(self, p, reject_allied = True):
-               result = []
+       def possible_moves(self, p, reject_allied = True, state=None):
                if p == None:
+                       raise Exception("SANITY: No piece")
+               
+               
+               
+               if state != None and state != p.current_type:
+                       old_type = p.current_type
+                       p.current_type = state
+                       result = self.possible_moves(p, reject_allied, state=None)
+                       p.current_type = old_type
                        return result
+               
+               if p.possible_moves != None:
+                       return p.possible_moves
+               
+               
+               result = []
+               
 
                
                if p.current_type == "unknown":
@@ -372,7 +441,9 @@ class Board():
                        if g != None and (g.colour == p.colour and reject_allied == True):
                                result.remove(point) # Remove allied pieces
                
-               self.verify()
+               #self.verify()
+               
+               p.possible_moves = result
                return result
 
 
@@ -396,8 +467,49 @@ class Board():
                                        
                return p
 
+       # Returns "white", "black" or "DRAW" if the game should end
+       def end_condition(self):
+               if self.king["white"] == None:
+                       if self.king["black"] == None:
+                               return "DRAW" # This shouldn't happen
+                       return "black"
+               elif self.king["black"] == None:
+                       return "white"
+               elif len(self.pieces["white"]) == 1 and len(self.pieces["black"]) == 1:
+                       return "DRAW"
+               elif self.max_moves != None and self.moves > self.max_moves:
+                       return "DRAW"
+               return None
 
 
        # I typed the full statement about 30 times before writing this function...
        def on_board(self, x, y):
                return (x >= 0 and x < w) and (y >= 0 and y < h)
+       
+       # Pushes a move temporarily
+       def push_move(self, piece, x, y):
+               target = self.grid[x][y]
+               self.move_stack.append([piece, target, piece.x, piece.y, x, y])
+               [piece.x, piece.y] = [x, y]
+               self.grid[x][y] = piece
+               self.grid[piece.x][piece.y] = None
+               
+               for p in self.pieces["white"] + self.pieces["black"]:
+                       p.possible_moves = None
+               
+       # Restore move
+       def pop_move(self):
+               #print str(self.move_stack)
+               [piece, target, x1, y1, x2, y2] = self.move_stack[len(self.move_stack)-1]
+               self.move_stack = self.move_stack[:-1]
+               piece.x = x1
+               piece.y = y1
+               self.grid[x1][y1] = piece
+               if target != None:
+                       target.x = x2
+                       target.y = y2
+               self.grid[x2][y2] = target
+               
+               for p in self.pieces["white"] + self.pieces["black"]:
+                               p.possible_moves = None
+               

UCC git Repository :: git.ucc.asn.au