new tictactoe plugin
This commit is contained in:
1
tictactoe/__init__.py
Normal file
1
tictactoe/__init__.py
Normal file
@@ -0,0 +1 @@
|
||||
from plugin import TictactoePlugin
|
||||
7
tictactoe/manifest.ini
Normal file
7
tictactoe/manifest.ini
Normal file
@@ -0,0 +1,7 @@
|
||||
[info]
|
||||
name: Tic tac toe
|
||||
short_name: Tic tac toe
|
||||
version: 0.1
|
||||
description: Play tic tac toe
|
||||
authors = Yann Leboulanger <asterix@lagaule.org>
|
||||
homepage = www.gajim.org
|
||||
717
tictactoe/plugin.py
Normal file
717
tictactoe/plugin.py
Normal file
@@ -0,0 +1,717 @@
|
||||
## plugins/tictactoe/plugin.py
|
||||
##
|
||||
## Copyright (C) 2011 Yann Leboulanger <asterix AT lagaule.org>
|
||||
##
|
||||
## This file is part of Gajim.
|
||||
##
|
||||
## Gajim 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; version 3 only.
|
||||
##
|
||||
## Gajim 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 Gajim. If not, see <http://www.gnu.org/licenses/>.
|
||||
##
|
||||
|
||||
'''
|
||||
Tictactoe plugin.
|
||||
|
||||
:author: Yann Leboulanger <asterix@lagaule.org>
|
||||
:since: 21 November 2011
|
||||
:copyright: Copyright (2011) Yann Leboulanger <asterix@lagaule.org>
|
||||
:license: GPL
|
||||
'''
|
||||
|
||||
|
||||
from common import helpers
|
||||
from common import gajim
|
||||
from plugins import GajimPlugin
|
||||
from plugins.plugin import GajimPluginException
|
||||
from plugins.helpers import log_calls, log
|
||||
import common.xmpp
|
||||
import gtk
|
||||
from gtk import gdk
|
||||
import cairo
|
||||
import chat_control
|
||||
from common import ged
|
||||
import dialogs
|
||||
from common import xmpp
|
||||
from common import caps_cache
|
||||
from common import stanza_session
|
||||
from common.connection_handlers_events import InformationEvent
|
||||
|
||||
NS_GAMES = 'http://jabber.org/protocol/games'
|
||||
NS_GAMES_TICTACTOE = NS_GAMES + '/tictactoe'
|
||||
|
||||
class TictactoePlugin(GajimPlugin):
|
||||
@log_calls('TictactoePlugin')
|
||||
def init(self):
|
||||
self.description = _('Play Tictactoe.')
|
||||
self.config_dialog = None
|
||||
self.events_handlers = {
|
||||
'decrypted-message-received': (ged.GUI1,
|
||||
self._nec_decrypted_message_received),
|
||||
}
|
||||
self.gui_extension_points = {
|
||||
'chat_control_base' : (self.connect_with_chat_control,
|
||||
self.disconnect_from_chat_control),
|
||||
'chat_control_base_update_toolbar': (self.update_button_state,
|
||||
None),
|
||||
}
|
||||
self.controls = []
|
||||
|
||||
@log_calls('TictactoePlugin')
|
||||
def _compute_caps_hash(self):
|
||||
for a in gajim.connections:
|
||||
gajim.caps_hash[a] = caps_cache.compute_caps_hash([
|
||||
gajim.gajim_identity], gajim.gajim_common_features + \
|
||||
gajim.gajim_optional_features[a])
|
||||
# re-send presence with new hash
|
||||
connected = gajim.connections[a].connected
|
||||
if connected > 1 and gajim.SHOW_LIST[connected] != 'invisible':
|
||||
gajim.connections[a].change_status(gajim.SHOW_LIST[connected],
|
||||
gajim.connections[a].status)
|
||||
|
||||
@log_calls('TictactoePlugin')
|
||||
def activate(self):
|
||||
if NS_GAMES not in gajim.gajim_common_features:
|
||||
gajim.gajim_common_features.append(NS_GAMES)
|
||||
if NS_GAMES_TICTACTOE not in gajim.gajim_common_features:
|
||||
gajim.gajim_common_features.append(NS_GAMES_TICTACTOE)
|
||||
self._compute_caps_hash()
|
||||
|
||||
@log_calls('TictactoePlugin')
|
||||
def deactivate(self):
|
||||
if NS_GAMES_TICTACTOE in gajim.gajim_common_features:
|
||||
gajim.gajim_common_features.remove(NS_GAMES_TICTACTOE)
|
||||
if NS_GAMES in gajim.gajim_common_features:
|
||||
gajim.gajim_common_features.remove(NS_GAMES)
|
||||
self._compute_caps_hash()
|
||||
|
||||
@log_calls('TictactoePlugin')
|
||||
def connect_with_chat_control(self, control):
|
||||
if isinstance(control, chat_control.ChatControl):
|
||||
base = Base(self, control)
|
||||
self.controls.append(base)
|
||||
# Already existing session?
|
||||
conn = gajim.connections[control.account]
|
||||
sessions = conn.get_sessions(control.contact.jid)
|
||||
tictactoes = [s for s in sessions if isinstance(s,
|
||||
TicTacToeSession)]
|
||||
if tictactoes:
|
||||
base.tictactoe = tictactoes[0]
|
||||
base.button.set_active(True)
|
||||
|
||||
@log_calls('TictactoePlugin')
|
||||
def disconnect_from_chat_control(self, chat_control):
|
||||
for base in self.controls:
|
||||
base.disconnect_from_chat_control()
|
||||
self.controls = []
|
||||
|
||||
@log_calls('TictactoePlugin')
|
||||
def update_button_state(self, control):
|
||||
for base in self.controls:
|
||||
if base.chat_control == control:
|
||||
if control.contact.supports(NS_GAMES) and \
|
||||
control.contact.supports(NS_GAMES_TICTACTOE):
|
||||
base.button.set_sensitive(True)
|
||||
tooltip_text = _('Play tictactoe')
|
||||
else:
|
||||
base.button.set_sensitive(False)
|
||||
tooltip_text = _('Client on the other side '
|
||||
'does not support playing tictactoe')
|
||||
base.button.set_tooltip_text(tooltip_text)
|
||||
|
||||
@log_calls('TictactoePlugin')
|
||||
def show_request_dialog(self, obj, session):
|
||||
def on_ok():
|
||||
session.invited(obj.stanza)
|
||||
|
||||
def on_cancel():
|
||||
session.decline_invitation()
|
||||
|
||||
account = obj.conn.name
|
||||
contact = gajim.contacts.get_first_contact_from_jid(account, obj.jid)
|
||||
if contact:
|
||||
name = contact.get_shown_name()
|
||||
else:
|
||||
name = obj.jid
|
||||
pritext = _('Incoming Tictactoe')
|
||||
sectext = _('%(name)s (%(jid)s) wants to play tictactoe with you. '
|
||||
'Do you want to accept?') % {'name': name, 'jid': obj.jid}
|
||||
dialog = dialogs.NonModalConfirmationDialog(pritext, sectext=sectext,
|
||||
on_response_ok=on_ok, on_response_cancel=on_cancel)
|
||||
dialog.popup()
|
||||
|
||||
@log_calls('TictactoePlugin')
|
||||
def _nec_decrypted_message_received(self, obj):
|
||||
if isinstance(obj.session, TicTacToeSession):
|
||||
obj.session.received(obj.stanza)
|
||||
game_invite = obj.stanza.getTag('invite', namespace=NS_GAMES)
|
||||
if game_invite:
|
||||
account = obj.conn.name
|
||||
game = game_invite.getTag('game')
|
||||
if game and game.getAttr('var') == NS_GAMES_TICTACTOE:
|
||||
session = obj.conn.make_new_session(obj.fjid, obj.thread_id,
|
||||
cls=TicTacToeSession)
|
||||
self.show_request_dialog(obj, session)
|
||||
|
||||
class Base(object):
|
||||
def __init__(self, plugin, chat_control):
|
||||
self.plugin = plugin
|
||||
self.chat_control = chat_control
|
||||
self.contact = self.chat_control.contact
|
||||
self.account = self.chat_control.account
|
||||
self.fjid = self.contact.get_full_jid()
|
||||
self.create_buttons()
|
||||
self.tictactoe = None
|
||||
|
||||
def create_buttons(self):
|
||||
# create whiteboard button
|
||||
actions_hbox = self.chat_control.xml.get_object('actions_hbox')
|
||||
self.button = gtk.ToggleButton(label=None, use_underline=True)
|
||||
self.button.set_property('relief', gtk.RELIEF_NONE)
|
||||
self.button.set_property('can-focus', False)
|
||||
img = gtk.Image()
|
||||
img_path = self.plugin.local_file_path('tictactoe.png')
|
||||
pixbuf = gtk.gdk.pixbuf_new_from_file(img_path)
|
||||
iconset = gtk.IconSet(pixbuf=pixbuf)
|
||||
factory = gtk.IconFactory()
|
||||
factory.add('tictactoe', iconset)
|
||||
factory.add_default()
|
||||
img.set_from_stock('tictactoe', gtk.ICON_SIZE_MENU)
|
||||
self.button.set_image(img)
|
||||
send_button = self.chat_control.xml.get_object('send_button')
|
||||
send_button_pos = actions_hbox.child_get_property(send_button,
|
||||
'position')
|
||||
actions_hbox.add_with_properties(self.button, 'position',
|
||||
send_button_pos - 1, 'expand', False)
|
||||
id_ = self.button.connect('toggled', self.on_tictactoe_button_toggled)
|
||||
self.chat_control.handlers[id_] = self.button
|
||||
self.button.show()
|
||||
|
||||
def on_tictactoe_button_toggled(self, widget):
|
||||
"""
|
||||
Popup whiteboard
|
||||
"""
|
||||
if widget.get_active():
|
||||
if not self.tictactoe:
|
||||
self.start_tictactoe()
|
||||
else:
|
||||
self.stop_tictactoe('resign')
|
||||
|
||||
def start_tictactoe(self):
|
||||
self.tictactoe = gajim.connections[self.account].make_new_session(
|
||||
self.fjid, cls=TicTacToeSession)
|
||||
self.tictactoe.base = self
|
||||
self.tictactoe.begin()
|
||||
|
||||
def stop_tictactoe(self, reason=None):
|
||||
self.tictactoe.end_game(reason)
|
||||
self.tictactoe.board.win.destroy()
|
||||
self.tictactoe = None
|
||||
|
||||
def disconnect_from_chat_control(self):
|
||||
actions_hbox = self.chat_control.xml.get_object('actions_hbox')
|
||||
actions_hbox.remove(self.button)
|
||||
|
||||
class InvalidMove(Exception):
|
||||
pass
|
||||
|
||||
class TicTacToeSession(stanza_session.StanzaSession):
|
||||
def __init__(self, conn, jid, thread_id, type_):
|
||||
stanza_session.StanzaSession.__init__(self, conn, jid, thread_id, type_)
|
||||
contact = gajim.contacts.get_contact(conn.name,
|
||||
gajim.get_jid_without_resource(str(jid)))
|
||||
self.name = contact.get_shown_name()
|
||||
self.base = None
|
||||
|
||||
# initiate a session
|
||||
def begin(self, rows=3, cols=3, role_s='x'):
|
||||
self.rows = rows
|
||||
self.cols = cols
|
||||
|
||||
self.role_s = role_s
|
||||
|
||||
self.strike = 3
|
||||
|
||||
if self.role_s == 'x':
|
||||
self.role_o = 'o'
|
||||
else:
|
||||
self.role_o = 'x'
|
||||
|
||||
self.send_invitation()
|
||||
|
||||
self.next_move_id = 1
|
||||
self.received = self.wait_for_invite_response
|
||||
|
||||
def send_invitation(self):
|
||||
msg = xmpp.Message()
|
||||
|
||||
invite = msg.NT.invite
|
||||
invite.setNamespace(NS_GAMES)
|
||||
invite.setAttr('type', 'new')
|
||||
|
||||
game = invite.NT.game
|
||||
game.setAttr('var', NS_GAMES_TICTACTOE)
|
||||
|
||||
x = xmpp.DataForm(typ='submit')
|
||||
f = x.setField('role')
|
||||
f.setType('list-single')
|
||||
f.setValue('x')
|
||||
f = x.setField('rows')
|
||||
f.setType('text-single')
|
||||
f.setValue('3')
|
||||
f = x.setField('cols')
|
||||
f.setType('text-single')
|
||||
f.setValue('3')
|
||||
f = x.setField('strike')
|
||||
f.setType('text-single')
|
||||
f.setValue('3')
|
||||
|
||||
game.addChild(node=x)
|
||||
|
||||
self.send(msg)
|
||||
|
||||
def read_invitation(self, msg):
|
||||
invite = msg.getTag('invite', namespace=NS_GAMES)
|
||||
game = invite.getTag('game')
|
||||
x = game.getTag('x', namespace='jabber:x:data')
|
||||
|
||||
form = xmpp.DataForm(node=x)
|
||||
|
||||
if form.getField('role'):
|
||||
self.role_o = form.getField('role').getValues()[0]
|
||||
else:
|
||||
self.role_o = 'x'
|
||||
|
||||
if form.getField('rows'):
|
||||
self.rows = int(form.getField('rows').getValues()[0])
|
||||
else:
|
||||
self.rows = 3
|
||||
|
||||
if form.getField('cols'):
|
||||
self.cols = int(form.getField('cols').getValues()[0])
|
||||
else:
|
||||
self.cols = 3
|
||||
|
||||
# number in a row needed to win
|
||||
if form.getField('strike'):
|
||||
self.strike = int(form.getField('strike').getValues()[0])
|
||||
else:
|
||||
self.strike = 3
|
||||
|
||||
# received an invitation
|
||||
def invited(self, msg):
|
||||
self.read_invitation(msg)
|
||||
|
||||
# the number of the move about to be made
|
||||
self.next_move_id = 1
|
||||
|
||||
# display the board
|
||||
self.board = TicTacToeBoard(self, self.rows, self.cols)
|
||||
|
||||
# accept the invitation, join the game
|
||||
response = xmpp.Message()
|
||||
|
||||
join = response.NT.join
|
||||
join.setNamespace(NS_GAMES)
|
||||
|
||||
self.send(response)
|
||||
|
||||
if self.role_o == 'x':
|
||||
self.role_s = 'o'
|
||||
|
||||
self.their_turn()
|
||||
else:
|
||||
self.role_s = 'x'
|
||||
self.role_o = 'o'
|
||||
|
||||
self.our_turn()
|
||||
|
||||
# just sent an invitation, expecting a reply
|
||||
def wait_for_invite_response(self, msg):
|
||||
if msg.getTag('join', namespace=NS_GAMES):
|
||||
self.board = TicTacToeBoard(self, self.rows, self.cols)
|
||||
|
||||
if self.role_s == 'x':
|
||||
self.our_turn()
|
||||
else:
|
||||
self.their_turn()
|
||||
|
||||
elif msg.getTag('decline', namespace=NS_GAMES):
|
||||
gajim.nec.push_incoming_event(InformationEvent(None, conn=self.conn,
|
||||
level='info', pri_txt=_('Invitation refused'),
|
||||
sec_txt=_('%(name)s refused your invitation to play tic tac '
|
||||
'toe.') % {'name': self.name}))
|
||||
self.conn.delete_session(str(self.jid), self.thread_id)
|
||||
if self.base:
|
||||
self.base.button.set_active(False)
|
||||
|
||||
def decline_invitation(self):
|
||||
msg = xmpp.Message()
|
||||
|
||||
terminate = msg.NT.decline
|
||||
terminate.setNamespace(NS_GAMES)
|
||||
|
||||
self.send(msg)
|
||||
|
||||
def treat_terminate(self, msg):
|
||||
term = msg.getTag('terminate', namespace=NS_GAMES)
|
||||
if term:
|
||||
if term.getAttr('reason') == 'resign':
|
||||
self.board.state = 'resign'
|
||||
self.board.win.queue_draw()
|
||||
self.received = self.game_over
|
||||
return True
|
||||
|
||||
# silently ignores any received messages
|
||||
def ignore(self, msg):
|
||||
self.treat_terminate(msg)
|
||||
|
||||
def game_over(self, msg):
|
||||
invite = msg.getTag('invite', namespace=NS_GAMES)
|
||||
|
||||
# ignore messages unless they're renewing the game
|
||||
if invite and invite.getAttr('type') == 'renew':
|
||||
self.invited(msg)
|
||||
|
||||
def wait_for_move(self, msg):
|
||||
if self.treat_terminate(msg):
|
||||
return
|
||||
turn = msg.getTag('turn', namespace=NS_GAMES)
|
||||
move = turn.getTag('move', namespace=NS_GAMES_TICTACTOE)
|
||||
|
||||
row = int(move.getAttr('row'))
|
||||
col = int(move.getAttr('col'))
|
||||
id_ = int(move.getAttr('id'))
|
||||
|
||||
if id_ != self.next_move_id:
|
||||
print 'unexpected move id, lost a move somewhere?'
|
||||
return
|
||||
|
||||
try:
|
||||
self.board.mark(row, col, self.role_o)
|
||||
except InvalidMove, e:
|
||||
# received an invalid move, end the game.
|
||||
self.board.cheated()
|
||||
self.end_game('cheating')
|
||||
self.received = self.game_over
|
||||
return
|
||||
|
||||
# check win conditions
|
||||
if self.board.check_for_strike(self.role_o, row, col, self.strike):
|
||||
self.lost()
|
||||
elif self.board.full():
|
||||
self.drawn()
|
||||
else:
|
||||
self.next_move_id += 1
|
||||
|
||||
self.our_turn()
|
||||
|
||||
def is_my_turn(self):
|
||||
return self.received == self.ignore
|
||||
|
||||
def our_turn(self):
|
||||
# ignore messages until we've made our move
|
||||
self.received = self.ignore
|
||||
self.board.set_title('your turn')
|
||||
|
||||
def their_turn(self):
|
||||
self.received = self.wait_for_move
|
||||
self.board.set_title('their turn')
|
||||
|
||||
# called when the board receives input
|
||||
def move(self, row, col):
|
||||
try:
|
||||
self.board.mark(row, col, self.role_s)
|
||||
except InvalidMove, e:
|
||||
print 'you made an invalid move'
|
||||
return
|
||||
|
||||
self.send_move(row, col)
|
||||
|
||||
# check win conditions
|
||||
if self.board.check_for_strike(self.role_s, row, col, self.strike):
|
||||
self.won()
|
||||
elif self.board.full():
|
||||
self.drawn()
|
||||
else:
|
||||
self.next_move_id += 1
|
||||
|
||||
self.their_turn()
|
||||
|
||||
# sends a move message
|
||||
def send_move(self, row, column):
|
||||
msg = xmpp.Message()
|
||||
msg.setType('chat')
|
||||
|
||||
turn = msg.NT.turn
|
||||
turn.setNamespace(NS_GAMES)
|
||||
|
||||
move = turn.NT.move
|
||||
move.setNamespace(NS_GAMES_TICTACTOE)
|
||||
|
||||
move.setAttr('row', str(row))
|
||||
move.setAttr('col', str(column))
|
||||
move.setAttr('id', str(self.next_move_id))
|
||||
|
||||
self.send(msg)
|
||||
|
||||
# sends a termination message and ends the game
|
||||
def end_game(self, reason):
|
||||
msg = xmpp.Message()
|
||||
|
||||
terminate = msg.NT.terminate
|
||||
terminate.setNamespace(NS_GAMES)
|
||||
terminate.setAttr('reason', reason)
|
||||
|
||||
self.send(msg)
|
||||
|
||||
self.received = self.game_over
|
||||
|
||||
def won(self):
|
||||
self.end_game('won')
|
||||
self.board.won()
|
||||
|
||||
def lost(self):
|
||||
self.end_game('lost')
|
||||
self.board.lost()
|
||||
|
||||
def drawn(self):
|
||||
self.end_game('draw')
|
||||
self.board.drawn()
|
||||
|
||||
class TicTacToeBoard:
|
||||
def __init__(self, session, rows, cols):
|
||||
self.session = session
|
||||
|
||||
self.state = 'None'
|
||||
|
||||
self.rows = rows
|
||||
self.cols = cols
|
||||
|
||||
self.board = [ [None] * self.cols for r in xrange(self.rows) ]
|
||||
|
||||
self.setup_window()
|
||||
|
||||
# check if the last move (at row r and column c) won the game
|
||||
def check_for_strike(self, p, r, c, strike):
|
||||
# number in a row: up and down, left and right
|
||||
tallyI = 0
|
||||
tally_ = 0
|
||||
|
||||
# number in a row: diagonal
|
||||
# (imagine L or F as two sides of a right triangle: L\ or F/)
|
||||
tallyL = 0
|
||||
tallyF = 0
|
||||
|
||||
# convert real columns to internal columns
|
||||
r -= 1
|
||||
c -= 1
|
||||
|
||||
for d in xrange(-strike, strike):
|
||||
r_in_range = 0 <= r+d < self.rows
|
||||
c_in_range = 0 <= c+d < self.cols
|
||||
|
||||
# vertical check
|
||||
if r_in_range:
|
||||
tallyI = tallyI + 1
|
||||
if self.board[r+d][c] != p:
|
||||
tallyI = 0
|
||||
|
||||
# horizontal check
|
||||
if c_in_range:
|
||||
tally_ = tally_ + 1
|
||||
if self.board[r][c+d] != p:
|
||||
tally_ = 0
|
||||
|
||||
# diagonal checks
|
||||
if r_in_range and c_in_range:
|
||||
tallyL = tallyL + 1
|
||||
if self.board[r+d][c+d] != p:
|
||||
tallyL = 0
|
||||
|
||||
if r_in_range and 0 <= c-d < self.cols:
|
||||
tallyF = tallyF + 1
|
||||
if self.board[r+d][c-d] != p:
|
||||
tallyF = 0
|
||||
|
||||
if any([t == strike for t in (tallyL, tallyF, tallyI, tally_)]):
|
||||
return True
|
||||
|
||||
return False
|
||||
|
||||
# is the board full?
|
||||
def full(self):
|
||||
for r in xrange(self.rows):
|
||||
for c in xrange(self.cols):
|
||||
if self.board[r][c] == None:
|
||||
return False
|
||||
|
||||
return True
|
||||
|
||||
def setup_window(self):
|
||||
self.win = gtk.Window()
|
||||
|
||||
self.title_prefix = 'tic-tac-toe with %s' % self.session.name
|
||||
self.set_title()
|
||||
|
||||
self.win.set_app_paintable(True)
|
||||
|
||||
self.win.add_events(gdk.BUTTON_PRESS_MASK)
|
||||
self.win.connect('button-press-event', self.clicked)
|
||||
self.win.connect('expose-event', self.expose)
|
||||
|
||||
self.win.show_all()
|
||||
|
||||
def clicked(self, widget, event):
|
||||
if not self.session.is_my_turn():
|
||||
return
|
||||
|
||||
(width, height) = widget.get_size()
|
||||
|
||||
# convert click co-ordinates to row and column
|
||||
row_height = height // self.rows
|
||||
col_width = width // self.cols
|
||||
|
||||
row = int(event.y // row_height) + 1
|
||||
column = int(event.x // col_width) + 1
|
||||
|
||||
self.session.move(row, column)
|
||||
|
||||
# this actually draws the board
|
||||
def expose(self, widget, event):
|
||||
win = widget.window
|
||||
|
||||
cr = win.cairo_create()
|
||||
|
||||
cr.set_source_rgb(1.0, 1.0, 1.0)
|
||||
|
||||
cr.set_operator(cairo.OPERATOR_SOURCE)
|
||||
cr.paint()
|
||||
|
||||
layout = cr.create_layout()
|
||||
text_height = layout.get_pixel_extents()[1][3]
|
||||
|
||||
(width, height) = widget.get_size()
|
||||
|
||||
row_height = (height - text_height) // self.rows
|
||||
col_width = width // self.cols
|
||||
|
||||
cr.set_source_rgb(0, 0, 0)
|
||||
cr.set_line_width(2)
|
||||
for x in xrange(1, self.cols):
|
||||
cr.move_to(col_width * x, 0)
|
||||
cr.line_to(col_width * x, height - text_height)
|
||||
for x in xrange(1, self.rows):
|
||||
cr.move_to(0, row_height * x)
|
||||
cr.line_to(width, row_height * x)
|
||||
cr.stroke()
|
||||
|
||||
cr.move_to(0, height - text_height)
|
||||
if self.state == 'None':
|
||||
if self.session.is_my_turn():
|
||||
txt = _('It\'s your turn')
|
||||
else:
|
||||
txt = _('It\'s %(name)s\'s turn') % {'name': self.session.name}
|
||||
elif self.state == 'won':
|
||||
txt = _('You won !')
|
||||
elif self.state == 'lost':
|
||||
txt = _('You lost !')
|
||||
elif self.state == 'resign': # other part resigned
|
||||
txt = _('%(name)s capitulated') % {'name': self.session.name}
|
||||
elif self.state == 'cheated': # other part cheated
|
||||
txt = _('%(name)s cheated') % {'name': self.session.name}
|
||||
else: #draw
|
||||
txt = _('It\'s a draw')
|
||||
layout.set_text(txt)
|
||||
cr.update_layout(layout)
|
||||
cr.show_layout(layout)
|
||||
|
||||
for i in xrange(self.rows):
|
||||
for j in xrange(self.cols):
|
||||
if self.board[i][j] == 'x':
|
||||
self.draw_x(cr, i, j, row_height, col_width)
|
||||
elif self.board[i][j] == 'o':
|
||||
self.draw_o(cr, i, j, row_height, col_width)
|
||||
|
||||
def draw_x(self, cr, row, col, row_height, col_width):
|
||||
if self.session.role_s == 'x':
|
||||
color = gajim.config.get('outmsgcolor')
|
||||
else:
|
||||
color = gajim.config.get('inmsgcolor')
|
||||
c = gtk.gdk.Color(color)
|
||||
cr.set_source_color(c)
|
||||
|
||||
top = row_height * (row + 0.2)
|
||||
bottom = row_height * (row + 0.8)
|
||||
|
||||
left = col_width * (col + 0.2)
|
||||
right = col_width * (col + 0.8)
|
||||
|
||||
cr.set_line_width(row_height / 5)
|
||||
|
||||
cr.move_to(left, top)
|
||||
cr.line_to(right, bottom)
|
||||
|
||||
cr.move_to(right, top)
|
||||
cr.line_to(left, bottom)
|
||||
|
||||
cr.stroke()
|
||||
|
||||
def draw_o(self, cr, row, col, row_height, col_width):
|
||||
if self.session.role_s == 'o':
|
||||
color = gajim.config.get('outmsgcolor')
|
||||
else:
|
||||
color = gajim.config.get('inmsgcolor')
|
||||
c = gtk.gdk.Color(color)
|
||||
cr.set_source_color(c)
|
||||
|
||||
x = col_width * (col + 0.5)
|
||||
y = row_height * (row + 0.5)
|
||||
|
||||
cr.arc(x, y, row_height/4, 0, 2.0*3.2) # slightly further than 2*pi
|
||||
|
||||
cr.set_line_width(row_height / 5)
|
||||
cr.stroke()
|
||||
|
||||
# mark a move on the board
|
||||
def mark(self, row, column, player):
|
||||
if self.board[row-1][column-1]:
|
||||
raise InvalidMove
|
||||
else:
|
||||
self.board[row-1][column-1] = player
|
||||
|
||||
self.win.queue_draw()
|
||||
|
||||
def set_title(self, suffix = None):
|
||||
str_ = self.title_prefix
|
||||
|
||||
if suffix:
|
||||
str_ += ': ' + suffix
|
||||
|
||||
self.win.set_title(str_)
|
||||
|
||||
def won(self):
|
||||
self.state = 'won'
|
||||
self.set_title('you won!')
|
||||
self.win.queue_draw()
|
||||
|
||||
def lost(self):
|
||||
self.state = 'lost'
|
||||
self.set_title('you lost.')
|
||||
self.win.queue_draw()
|
||||
|
||||
def drawn(self):
|
||||
self.state = 'drawn'
|
||||
self.win.set_title(self.title_prefix + ': a draw.')
|
||||
self.win.queue_draw()
|
||||
|
||||
def cheated(self):
|
||||
self.state == 'cheated'
|
||||
self.win.queue_draw()
|
||||
BIN
tictactoe/tictactoe.png
Normal file
BIN
tictactoe/tictactoe.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 1.4 KiB |
Reference in New Issue
Block a user