home *** CD-ROM | disk | FTP | other *** search
/ Mac Easy 2010 May / Mac Life Ubuntu.iso / casper / filesystem.squashfs / usr / share / python-support / gnome-games-data / glchess / display.py < prev    next >
Encoding:
Python Source  |  2009-04-14  |  17.9 KB  |  583 lines

  1. # -*- coding: utf-8 -*-
  2. __author__ = 'Robert Ancell <bob27@users.sourceforge.net>'
  3. __license__ = 'GNU General Public License Version 2'
  4. __copyright__ = 'Copyright 2005-2006  Robert Ancell'
  5.  
  6. import config
  7. import player
  8. import scene
  9. import scene.cairo
  10. import scene.opengl
  11. import scene.human
  12. import ui
  13. import game
  14. import chess.board
  15.  
  16. class MovePlayer(game.ChessPlayer):
  17.     """This class provides a pseudo-player to watch for piece movements"""
  18.     
  19.     def __init__(self, view):
  20.         """Constructor for a move player.
  21.         
  22.         'view' is the view to update
  23.         """
  24.         self.view = view
  25.         game.ChessPlayer.__init__(self, '@view')
  26.  
  27.     # Extended methods
  28.  
  29.     def onPieceMoved(self, piece, start, end, delete):
  30.         """Called by chess.board.ChessPlayer"""
  31.         if self.view.moveNumber != -1:
  32.             return
  33.         animate = self.view.game.isStarted()
  34.         p = self.view.scene.movePiece(piece, end, delete, animate)
  35.  
  36.         # If a player move notify when animation completes
  37.         if animate and self.view.moveNumber == -1 and start is not None and start != end:
  38.             self.view.scene.waitingPiece = p
  39.  
  40.     def onPlayerMoved(self, p, move):
  41.         self.view._redrawHighlight()
  42.         
  43.     def onPlayerStartTurn(self, player):
  44.         self.view._redrawHighlight()
  45.  
  46. class CairoPiece(scene.ChessPieceFeedback):
  47.     """
  48.     """
  49.     
  50.     model = None
  51.     
  52.     location = ''
  53.     
  54.     def __init__(self, scene, piece):
  55.         self.scene = scene
  56.         self.piece = piece
  57.  
  58.     def onDeleted(self):
  59.         """Called by scene.ChessPieceFeedback"""
  60.         self.scene.pieces.pop(self.piece)
  61.  
  62.     def onMoved(self):
  63.         """Called by scene.ChessPieceFeedback"""
  64.         self.scene.view._pieceMoved(self)
  65.  
  66. class SceneCairo(scene.SceneFeedback, scene.human.SceneHumanInput):
  67.     """
  68.     """
  69.     controller = None
  70.     
  71.     # The game this scene is rendering
  72.     game = None
  73.     
  74.     # TODO
  75.     pieces       = None
  76.     
  77.     # FIXME: Abort when scenes changed
  78.     waitingPiece = None
  79.  
  80.     def __init__(self, view):
  81.         """
  82.         """
  83.         self.view = view
  84.         self.controller = scene.cairo.Scene(self)
  85.         self.game = view.game
  86.         self.pieces = {}
  87.         scene.human.SceneHumanInput.__init__(self)
  88.         
  89.     def getPieces(self):
  90.         return self.pieces.values()
  91.  
  92.     def movePiece(self, piece, location, delete, animate):
  93.         """
  94.         """
  95.         # Get the model for this piece creating one if it doesn't exist
  96.         try:
  97.             p = self.pieces[piece]
  98.         except KeyError:
  99.             # Make the new model
  100.             pieceName = {chess.board.PAWN: 'pawn', chess.board.ROOK: 'rook', chess.board.KNIGHT: 'knight',
  101.                          chess.board.BISHOP: 'bishop', chess.board.QUEEN: 'queen', chess.board.KING: 'king'}[piece.getType()]
  102.             chessSet = {chess.board.WHITE: 'white', chess.board.BLACK: 'black'}[piece.getColour()]
  103.             p = CairoPiece(self, piece)
  104.             p.model = self.controller.addChessPiece(chessSet, pieceName, location, p)
  105.             self.pieces[piece] = p
  106.  
  107.         # Move the model
  108.         p.location = location
  109.         p.model.move(location, delete, animate)
  110.         
  111.         return p
  112.  
  113.     # Extended methods
  114.  
  115.     def onRedraw(self):
  116.         """Called by scene.cairo.Scene"""
  117.         if self.game.view is not None and self.game.view.controller is not None:
  118.             self.game.view.controller.render()
  119.  
  120.     def startAnimation(self):
  121.         """Called by scene.cairo.Scene"""
  122.         self.game.application.ui.controller.startAnimation()
  123.         
  124.     def getSquare(self, x, y):
  125.         """Called by scene.human.SceneHumanInput"""
  126.         return self.controller.getSquare(x, y)
  127.  
  128.     def playerIsHuman(self):
  129.         """Called by scene.human.SceneHumanInput"""
  130.         return self.game.currentPlayerIsHuman()
  131.  
  132.     def squareIsFriendly(self, coord):
  133.         """Called by scene.human.SceneHumanInput"""
  134.         return self.playerIsHuman() and self.game.squareIsFriendly(coord)
  135.     
  136.     def canMove(self, start, end):
  137.         """Called by scene.human.SceneHumanInput"""
  138.         return self.playerIsHuman() and self.game.getCurrentPlayer().canMove(start, end) # FIXME: Promotion type
  139.  
  140.     def selectSquare(self, coord):
  141.         """Called by scene.human.SceneHumanInput"""
  142.         self.view.setSelectedSquare(coord)
  143.  
  144.     def moveHuman(self, start, end):
  145.         """Called by scene.human.SceneHumanInput"""
  146.         self.game.moveHuman(start, end)
  147.         
  148. class OpenGLPiece(scene.ChessPieceFeedback):
  149.     """
  150.     """
  151.     
  152.     model = None
  153.     
  154.     location = ''
  155.     
  156.     def __init__(self, scene, piece):
  157.         self.scene = scene
  158.         self.piece = piece
  159.  
  160.     def onDeleted(self):
  161.         """Called by scene.ChessPieceFeedback"""
  162.         self.scene.pieces.pop(self.piece)
  163.  
  164.     def onMoved(self):
  165.         """Called by scene.ChessPieceFeedback"""
  166.         self.scene.view._pieceMoved(self)
  167.  
  168. class SceneOpenGL(scene.SceneFeedback, scene.human.SceneHumanInput):
  169.     """
  170.     """
  171.     # The game this scene is rendering
  172.     game          = None
  173.     
  174.     # TODO
  175.     pieces        = None
  176.     
  177.     # FIXME: Abort when scenes changed
  178.     waitingPiece = None
  179.  
  180.     def __init__(self, view):
  181.         """Constructor for a glChess scene.
  182.         
  183.  
  184.         """
  185.         self.view = view
  186.         self.game = view.game
  187.         self.pieces = {}
  188.  
  189.         # Call parent constructors
  190.         self.controller = scene.opengl.Scene(self)
  191.         scene.human.SceneHumanInput.__init__(self)
  192.  
  193.     def getPieces(self):
  194.         return self.pieces.values()
  195.         
  196.     def movePiece(self, piece, location, delete, animate):
  197.         """
  198.         """
  199.         # Get the model for this piece creating one if it doesn't exist
  200.         try:
  201.             p = self.pieces[piece]
  202.         except KeyError:
  203.             # Make the new model
  204.             pieceName = {chess.board.PAWN: 'pawn', chess.board.ROOK: 'rook', chess.board.KNIGHT: 'knight',
  205.                          chess.board.BISHOP: 'bishop', chess.board.QUEEN: 'queen', chess.board.KING: 'king'}[piece.getType()]
  206.             chessSet = {chess.board.WHITE: 'white', chess.board.BLACK: 'black'}[piece.getColour()]
  207.             p = OpenGLPiece(self, piece)
  208.             p.model = self.controller.addChessPiece(chessSet, pieceName, location, p)
  209.             self.pieces[piece] = p
  210.             
  211.         # Move the model
  212.         p.location = location
  213.         p.model.move(location, delete)
  214.  
  215.         return p
  216.  
  217.     # Extended methods
  218.  
  219.     def onRedraw(self):
  220.         """Called by scene.opengl.Scene"""
  221.         if self.game.view is not None and self.game.view.controller is not None:
  222.             self.game.view.controller.render()
  223.  
  224.     def startAnimation(self):
  225.         """Called by scene.opengl.Scene"""
  226.         self.game.application.ui.controller.startAnimation()
  227.         
  228.     def getSquare(self, x, y):
  229.         """Called by scene.human.SceneHumanInput"""
  230.         return self.controller.getSquare(x, y)
  231.  
  232.     def playerIsHuman(self):
  233.         """Called by scene.human.SceneHumanInput"""
  234.         return self.game.currentPlayerIsHuman()
  235.  
  236.     def squareIsFriendly(self, coord):
  237.         """Called by scene.human.SceneHumanInput"""
  238.         return self.playerIsHuman() and self.game.squareIsFriendly(coord)
  239.     
  240.     def canMove(self, start, end):
  241.         """Called by scene.human.SceneHumanInput"""
  242.         return self.playerIsHuman() and self.game.getCurrentPlayer().canMove(start, end) # FIXME: Promotion type
  243.     
  244.     def selectSquare(self, coord):
  245.         """Called by scene.human.SceneHumanInput"""
  246.         self.view.setSelectedSquare(coord)
  247.     
  248.     def moveHuman(self, start, end):
  249.         """Called by scene.human.SceneHumanInput"""
  250.         self.game.moveHuman(start, end)
  251.  
  252. class Splashscreen(ui.ViewFeedback):
  253.     """
  254.     """    
  255.     application = None
  256.     scene       = None
  257.     
  258.     def __init__(self, application):
  259.         """Constructor.
  260.         
  261.         'application' is ???
  262.         """
  263.         self.application = application
  264.         self.cairoScene = scene.cairo.Scene(self)
  265.         self.scene = scene.opengl.Scene(self)
  266.  
  267.     def updateRotation(self, animate = True):
  268.         boardView = config.get('board_view')
  269.         if boardView == 'black':
  270.             rotation = 180.0
  271.         else:
  272.             rotation = 0.0
  273.         self.cairoScene.controller.setBoardRotation(rotation, animate)
  274.         self.scene.controller.setBoardRotation(rotation, animate)
  275.  
  276.     def onRedraw(self):
  277.         """Called by scene.SceneFeedback"""
  278.         if self.controller is not None:
  279.             self.controller.render()
  280.             
  281.     def showBoardNumbering(self, showNumbering):
  282.         """Called by ui.ViewFeedback"""
  283.         self.scene.showBoardNumbering(showNumbering)
  284.         self.cairoScene.showBoardNumbering(showNumbering)
  285.  
  286.     def showMoveHints(self, showHints):
  287.         """Called by ui.ViewFeedback"""
  288.         pass
  289.  
  290.     def renderGL(self):
  291.         """Called by ui.ViewFeedback"""
  292.         self.scene.render()
  293.         
  294.     def renderCairoStatic(self, context):
  295.         """Called by ui.ViewFeedback"""
  296.         return self.cairoScene.renderStatic(context)
  297.         
  298.     def renderCairoDynamic(self, context):
  299.         """Called by ui.ViewFeedback"""
  300.         self.cairoScene.renderDynamic(context)
  301.     
  302.     def reshape(self, width, height):
  303.         """Called by ui.ViewFeedback"""
  304.         self.scene.reshape(width, height)
  305.         self.cairoScene.reshape(width, height)
  306.  
  307.     def select(self, x, y):
  308.         pass
  309.     
  310.     def deselect(self, x, y):
  311.         pass    
  312.  
  313.     def selectSquare(self, coord):
  314.         pass
  315.     
  316.     def undo(self):
  317.         """Called by ui.ViewFeedback"""
  318.         pass
  319.  
  320.     def resign(self):
  321.         """Called by ui.ViewFeedback"""
  322.         pass
  323.     
  324.     def claimDraw(self):
  325.         """Called by ui.ViewFeedback"""
  326.         pass
  327.     
  328.     def setMoveNumber(self, moveNumber):
  329.         """Called by ui.ViewFeedback"""
  330.         pass
  331.  
  332. class View(ui.ViewFeedback):
  333.     """
  334.     """
  335.     # The controller object for this view
  336.     controller  = None
  337.     
  338.     def __init__(self, game):
  339.         """Constructor.
  340.         
  341.         'game' is the game this view is rendering
  342.         """
  343.         self.game = game
  344.         
  345.         # The move we are watching
  346.         self.moveNumber = -1
  347.         
  348.         # The selected square
  349.         self.selectedCoord = None
  350.         self.showHints = False
  351.         self.showNumbering = False
  352.         self.doSmooth = False
  353.         self.highlightParams = (None, None, None, None)
  354.         self.changedHighlight = True
  355.         
  356.         # Use a Cairo scene by default - it will be replaced by an OpenGL one if that is the requested view
  357.         # I wanted to remove this but then scene is None and there are a number of issues...
  358.         # This should be cleaned up
  359.         self.scene = SceneCairo(self)
  360.         config.watch('board_view', self.__onBoardViewChanged)
  361.  
  362.         # Look for game events to update the scene
  363.         movePlayer = MovePlayer(self)
  364.         game.addSpectator(movePlayer)
  365.  
  366.     def setSelectedSquare(self, coord):
  367.         if self.selectedCoord == coord:
  368.             return
  369.         self.selectedCoord = coord
  370.         self._redrawHighlight()
  371.  
  372.     def _redrawHighlight(self):
  373.         self.changedHighlight = True
  374.         if self.controller is not None:
  375.             self.controller.render()
  376.  
  377.     def __onBoardViewChanged(self, key, value):
  378.         self.updateRotation()
  379.  
  380.     def _updateHighlight(self, coord):
  381.         if self.moveNumber == -1:
  382.             player = self.game.getCurrentPlayer()
  383.             if player is self.game.getWhite():
  384.                 colour = chess.board.WHITE
  385.             else:
  386.                 colour = chess.board.BLACK
  387.         else:
  388.             if self.moveNumber % 2 == 0:
  389.                 colour = chess.board.WHITE
  390.             else:
  391.                 colour = chess.board.BLACK
  392.  
  393.         # Don't update if nothing has changed
  394.         params = (colour, self.moveNumber, self.selectedCoord, self.showHints)
  395.         if self.highlightParams == params:
  396.             return
  397.         self.highlightParams = params
  398.  
  399.         highlights = {}
  400.         if self.showHints:
  401.             for file in '12345678':
  402.                 for rank in 'abcdefgh':
  403.                     c = rank + file
  404.                     highlight = None
  405.                     if self.game.board.squareUnderAttack(colour, c, moveNumber = self.moveNumber):
  406.                         highlight = scene.HIGHLIGHT_THREATENED
  407.                     elif coord is not None:
  408.                         move = self.game.board.testMove(colour, coord, c, moveNumber = self.moveNumber)
  409.                         if move is not None:
  410.                             if self.game.board.getPiece(c, self.moveNumber):
  411.                                 highlight = scene.HIGHLIGHT_CAN_TAKE
  412.                             else:
  413.                                 highlight = scene.HIGHLIGHT_CAN_MOVE
  414.  
  415.                     if highlight is not None:
  416.                         highlights[c] = highlight
  417.         if coord is not None:
  418.             highlights[coord] = scene.HIGHLIGHT_SELECTED
  419.  
  420.         self.scene.controller.setBoardHighlight(highlights)
  421.  
  422.     def updateRotation(self, animate = True):
  423.         """
  424.         """
  425.         # Get the angle to face
  426.         p = self.game.getCurrentPlayer()
  427.         if p is self.game.getWhite():
  428.             rotation = 0.0
  429.         elif p is self.game.getBlack():
  430.             rotation = 180.0
  431.         
  432.         # Decide if we should face this angle
  433.         boardView = config.get('board_view')
  434.         if boardView == 'white':
  435.             rotation = 0.0
  436.         elif boardView == 'black':
  437.             rotation = 180.0
  438.         elif boardView == 'human':
  439.             if not isinstance(p, player.HumanPlayer):
  440.                 return
  441.  
  442.         self.scene.controller.setBoardRotation(rotation, animate)
  443.  
  444.     def _pieceMoved(self, piece):
  445.         """
  446.         """
  447.         self._redrawHighlight()
  448.         
  449.         # If waiting for this piece then end players turn
  450.         if piece is not None and piece is self.scene.waitingPiece:
  451.             self.scene.waitingPiece = None
  452.             self.game.getCurrentPlayer().endMove()
  453.  
  454.     def showMoveHints(self, showHints):
  455.         """Called by ui.ViewFeedback"""
  456.         self.showHints = showHints
  457.         self._redrawHighlight()
  458.  
  459.     def showBoardNumbering(self, showNumbering):
  460.         """Called by ui.ViewFeedback"""
  461.         self.showNumbering = showNumbering
  462.         self.scene.controller.showBoardNumbering(showNumbering)
  463.         
  464.     def showSmooth(self, doSmooth):
  465.         """Called by ui.ViewFeedback"""
  466.         self.doSmooth = doSmooth
  467.         self.scene.controller.showSmooth(doSmooth)
  468.  
  469.     def updateScene(self, sceneClass):
  470.         """
  471.         """
  472.         if self.changedHighlight:
  473.             self._updateHighlight(self.selectedCoord)
  474.         self.changedHighlight = False
  475.         
  476.         if isinstance(self.scene, sceneClass):
  477.             return
  478.         self._pieceMoved(None)
  479.         self.scene = sceneClass(self)
  480.         self.reshape(self.width, self.height)
  481.         self.setMoveNumber(self.moveNumber)
  482.         self.showBoardNumbering(self.showNumbering)
  483.         self.showSmooth(self.doSmooth)
  484.         self.updateRotation(animate = False)
  485.  
  486.     def renderGL(self):
  487.         """Called by ui.ViewFeedback"""
  488.         self.updateScene(SceneOpenGL)
  489.         self.scene.controller.render()
  490.  
  491.     def renderCairoStatic(self, context):
  492.         """Called by ui.ViewFeedback"""
  493.         self.updateScene(SceneCairo)
  494.         return self.scene.controller.renderStatic(context)
  495.         
  496.     def renderCairoDynamic(self, context):
  497.         """Called by ui.ViewFeedback"""
  498.         self.updateScene(SceneCairo)
  499.         self.scene.controller.renderDynamic(context)
  500.  
  501.     def reshape(self, width, height):
  502.         """Called by ui.ViewFeedback"""
  503.         self.width = width
  504.         self.height = height
  505.         self.scene.controller.reshape(width, height)
  506.     
  507.     def select(self, x, y):
  508.         """Called by ui.ViewFeedback"""
  509.         self.scene.select(x, y)
  510.     
  511.     def deselect(self, x, y):
  512.         """Called by ui.ViewFeedback"""
  513.         self.scene.deselect(x, y)
  514.     
  515.     def setMoveNumber(self, moveNumber):
  516.         """Called by ui.ViewFeedback"""
  517.         self.moveNumber = moveNumber
  518.         
  519.         # Lock the scene if not tracking the game
  520.         self.scene.enableHumanInput(moveNumber == -1)
  521.         
  522.         # Get the state of this scene
  523.         piecesByLocation = self.game.getAlivePieces(moveNumber)
  524.         
  525.         # Remove any models not present
  526.         requiredPieces = piecesByLocation.values()
  527.         for piece in self.scene.getPieces():
  528.             try:
  529.                 requiredPieces.index(piece.piece)
  530.             except ValueError:
  531.                 piece.model.move(piece.location, True)
  532.         
  533.         # Move the models in the scene
  534.         for (location, piece) in piecesByLocation.iteritems():
  535.             self.scene.movePiece(piece, location, False, True)
  536.  
  537.         # Can't wait for animation if not looking at the latest move
  538.         if moveNumber != -1:
  539.             self._pieceMoved(piece)
  540.  
  541.         self._redrawHighlight()
  542.  
  543.     def save(self, fileName = None):
  544.         """Called by ui.ViewFeedback"""
  545.         # If filename supplied take out of the history
  546.         if fileName is not None:
  547.             if self.game.inHistory:
  548.                 self.game.inHistory = False
  549.                 if self.game.fileName is not None:
  550.                     self.game.application.history.rename(self.game.fileName, fileName)
  551.             self.game.fileName = fileName
  552.         return self.game.save()
  553.  
  554.     def getFileName(self):
  555.         """Called by ui.ViewFeedback"""
  556.         # If in the history then prompt for a new name
  557.         if self.game.inHistory:
  558.             return None
  559.         return self.game.fileName
  560.     
  561.     def undo(self):
  562.         """Called by ui.ViewFeedback"""
  563.         p = self.game.getHumanPlayer()
  564.         if p is not None:
  565.             p.undo()
  566.         
  567.     def resign(self):
  568.         """Called by ui.ViewFeedback"""
  569.         p = self.game.getHumanPlayer()
  570.         if p is None:
  571.             # If no human players then abandon game
  572.             self.game.abandon()
  573.         else:
  574.             p.resign()
  575.             
  576.     def claimDraw(self):
  577.         """Called by ui.ViewFeedback"""
  578.         # TODO: Have the UI ask if the player wants to make a move first or claim now (or abort)
  579.         p = self.game.getHumanPlayer()
  580.         if p is None:
  581.             return False
  582.         return p.claimDraw()
  583.