# -*- coding: UTF-8 -*- # Copyright 2007-2008 One Laptop Per Child # Copyright 2007 Gerard J. Cerchio # Copyright 2008 Andrés Ambrois # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA import logging import sugar.logger from gettext import gettext as _ import cPickle import gtk from sugar.activity.activity import Activity, ActivityToolbox from sugar._sugarext import KeyGrabber from gametoolbar import GameToolbar from tutorialtoolbar import TutorialToolbar from edittoolbar import EditToolbar from gogame import GoGame import boardwidget import infopanel from collaboration import CollaborationWrapper from gtp import gnugo logger = logging.getLogger('PlayGo') DEFAULT_SIZE = 19 DEFAULT_KOMI = 5.5 class PlayGo(Activity): def __init__(self, handle): # Initialize the parent Activity.__init__(self, handle) logger.debug('Initiating PlayGo') self.size = DEFAULT_SIZE self.komi = DEFAULT_KOMI # Set the script self.script = ["", "This is the main board for a game of Go.", "There are three different board sizes to choose from; 9 x 9, 13 x 13, and 19 x 19.", "This game is played by placing stones down on the board.", "One person has black stones, and the other has white stones.", "To place a stone, move your mouse to the where you want to put the stone and click.", "Territories are created when you place stones of your color near other stones.", "If empty places on the board are surrounded by your pieces alone, then it counts as your territory.", "Scoring is based on a lot of different things.", "During the game, your score increases based on the amount of pieces you capture that are your opponents.", "When the game ends, territory is also added to these scores.", "A liberty is when there is a blank space next to one of your pieces.", "In this example, the black piece has four liberties.", "Those liberties are shown by the four squares around the piece.", "At one time, a piece can only have four liberties.", "To capture an opponents piece, it must have no more liberties.", "In this example, the black piece would be captured if white placed a piece where the triangle is.", "This would give white one point.", "Seki is a situation where both players share liberties.", "In this example, the black and white pieces share the two liberties that have circles in them.", "It is recommended for neither player to place pieces in those spots, because the other opponent could then capture the other player's pieces.", "Ko is a situation which prevents a game from going on forever.", "The example above shows a normal ko situation.", "If white were to place a piece where the X is, then it would capture the black piece.", "Black can't place a piece back in the same place though, since it would allow black and white capture the same pieces over and over.", "Superko is similar to ko, but on a larger scale.", "The superko rule states that the board can't be brought back to a previous position.", "This can happen when there is many ko's on the board, and players could keep capturing them forever.", "In the example above, there are two ko's that could be captured over and over, causing a superko.", "Life and death are important things to consider in Go.", "When some of your pieces become surrounded, then they are considered to be dead.", "This is because they could be captured at any time.", "It is important to know when a group of pieces are dead, since it will let you place pieces where they may be more useful.", "A ko fight is when two players challenge each other with their kos.", "When fighting, they will place pieces that will give them advantage as long as the opponent doesn't stop them.", "In this example, a white piece was taken where the circle was.", "During white's turn they then place the white piece with the x, which gives the black player a choice.", "They can either place a spot where the circle is, or stop the white player from having territory that won't be capturable.", "Semeai, or \"Capture Race\", is when there is a mutual capturing contest between the two players.", "These situations are usually won by whomever moves first in the race, since they tend to involve the same amount of moves on both sides.", "The current board is a common example of semeai.", "Sente and gote are terms for who has initiative at a current time.", "Sente means that you are making the first move, which the opponent may then have to respond to.", "Gote is the direct opposite, where you have to play a piece in respose to your opponent's move.", "In this example, black has played at x in sente.", "This places white in gote, where they must respond where the circle is or they will lose their pieces eventually.", "It's important to know when you have initiative in the game, since it will commonly exchange between the players.", "Maintaining sente and keeping out of gote will give you a higher chance of winning, since you will be able to make your opponent play where you want them to play.", "The game ends with both players have passed in the same turn.", "When that happens, each player's score is settled.", "First, the pieces that were captured by each player are counted.", "Then, the score of each player's territories are added to their scores.", "Finally, the komi (a point handicap given for playing second) is added to the white player.", "Whomever has the higher score after this is the winner!"] self.next_script_frame = [0,1,3,6,8,11,15,18,21,25,29,33,38,41,48] self.is_editing = 0 self.edit_type = 0 self.edit_status = { } # Set the activity toolbox toolbox = ActivityToolbox(self) self.set_toolbox(toolbox) self.gameToolbar = GameToolbar(self) toolbox.add_toolbar(_('Game'), self.gameToolbar) self.gameToolbar.connect('game-restart', self.restart_game) self.gameToolbar.connect('game-board-size', self.board_size_change) self.gameToolbar.connect('ai-activated', self.ai_activated_cb) self.gameToolbar.connect('ai-deactivated', self.ai_deactivated_cb) self.gameToolbar.show() # Set the tutorial toolbox self.tutorialToolbar = TutorialToolbar(self) toolbox.add_toolbar(_('Tutorial'), self.tutorialToolbar) self.tutorialToolbar.connect('begin', self.begin_cb) self.tutorialToolbar.connect('previous', self.previous_category) self.tutorialToolbar.connect('next', self.next_category) self.tutorialToolbar.connect('change-category', self.category_cb) self.tutorialToolbar.show() # Set the editor toolbox self.editToolbar = EditToolbar(self) toolbox.add_toolbar(_('Editor'), self.editToolbar) self.editToolbar.connect('edit', self.edit_cb) self.editToolbar.connect('add-x', self.add_x_cb) self.editToolbar.connect('add-circle', self.add_circle_cb) self.editToolbar.connect('add-triangle', self.add_triangle_cb) self.editToolbar.connect('add-square', self.add_square_cb) self.editToolbar.connect('load-game', self.load_cb) self.editToolbar.connect('save-game', self.save_cb) self.editToolbar.show() # Initialize the game self.game = GoGame(self.size) self.CurrentColor = 'B' self.PlayerColor = 'B' self.pass_count = 0 self.ai_activated = False self.set_up_ui() self.current_tutorial = 0; self.tutorialToolbar.grey_out_previous() self.tutorialToolbar.grey_out_next() self.tutorialToolbar.grey_out_category() self.editToolbar.grey_out_add_x() self.editToolbar.grey_out_add_triangle() self.editToolbar.grey_out_add_circle() self.editToolbar.grey_out_add_square() if not handle.object_id: self.infopanel.show(_('Welcome to PlayGo!')) else: self.show_score() self.lastX = -1 self.lastY = -1 # Set keypad actions self._key_actions = { 'KP_Up' : 'move_up', 'KP_Right' : 'move_right', 'KP_Down' : 'move_down', 'KP_Left' : 'move_left', 'KP_Home' : 'place_stone', 'KP_Next' : 'undo', 'KP_End' : 'pass' } self._key_grabber = KeyGrabber() self._key_grabber.connect('key-pressed', self._key_pressed_cb) # New KeyGrabber API change (ticket #7999) try: self._key_grabber.grab_keys(self._key_actions.keys()) except: for key in self._key_actions.keys(): self._key_grabber.grab(key) #Set up collaboration self.collaboration = CollaborationWrapper(self, self.buddy_joined, self.buddy_left, self.Play, self.game.undostack, self.bootstrap) self.connect('shared', self.collaboration._shared_cb) if self._shared_activity: # We are joining the activity self.connect('joined', self.collaboration._joined_cb) if self.get_shared(): # We've already joined self.collaboration._joined_cb() def set_up_ui(self): self.board = boardwidget.GoBoardWidget(self.game.get_status(), self.size) self.board.connect('motion-notify-event', self.board_motion_cb) self.board.connect('insert-requested', self.insert_cb) self.main_view = gtk.VBox() self.board_aspect = gtk.AspectFrame(None, .5, .5, 1, False) self.board_aspect.add(self.board) self.main_view.pack_start(self.board_aspect) self.buttons_box = gtk.HBox() self.buttons_alignment = gtk.Alignment(0.5, 1, 0.5, 1) #Pass button self.pass_button = gtk.Button(_('Pass')) self.pass_button.connect("clicked", self.pass_cb) self.buttons_box.pack_start(self.pass_button, True, True, 10) #Undo button self.undo_button = gtk.Button(_('Undo')) self.undo_button.connect("clicked", self.undo_cb) self.buttons_box.pack_start(self.undo_button, True, True, 10) self.buttons_alignment.add(self.buttons_box) self.main_view.pack_start(self.buttons_alignment, False, padding=10) self.infopanel = infopanel.InfoPanel() self.main_view.pack_start(self.infopanel, False) self.set_canvas(self.main_view) self.show_all() def insert_cb(self, widget, x, y, announce=True, ai_play=False): if self.is_editing == 0: ''' The insert function. It makes the play and manages turn changing stone drawing, etc. Parameters x and y are the coordinates of the play ((0,0) is top left), widget points to the widget that emitted the signal connected to this function, announce is True when we need to announce this play to other people collaborating, and ai_play is True when this is called by the AI, so we know not to ask for an AI play again ''' # Check if it's our turn only if it's a local play (announce is True) # Calls by other players will always be out of turn for us. if announce and self.get_currentcolor() != self.get_playercolor(): logger.debug('Play at %s x %s was out-of-turn!', x, y) self.infopanel.show(_('It\'s not your turn!')) return False # Make the play only if it wasn't a pass move. if x != -1: self.pass_count = 0 error = self.game.illegal(x, y, self.get_currentcolor()) if error: self.infopanel.show(error) return False # Make the play captures = self.game.play((x, y), self.get_currentcolor()) if self.ai_activated and not ai_play: self.notify_ai(x, y, self.get_currentcolor()) self.gameToolbar.grey_out_size_change() if captures: self.redraw_captures(captures) self.show_score() self.board.draw_stone(x, y, self.get_currentcolor(), widget) # Player passed else: self.pass_count += 1 # Announce the local play if self.get_shared() and announce: self.collaboration.Play(x, y) self.change_turn() if x == -1: self.infopanel.show(_('Opponent passed')) # If this is the second consecutive pass, the game ends if self.pass_count == 2: self.game_end() return # If we are playing a local game with AI turned off, change the color if not self.get_shared() and not self.ai_activated: self.change_player_color() # Else, if the AI is on, and this wasn't played by it, request a play by it. elif self.ai_activated: self.change_player_color() if not ai_play: self.play_ai() self.edit_status = self.game.status else: if self.edit_type == 0: if not self.board.status.has_key((x, y)): self.board.status[(x,y)] = 'X' elif self.board.status[(x,y)] == 'B': self.board.status[(x,y)] = 'E' elif self.board.status[(x,y)] == 'W': self.board.status[(x,y)] = 'F' elif self.board.status[(x,y)] == 'X': del self.board.status[(x,y)] elif self.board.status[(x,y)] == 'T': self.board.status[(x,y)] = 'X' elif self.board.status[(x,y)] == 'C': self.board.status[(x,y)] = 'X' elif self.board.status[(x,y)] == 'S': self.board.status[(x,y)] = 'X' elif self.board.status[(x,y)] == 'E': self.board.status[(x,y)] = 'B' elif self.board.status[(x,y)] == 'F': self.board.status[(x,y)] = 'W' elif self.board.status[(x,y)] == 'G': self.board.status[(x,y)] = 'E' elif self.board.status[(x,y)] == 'H': self.board.status[(x,y)] = 'F' elif self.board.status[(x,y)] == 'I': self.board.status[(x,y)] = 'E' elif self.board.status[(x,y)] == 'J': self.board.status[(x,y)] = 'F' elif self.board.status[(x,y)] == 'K': self.board.status[(x,y)] = 'E' else: self.board.status[(x,y)] = 'F' elif self.edit_type == 2: if not self.board.status.has_key((x, y)): self.board.status[(x,y)] = 'T' elif self.board.status[(x,y)] == 'B': self.board.status[(x,y)] = 'G' elif self.board.status[(x,y)] == 'W': self.board.status[(x,y)] = 'H' elif self.board.status[(x,y)] == 'X': self.board.status[(x,y)] = 'T' elif self.board.status[(x,y)] == 'T': del self.board.status[(x,y)] elif self.board.status[(x,y)] == 'C': self.board.status[(x,y)] = 'T' elif self.board.status[(x,y)] == 'S': self.board.status[(x,y)] = 'T' elif self.board.status[(x,y)] == 'E': self.board.status[(x,y)] = 'G' elif self.board.status[(x,y)] == 'F': self.board.status[(x,y)] = 'H' elif self.board.status[(x,y)] == 'G': self.board.status[(x,y)] = 'B' elif self.board.status[(x,y)] == 'H': self.board.status[(x,y)] = 'W' elif self.board.status[(x,y)] == 'I': self.board.status[(x,y)] = 'G' elif self.board.status[(x,y)] == 'J': self.board.status[(x,y)] = 'H' elif self.board.status[(x,y)] == 'K': self.board.status[(x,y)] = 'G' else: self.board.status[(x,y)] = 'H' elif self.edit_type == 1: if not self.board.status.has_key((x, y)): self.board.status[(x,y)] = 'C' elif self.board.status[(x,y)] == 'B': self.board.status[(x,y)] = 'I' elif self.board.status[(x,y)] == 'W': self.board.status[(x,y)] = 'J' elif self.board.status[(x,y)] == 'X': self.board.status[(x,y)] = 'C' elif self.board.status[(x,y)] == 'T': self.board.status[(x,y)] = 'C' elif self.board.status[(x,y)] == 'C': del self.board.status[(x,y)] elif self.board.status[(x,y)] == 'S': self.board.status[(x,y)] = 'C' elif self.board.status[(x,y)] == 'E': self.board.status[(x,y)] = 'I' elif self.board.status[(x,y)] == 'F': self.board.status[(x,y)] = 'J' elif self.board.status[(x,y)] == 'G': self.board.status[(x,y)] = 'I' elif self.board.status[(x,y)] == 'H': self.board.status[(x,y)] = 'J' elif self.board.status[(x,y)] == 'I': self.board.status[(x,y)] = 'B' elif self.board.status[(x,y)] == 'J': self.board.status[(x,y)] = 'W' elif self.board.status[(x,y)] == 'K': self.board.status[(x,y)] = 'I' else: self.board.status[(x,y)] = 'J' else: if not self.board.status.has_key((x, y)): self.board.status[(x,y)] = 'S' elif self.board.status[(x,y)] == 'B': self.board.status[(x,y)] = 'K' elif self.board.status[(x,y)] == 'W': self.board.status[(x,y)] = 'L' elif self.board.status[(x,y)] == 'X': self.board.status[(x,y)] = 'S' elif self.board.status[(x,y)] == 'T': self.board.status[(x,y)] = 'S' elif self.board.status[(x,y)] == 'C': self.board.status[(x,y)] = 'S' elif self.board.status[(x,y)] == 'S': del self.board.status[(x,y)] elif self.board.status[(x,y)] == 'E': self.board.status[(x,y)] = 'K' elif self.board.status[(x,y)] == 'F': self.board.status[(x,y)] = 'L' elif self.board.status[(x,y)] == 'G': self.board.status[(x,y)] = 'K' elif self.board.status[(x,y)] == 'H': self.board.status[(x,y)] = 'L' elif self.board.status[(x,y)] == 'I': self.board.status[(x,y)] = 'K' elif self.board.status[(x,y)] == 'J': self.board.status[(x,y)] = 'L' elif self.board.status[(x,y)] == 'K': self.board.status[(x,y)] = 'B' else: self.board.status[(x,y)] = 'W' self.board.do_expose_event() def undo_cb(self, widget=None, data=None): if self.game.undo(): self.board.queue_draw() # If playing against AI undo twice if self.ai_activated: self.ai.undo() self.game.undo() self.ai.undo() else: self.change_turn() if not self.get_shared() and not self.ai_activated: self.change_player_color() self.show_score() def pass_cb(self, widget=None, data=None): if self.get_shared(): if self.get_currentcolor() == self.get_playercolor(): self.pass_count += 1 self.collaboration.Play(-1, -1) else: self.infopanel.show(_('It\'s not your turn!')) return else: self.pass_count += 1 self.change_player_color() self.change_turn() if self.pass_count == 2: self.game_end() if self.ai_activated: self.ai.pass_move(self.get_currentcolor()) self.play_ai() def write_file(self, file_path): logger.debug('Writing file: %s', file_path) # Strip the undostack undostack = self.game.undostack[:] strippedstack = [] for pos, color, captures in undostack: strippedstack.append(pos) f = open(file_path, 'w') try: cPickle.dump(strippedstack, f, cPickle.HIGHEST_PROTOCOL) finally: f.close() self.metadata['our-color'] = self.get_playercolor() self.metadata['shared'] = str(self.get_shared()) self.metadata['size'] = str(self.size) self.metadata['ai'] = str(self.ai_activated) def read_file(self, file_path): logger.debug('Reading file: %s', file_path) f = open(file_path, 'r') try: newstack = cPickle.load(f) finally: f.close() if self.get_shared(): logger.debug('The game we are loading is shared!') self.PlayerColor = self.metadata.get('our-color', 'B') if self.size != self.metadata.get('size', DEFAULT_SIZE): self.board_size_change(None, int(self.metadata.get('size', DEFAULT_SIZE))) self.bootstrap(newstack) if self.metadata.get('ai', None) == 'True': self.gameToolbar._size_combo.set_sensitive(False) self.gameToolbar._ai_button.set_active(True) # This triggers the 'toggled' signal too def board_motion_cb(self, widget, event): x, y = self.board.get_mouse_event_xy(event) if x == self.lastX and y == self.lastY: return if not self.game.is_occupied(x, y) and self.game.legal((x, y), self.get_playercolor()): self.board.draw_ghost_stone(x, y, self.get_playercolor()) self.lastX = x self.lastY = y def invert_color(self, color): if color == 'B': return 'W' return 'B' def get_currentcolor(self): return self.CurrentColor def change_turn(self): # It's the other guy's turn now if self.CurrentColor == 'B': self.infopanel.show(_('White\'s turn')) else: self.infopanel.show(_('Black\'s turn')) self.CurrentColor = self.invert_color(self.get_currentcolor()) def get_playercolor(self): return self.PlayerColor def change_player_color(self): self.PlayerColor = self.invert_color(self.get_playercolor()) def set_player_color(self, color): self.PlayerColor = color def redraw_captures(self, captures): for x in captures: self.board.redraw_area(x[0], x[1]) def bootstrap(self, plays): ''' Take our game to the state it would have if @plays were manually played''' logger.debug('Bootstraping...') self.board.do_expose_event() # HACK: Looks like read_file is called before the board is exposed for pos in plays: logger.debug('Playing at %s with color %s', pos, self.get_currentcolor()) captures = self.game.play((pos[0], pos[1]), self.get_currentcolor()) if captures: self.redraw_captures(captures) self.change_turn() self.change_player_color() logger.debug('Color after bootstraping is %s', self.get_currentcolor()) self.show_score() self.board.do_expose_event() def restart_game(self, widget=None): logger.debug('Received restart signal!') self.CurrentColor = 'B' self.PlayerColor = 'B' self.pass_count = 0 self.edit_status = { } self.game.clear() self.board.territories = None self.board.status = self.game.status self.board.do_expose_event() self.show_score() self.board.set_sensitive(True) self.buttons_box.set_sensitive(True) self.tutorialToolbar.reset_cb() self.tutorialToolbar.grey_out_previous() self.tutorialToolbar.grey_out_next() self.tutorialToolbar.grey_out_category() self.tutorialToolbar.activate_begin() self.editToolbar.activate_edit() self.editToolbar.grey_out_add_x() self.editToolbar.grey_out_add_square() self.editToolbar.grey_out_add_circle() self.editToolbar.grey_out_add_triangle() self.editToolbar.activate_save() self.editToolbar.activate_load() self.gameToolbar.activate_size_change() self.gameToolbar.activate_ai() self.current_tutorial = 0; self.lastX = -1 self.lastY = -1 self.infopanel.show(self.script[0]) if self.ai_activated: self.ai.clear() def game_end(self): self.board.set_sensitive(False) self.buttons_box.set_sensitive(False) territories = self.game.get_territories() self.board.territories = territories final_score = {'B':(len(territories['B']) - self.game.get_score()['W']), 'W':(len(territories['W']) - self.game.get_score()['B'] + self.komi)} if final_score['B'] > final_score['W']: winner_string = _('Black wins!') elif final_score['W'] > final_score['B']: winner_string = _('White wins!') else: winner_string = _('There was a tie!') self.infopanel.show(_('Game ended! %s' % winner_string)) self.infopanel.show_score(_('Final score: White %(W)g - Black %(B)g' % final_score)) def board_size_change(self, widget, size): self.lastY = -1 self.lastX = -1 if size == self.size: return self.size = size del self.game self.game = GoGame(size) self.board_aspect.remove(self.board) del self.board self.board = boardwidget.GoBoardWidget(self.game.get_status(), int(size)) self.board_aspect.add(self.board) self.board.connect('motion-notify-event', self.board_motion_cb) self.board.connect('insert-requested', self.insert_cb) self.board.show() if self.ai_activated: del self.ai self.ai = gnugo(boardsize=self.size) def ai_activated_cb(self, widget=None): try: self.ai = gnugo(boardsize=self.size) except Exception, e: self._alert(_('AI'), _('GnuGo loading failed!: %s' % e)) self.gameToolbar.set_ai_button_state(False) else: self.ai_activated = True for pos, color, captures in self.game.undostack: self.notify_ai(pos[0], pos[1], color) self._alert(_('AI'), _('PlayGo AI Activated')) def ai_deactivated_cb(self, widget): if self.ai: self.ai_activated = False del self.ai self._alert(_('AI'), _('PlayGo AI Deactivated')) def notify_ai(self, x, y, color): logger.debug('Notifying AI of play by %s at %s x %s', color, x, y) self.ai.make_play(color, x, y) def play_ai(self): if self.get_currentcolor() == self.get_playercolor(): x, y = self.ai.get_move(self.get_currentcolor()) logger.debug('Got play %s x %s from AI', x, y) self.insert_cb(None, x, y, ai_play=True) #logger.debug('Dumping board: %s', self.ai.dump_board()) def show_score(self): self.infopanel.show_score(_("Score is: White %(W)g - Black %(B)g" % self.game.get_score())) def _alert(self, title, text=None): from sugar.graphics.alert import NotifyAlert alert = NotifyAlert(timeout=5) alert.props.title = title alert.props.msg = text self.add_alert(alert) alert.connect('response', self._alert_cancel_cb) alert.show() def _alert_cancel_cb(self, alert, response_id): self.remove_alert(alert) # ----------- Tutorial event functions ---------- # # What should these do? # There should be a specific script and amount of pages. # For these pages, there should be a flag signifying if the board needs to be changed or not. # If yes, then clear the board and redraw the board. # If no, then continue as normal. # Each page has a script which will be printed out to the user, which will explain the current item. def begin_cb(self, widget = None): del self.game self.game = GoGame(19) self.board_aspect.remove(self.board) del self.board self.board = boardwidget.GoBoardWidget(self.game.get_status(), int(19)) self.board_aspect.add(self.board) self.board.connect('motion-notify-event', self.board_motion_cb) self.board.connect('insert-requested', self.insert_cb) self.board.show() self.game.clear() self.board.set_sensitive(False) self.buttons_box.set_sensitive(False) self.board.territories = None self.board.status = self.game.status self.board.do_expose_event() self.gameToolbar.grey_out_size_change() self.gameToolbar.grey_out_ai() self.tutorialToolbar.activate_previous() self.tutorialToolbar.activate_next() self.tutorialToolbar.activate_category() self.editToolbar.grey_out_edit() self.editToolbar.grey_out_add_x() self.editToolbar.grey_out_add_square() self.editToolbar.grey_out_add_circle() self.editToolbar.grey_out_add_triangle() self.editToolbar.grey_out_save() self.editToolbar.grey_out_load() self.infopanel.show(self.script[0]) def previous_category(self, widget = None): self.board.set_sensitive(False) self.buttons_box.set_sensitive(False) self.board.territories = None self.board.status = self.game.status self.board.do_expose_event() self.infopanel.show(self.script[self.current_tutorial]) def next_category(self, widget = None): if self.current_tutorial != 53: self.current_tutorial += 1 self.board.set_sensitive(False) self.buttons_box.set_sensitive(False) self.board.territories = None self.board.status = self.game.status self.board.do_expose_event() self.infopanel.show(self.script[self.current_tutorial]) def category_cb(self, widget, category): self.board.set_sensitive(False) self.buttons_box.set_sensitive(False) self.board.territories = None self.current_tutorial = int(self.next_script_frame[category]) if self.current_tutorial == 0: self.game.clear() elif self.current_tutorial == 1: self.game.clear() elif self.current_tutorial == 3: self.game.clear() elif self.current_tutorial == 6: self.game.clear() self.game.status[(7,0)] = 'B' self.game.status[(8,1)] = 'B' self.game.status[(9,1)] = 'B' self.game.status[(10,1)] = 'B' self.game.status[(11,1)] = 'B' self.game.status[(12,0)] = 'B' self.game.status[(0,7)] = 'B' self.game.status[(0,1)] = 'W' self.game.status[(1,2)] = 'W' self.game.status[(1,3)] = 'W' self.game.status[(1,4)] = 'W' self.game.status[(1,5)] = 'W' self.game.status[(1,6)] = 'W' elif self.current_tutorial == 8: self.game.clear() self.game.status[(7,0)] = 'B' self.game.status[(8,1)] = 'B' self.game.status[(9,1)] = 'B' self.game.status[(10,1)] = 'B' self.game.status[(11,1)] = 'B' self.game.status[(12,0)] = 'B' self.game.status[(0,7)] = 'B' self.game.status[(0,1)] = 'W' self.game.status[(1,2)] = 'W' self.game.status[(1,3)] = 'W' self.game.status[(1,4)] = 'W' self.game.status[(1,5)] = 'W' self.game.status[(1,6)] = 'W' elif self.current_tutorial == 11: self.game.clear() self.game.status[(11,4)] = 'B' self.game.status[(10,4)] = 'S' self.game.status[(12,4)] = 'S' self.game.status[(11,3)] = 'S' self.game.status[(11,5)] = 'S' elif self.current_tutorial == 15: self.game.clear() self.game.status[(9,3)] = 'B' self.game.status[(8,4)] = 'B' self.game.status[(15,9)] = 'B' self.game.status[(15,10)] = 'B' self.game.status[(8,3)] = 'W' self.game.status[(8,5)] = 'W' self.game.status[(9,4)] = 'W' self.game.status[(7,4)] = 'T' elif self.current_tutorial == 18: self.game.clear() self.game.status[(8,2)] = 'B' self.game.status[(9,1)] = 'B' self.game.status[(9,0)] = 'B' self.game.status[(7,0)] = 'W' self.game.status[(7,1)] = 'W' self.game.status[(7,2)] = 'W' self.game.status[(8,0)] = 'C' self.game.status[(8,1)] = 'C' elif self.current_tutorial == 21: self.game.clear() self.game.status[(9,9)] = 'B' self.game.status[(10,8)] = 'B' self.game.status[(10,10)] = 'B' self.game.status[(11,9)] = 'B' self.game.status[(9,8)] = 'W' self.game.status[(9,10)] = 'W' self.game.status[(8,9)] = 'W' self.game.status[(10,9)] = 'X' elif self.current_tutorial == 25: self.game.clear() self.game.status[(9,9)] = 'B' self.game.status[(10,8)] = 'B' self.game.status[(10,10)] = 'B' self.game.status[(11,9)] = 'B' self.game.status[(9,12)] = 'B' self.game.status[(9,14)] = 'B' self.game.status[(8,13)] = 'B' self.game.status[(9,8)] = 'W' self.game.status[(9,10)] = 'W' self.game.status[(8,9)] = 'W' self.game.status[(9,13)] = 'W' self.game.status[(10,12)] = 'W' self.game.status[(10,14)] = 'W' self.game.status[(11,13)] = 'W' elif self.current_tutorial == 29: self.game.clear() self.game.status[(7,0)] = 'B' self.game.status[(8,0)] = 'B' self.game.status[(8,1)] = 'B' self.game.status[(9,0)] = 'B' self.game.status[(9,1)] = 'B' self.game.status[(9,2)] = 'B' self.game.status[(10,1)] = 'B' self.game.status[(10,2)] = 'B' self.game.status[(11,0)] = 'B' self.game.status[(11,1)] = 'B' self.game.status[(12,0)] = 'B' self.game.status[(6,0)] = 'W' self.game.status[(7,1)] = 'W' self.game.status[(7,2)] = 'W' self.game.status[(8,3)] = 'W' self.game.status[(9,3)] = 'W' self.game.status[(10,3)] = 'W' self.game.status[(11,2)] = 'W' self.game.status[(12,2)] = 'W' self.game.status[(12,1)] = 'W' self.game.status[(13,1)] = 'W' self.game.status[(13,0)] = 'W' elif self.current_tutorial == 33: self.game.clear() self.game.status[(10,16)] = 'B' self.game.status[(10,17)] = 'B' self.game.status[(11,15)] = 'B' self.game.status[(11,17)] = 'B' self.game.status[(11,18)] = 'B' self.game.status[(12,16)] = 'B' self.game.status[(12,17)] = 'B' self.game.status[(12,18)] = 'B' self.game.status[(13,16)] = 'B' self.game.status[(13,17)] = 'B' self.game.status[(14,18)] = 'B' self.game.status[(2,18)] = 'W' self.game.status[(3,18)] = 'W' self.game.status[(3,17)] = 'W' self.game.status[(4,16)] = 'W' self.game.status[(5,17)] = 'W' self.game.status[(6,17)] = 'W' self.game.status[(7,17)] = 'W' self.game.status[(7,18)] = 'W' self.game.status[(8,18)] = 'W' self.game.status[(4,18)] = 'T' self.game.status[(11,16)] = 'C' self.game.status[(5,18)] = 'S' elif self.current_tutorial == 38: self.game.clear() self.game.status[(7,0)] = 'B' self.game.status[(7,1)] = 'B' self.game.status[(7,2)] = 'B' self.game.status[(7,3)] = 'B' self.game.status[(7,4)] = 'B' self.game.status[(8,5)] = 'B' self.game.status[(9,5)] = 'B' self.game.status[(10,0)] = 'B' self.game.status[(10,1)] = 'B' self.game.status[(10,2)] = 'B' self.game.status[(10,3)] = 'B' self.game.status[(10,4)] = 'B' self.game.status[(9,0)] = 'W' self.game.status[(9,1)] = 'W' self.game.status[(9,2)] = 'W' self.game.status[(9,3)] = 'W' self.game.status[(9,4)] = 'W' self.game.status[(10,5)] = 'W' self.game.status[(11,5)] = 'W' self.game.status[(12,0)] = 'W' self.game.status[(12,1)] = 'W' self.game.status[(12,2)] = 'W' self.game.status[(12,3)] = 'W' self.game.status[(12,4)] = 'W' elif self.current_tutorial == 41: self.game.clear() self.game.status[(3,0)] = 'B' self.game.status[(3,1)] = 'B' self.game.status[(4,2)] = 'B' self.game.status[(5,2)] = 'B' self.game.status[(6,2)] = 'B' self.game.status[(7,2)] = 'B' self.game.status[(8,2)] = 'B' self.game.status[(4,0)] = 'W' self.game.status[(4,1)] = 'W' self.game.status[(5,1)] = 'W' self.game.status[(6,0)] = 'W' self.game.status[(6,1)] = 'W' self.game.status[(7,1)] = 'W' self.game.status[(8,1)] = 'W' self.game.status[(8,0)] = 'C' self.game.status[(9,1)] = 'E' elif self.current_tutorial == 48: self.game.clear() else: self.game.status = self.game.status self.board.status = self.game.status self.board.do_expose_event() self.infopanel.show(self.script[self.current_tutorial]) # ----------- Editor Functions ------------------ # def edit_cb(self, widget=None): if self.is_editing == 0: self.is_editing = 1 if self.edit_type == 0: self.editToolbar.grey_out_add_x() self.editToolbar.activate_add_circle() self.editToolbar.activate_add_triangle() self.editToolbar.activate_add_square() elif self.edit_type == 1: self.editToolbar.activate_add_x() self.editToolbar.grey_out_add_circle() self.editToolbar.activate_add_triangle() self.editToolbar.activate_add_square() elif self.edit_type == 2: self.editToolbar.activate_add_x() self.editToolbar.activate_add_circle() self.editToolbar.grey_out_add_triangle() self.editToolbar.activate_add_square() else: self.editToolbar.activate_add_x() self.editToolbar.activate_add_circle() self.editToolbar.activate_add_triangle() self.editToolbar.grey_out_add_square() else: self.is_editing = 0 self.editToolbar.grey_out_add_x() self.editToolbar.grey_out_add_circle() self.editToolbar.grey_out_add_triangle() self.editToolbar.grey_out_add_square() self.board.status = self.edit_status self.game.status = self.edit_status def add_x_cb(self, widget=None): self.editToolbar.grey_out_add_x() self.edit_type = 0 self.editToolbar.activate_add_circle() self.editToolbar.activate_add_triangle() self.editToolbar.activate_add_square() def add_circle_cb(self, widget=None): self.editToolbar.grey_out_add_circle() self.edit_type = 1 self.editToolbar.activate_add_x() self.editToolbar.activate_add_triangle() self.editToolbar.activate_add_square() def add_triangle_cb(self, widget=None): self.editToolbar.grey_out_add_triangle() self.edit_type = 2 self.editToolbar.activate_add_x() self.editToolbar.activate_add_circle() self.editToolbar.activate_add_square() def add_square_cb(self, widget=None): self.editToolbar.grey_out_add_square() self.edit_type = 3 self.editToolbar.activate_add_x() self.editToolbar.activate_add_circle() self.editToolbar.activate_add_triangle() def save_cb(self, widget=None): self.infopanel.show(_("To be implemented in the future!")) def load_cb(self, widget=None): self.infopanel.show(_("To be implemented in the future!")) # ----------- Keypad events functions ----------- # def _key_pressed_cb(self, grabber, keycode, state): key = grabber.get_key(keycode, state) logging.debug("Key pressed: %s", key) action = self._key_actions[key] method = getattr(self, 'handle_' + action) method() def handle_move_up(self): self.move_ghost_stone(0, -1) def handle_move_right(self): self.move_ghost_stone(1, 0) def handle_move_down(self): self.move_ghost_stone(0, 1) def handle_move_left(self): self.move_ghost_stone(-1, 0) def handle_place_stone(self): self.insert_cb(None, self.lastX, self.lastY) def handle_undo(self): self.undo_cb() def handle_pass(self): self.pass_cb() def move_ghost_stone(self, deltaX=0, deltaY=0): if self.lastX < 0: self.lastX = int(self.size/2) self.lastY = int(self.size/2) x = self.lastX + deltaX y = self.lastY + deltaY if x < 0 or x > self.size - 1 or y < 0 or y > self.size - 1: return self.board.draw_ghost_stone(x, y, self.get_playercolor()) self.lastX = x self.lastY = y # ------- Callbacks for Collaboration ------- # def buddy_joined(self, buddy): self._alert(_('Buddy joined'), _('%s joined' % buddy.props.nick)) def buddy_left(self, buddy): self._alert(_('Buddy left'), _('%s left' % buddy.props.nick)) def Play(self, x, y, sender=None): ''' Called when a stone was placed at x,y by sender''' # Discard a pass move received in our turn. Do it here for extra security if x == -1 and self.get_currentcolor() == self.get_playercolor(): return self.insert_cb(None, x, y, False)