check tic-tac-toe win conditions, slimmed down _messageCB some more
This commit is contained in:
parent
b170e77cdb
commit
76808901eb
|
@ -1593,7 +1593,6 @@ class ConnectionHandlers(ConnectionVcard, ConnectionBytestream, ConnectionDisco,
|
||||||
self.dispatch('FAILED_DECRYPT', (frm, tim))
|
self.dispatch('FAILED_DECRYPT', (frm, tim))
|
||||||
|
|
||||||
msgtxt = msg.getBody()
|
msgtxt = msg.getBody()
|
||||||
msghtml = msg.getXHTML()
|
|
||||||
subject = msg.getSubject() # if not there, it's None
|
subject = msg.getSubject() # if not there, it's None
|
||||||
|
|
||||||
tim = msg.getTimestamp()
|
tim = msg.getTimestamp()
|
||||||
|
@ -1612,19 +1611,15 @@ class ConnectionHandlers(ConnectionVcard, ConnectionBytestream, ConnectionDisco,
|
||||||
frm = address.getAttr('jid')
|
frm = address.getAttr('jid')
|
||||||
jid = gajim.get_jid_without_resource(frm)
|
jid = gajim.get_jid_without_resource(frm)
|
||||||
|
|
||||||
encTag = msg.getTag('x', namespace = common.xmpp.NS_ENCRYPTED)
|
|
||||||
# invitations
|
# invitations
|
||||||
invite = None
|
invite = None
|
||||||
|
encTag = msg.getTag('x', namespace = common.xmpp.NS_ENCRYPTED)
|
||||||
|
|
||||||
if not encTag:
|
if not encTag:
|
||||||
invite = msg.getTag('x', namespace = common.xmpp.NS_MUC_USER)
|
invite = msg.getTag('x', namespace = common.xmpp.NS_MUC_USER)
|
||||||
if invite and not invite.getTag('invite'):
|
if invite and not invite.getTag('invite'):
|
||||||
invite = None
|
invite = None
|
||||||
|
|
||||||
delayed = msg.getTag('x', namespace = common.xmpp.NS_DELAY) != None
|
|
||||||
msg_id = None
|
|
||||||
composing_xep = None
|
|
||||||
|
|
||||||
# FIXME: Msn transport (CMSN1.2.1 and PyMSN0.10) do NOT RECOMMENDED
|
# FIXME: Msn transport (CMSN1.2.1 and PyMSN0.10) do NOT RECOMMENDED
|
||||||
# invitation
|
# invitation
|
||||||
# stanza (MUC XEP) remove in 2007, as we do not do NOT RECOMMENDED
|
# stanza (MUC XEP) remove in 2007, as we do not do NOT RECOMMENDED
|
||||||
|
@ -1639,37 +1634,6 @@ class ConnectionHandlers(ConnectionVcard, ConnectionBytestream, ConnectionDisco,
|
||||||
is_continued))
|
is_continued))
|
||||||
return
|
return
|
||||||
|
|
||||||
form_node = None
|
|
||||||
for xtag in xtags:
|
|
||||||
if xtag.getNamespace() == common.xmpp.NS_DATA:
|
|
||||||
form_node = xtag
|
|
||||||
break
|
|
||||||
|
|
||||||
chatstate = None
|
|
||||||
|
|
||||||
# chatstates - look for chatstate tags in a message if not delayed
|
|
||||||
if not delayed:
|
|
||||||
composing_xep = False
|
|
||||||
children = msg.getChildren()
|
|
||||||
for child in children:
|
|
||||||
if child.getNamespace() == 'http://jabber.org/protocol/chatstates':
|
|
||||||
chatstate = child.getName()
|
|
||||||
composing_xep = 'XEP-0085'
|
|
||||||
break
|
|
||||||
# No XEP-0085 support, fallback to XEP-0022
|
|
||||||
if not chatstate:
|
|
||||||
chatstate_child = msg.getTag('x', namespace = common.xmpp.NS_EVENT)
|
|
||||||
if chatstate_child:
|
|
||||||
chatstate = 'active'
|
|
||||||
composing_xep = 'XEP-0022'
|
|
||||||
if not msgtxt and chatstate_child.getTag('composing'):
|
|
||||||
chatstate = 'composing'
|
|
||||||
|
|
||||||
# XEP-0172 User Nickname
|
|
||||||
user_nick = msg.getTagData('nick')
|
|
||||||
if not user_nick:
|
|
||||||
user_nick = ''
|
|
||||||
|
|
||||||
if encTag and self.USE_GPG:
|
if encTag and self.USE_GPG:
|
||||||
encmsg = encTag.getData()
|
encmsg = encTag.getData()
|
||||||
|
|
||||||
|
@ -1683,44 +1647,16 @@ class ConnectionHandlers(ConnectionVcard, ConnectionBytestream, ConnectionDisco,
|
||||||
|
|
||||||
if mtype == 'error':
|
if mtype == 'error':
|
||||||
self.dispatch_error_message(msg, msgtxt, session, frm, tim, subject)
|
self.dispatch_error_message(msg, msgtxt, session, frm, tim, subject)
|
||||||
|
|
||||||
return
|
|
||||||
elif mtype == 'groupchat':
|
elif mtype == 'groupchat':
|
||||||
self.dispatch_gc_message(msg, subject, frm, msgtxt, jid, tim, msghtml)
|
self.dispatch_gc_message(msg, subject, frm, msgtxt, jid, tim)
|
||||||
|
|
||||||
return
|
|
||||||
elif invite is not None:
|
elif invite is not None:
|
||||||
self.dispatch_invite_message(invite, frm)
|
self.dispatch_invite_message(invite, frm)
|
||||||
|
|
||||||
return
|
|
||||||
elif mtype == 'chat':
|
|
||||||
if not msg.getTag('body') and chatstate is None: # no <body>
|
|
||||||
return
|
|
||||||
|
|
||||||
log_type = 'chat_msg_recv'
|
|
||||||
else: # it's a single message
|
|
||||||
log_type = 'single_msg_recv'
|
|
||||||
|
|
||||||
mtype = 'normal'
|
|
||||||
|
|
||||||
if session.is_loggable() and msgtxt:
|
|
||||||
try:
|
|
||||||
msg_id = gajim.logger.write(log_type, frm, msgtxt,
|
|
||||||
tim = tim, subject = subject)
|
|
||||||
except exceptions.PysqliteOperationalError, e:
|
|
||||||
self.dispatch('ERROR', (_('Disk Write Error'), str(e)))
|
|
||||||
|
|
||||||
treat_as = gajim.config.get('treat_incoming_messages')
|
|
||||||
|
|
||||||
if treat_as:
|
|
||||||
mtype = treat_as
|
|
||||||
|
|
||||||
# XXX horrible hack
|
|
||||||
if isinstance(session, ChatControlSession):
|
|
||||||
session.received(frm, msgtxt, tim, encrypted, mtype, subject, chatstate,
|
|
||||||
msg_id, composing_xep, user_nick, msghtml, form_node)
|
|
||||||
else:
|
else:
|
||||||
session.received(msg)
|
# XXX horrible hack
|
||||||
|
if isinstance(session, ChatControlSession):
|
||||||
|
session.received(frm, msgtxt, tim, encrypted, subject, msg)
|
||||||
|
else:
|
||||||
|
session.received(msg)
|
||||||
# END messageCB
|
# END messageCB
|
||||||
|
|
||||||
# process and dispatch an error message
|
# process and dispatch an error message
|
||||||
|
@ -1741,7 +1677,7 @@ class ConnectionHandlers(ConnectionVcard, ConnectionBytestream, ConnectionDisco,
|
||||||
self.dispatch('MSGERROR', (frm, msg.getErrorCode(), error_msg, msgtxt, tim))
|
self.dispatch('MSGERROR', (frm, msg.getErrorCode(), error_msg, msgtxt, tim))
|
||||||
|
|
||||||
# process and dispatch a groupchat message
|
# process and dispatch a groupchat message
|
||||||
def dispatch_gc_message(self, msg, subject, frm, msgtxt, jid, tim, msghtml):
|
def dispatch_gc_message(self, msg, subject, frm, msgtxt, jid, tim):
|
||||||
has_timestamp = bool(msg.timestamp)
|
has_timestamp = bool(msg.timestamp)
|
||||||
|
|
||||||
if subject != None:
|
if subject != None:
|
||||||
|
@ -1761,7 +1697,7 @@ class ConnectionHandlers(ConnectionVcard, ConnectionBytestream, ConnectionDisco,
|
||||||
if not self.last_history_line.has_key(jid):
|
if not self.last_history_line.has_key(jid):
|
||||||
return
|
return
|
||||||
|
|
||||||
self.dispatch('GC_MSG', (frm, msgtxt, tim, has_timestamp, msghtml,
|
self.dispatch('GC_MSG', (frm, msgtxt, tim, has_timestamp, msg.getXHTML(),
|
||||||
statusCode))
|
statusCode))
|
||||||
|
|
||||||
no_log_for = gajim.config.get_per('accounts', self.name,
|
no_log_for = gajim.config.get_per('accounts', self.name,
|
||||||
|
|
|
@ -1,9 +1,12 @@
|
||||||
from common import helpers
|
from common import helpers
|
||||||
|
|
||||||
|
from common import exceptions
|
||||||
from common import gajim
|
from common import gajim
|
||||||
from common import stanza_session
|
from common import stanza_session
|
||||||
from common import contacts
|
from common import contacts
|
||||||
|
|
||||||
|
import common.xmpp
|
||||||
|
|
||||||
import dialogs
|
import dialogs
|
||||||
|
|
||||||
import message_control
|
import message_control
|
||||||
|
@ -16,8 +19,70 @@ class ChatControlSession(stanza_session.EncryptedStanzaSession):
|
||||||
|
|
||||||
self.control = None
|
self.control = None
|
||||||
|
|
||||||
|
# extracts chatstate from a <message/> stanza
|
||||||
|
def get_chatstate(self, msg, msgtxt):
|
||||||
|
composing_xep = None
|
||||||
|
chatstate = None
|
||||||
|
|
||||||
|
# chatstates - look for chatstate tags in a message if not delayed
|
||||||
|
delayed = msg.getTag('x', namespace=common.xmpp.NS_DELAY) != None
|
||||||
|
if not delayed:
|
||||||
|
composing_xep = False
|
||||||
|
children = msg.getChildren()
|
||||||
|
for child in children:
|
||||||
|
if child.getNamespace() == 'http://jabber.org/protocol/chatstates':
|
||||||
|
chatstate = child.getName()
|
||||||
|
composing_xep = 'XEP-0085'
|
||||||
|
break
|
||||||
|
# No XEP-0085 support, fallback to XEP-0022
|
||||||
|
if not chatstate:
|
||||||
|
chatstate_child = msg.getTag('x', namespace = common.xmpp.NS_EVENT)
|
||||||
|
if chatstate_child:
|
||||||
|
chatstate = 'active'
|
||||||
|
composing_xep = 'XEP-0022'
|
||||||
|
if not msgtxt and chatstate_child.getTag('composing'):
|
||||||
|
chatstate = 'composing'
|
||||||
|
|
||||||
|
return (composing_xep, chatstate)
|
||||||
|
|
||||||
# dispatch a received <message> stanza
|
# dispatch a received <message> stanza
|
||||||
def received(self, full_jid_with_resource, message, tim, encrypted, msg_type, subject, chatstate, msg_id, composing_xep, user_nick, xhtml, form_node):
|
def received(self, full_jid_with_resource, msgtxt, tim, encrypted, subject, msg):
|
||||||
|
msg_type = msg.getType()
|
||||||
|
msg_id = None
|
||||||
|
|
||||||
|
# XEP-0172 User Nickname
|
||||||
|
user_nick = msg.getTagData('nick')
|
||||||
|
if not user_nick:
|
||||||
|
user_nick =''
|
||||||
|
|
||||||
|
form_node = None
|
||||||
|
for xtag in msg.getTags('x'):
|
||||||
|
if xtag.getNamespace() == common.xmpp.NS_DATA:
|
||||||
|
form_node = xtag
|
||||||
|
break
|
||||||
|
|
||||||
|
composing_xep, chatstate = self.get_chatstate(msg, msgtxt)
|
||||||
|
|
||||||
|
xhtml = msg.getXHTML()
|
||||||
|
|
||||||
|
if msg_type == 'chat':
|
||||||
|
if not msg.getTag('body') and chatstate is None:
|
||||||
|
return
|
||||||
|
|
||||||
|
log_type = 'chat_msg_recv'
|
||||||
|
else:
|
||||||
|
log_type = 'single_msg_recv'
|
||||||
|
|
||||||
|
if self.is_loggable() and msgtxt:
|
||||||
|
try:
|
||||||
|
msg_id = gajim.logger.write(log_type, full_jid_with_resource, msgtxt,
|
||||||
|
tim=tim, subject=subject)
|
||||||
|
except exceptions.PysqliteOperationalError, e:
|
||||||
|
gajim.dispatch('ERROR', (_('Disk WriteError'), str(e)))
|
||||||
|
|
||||||
|
treat_as = gajim.config.get('treat_incoming_messages')
|
||||||
|
if treat_as:
|
||||||
|
msg_type = treat_as
|
||||||
|
|
||||||
jid = gajim.get_jid_without_resource(full_jid_with_resource)
|
jid = gajim.get_jid_without_resource(full_jid_with_resource)
|
||||||
resource = gajim.get_resource_from_jid(full_jid_with_resource)
|
resource = gajim.get_resource_from_jid(full_jid_with_resource)
|
||||||
|
@ -65,7 +130,7 @@ class ChatControlSession(stanza_session.EncryptedStanzaSession):
|
||||||
|
|
||||||
# THIS MUST BE AFTER chatstates handling
|
# THIS MUST BE AFTER chatstates handling
|
||||||
# AND BEFORE playsound (else we ear sounding on chatstates!)
|
# AND BEFORE playsound (else we ear sounding on chatstates!)
|
||||||
if not message: # empty message text
|
if not msgtxt: # empty message text
|
||||||
return
|
return
|
||||||
|
|
||||||
if gajim.config.get('ignore_unknown_contacts') and \
|
if gajim.config.get('ignore_unknown_contacts') and \
|
||||||
|
@ -86,16 +151,16 @@ class ChatControlSession(stanza_session.EncryptedStanzaSession):
|
||||||
|
|
||||||
if pm:
|
if pm:
|
||||||
nickname = resource
|
nickname = resource
|
||||||
groupchat_control.on_private_message(nickname, message, array[2],
|
groupchat_control.on_private_message(nickname, msgtxt, array[2],
|
||||||
xhtml, session, msg_id)
|
xhtml, session, msg_id)
|
||||||
else:
|
else:
|
||||||
self.roster_message(jid, message, tim, encrypted, msg_type,
|
self.roster_message(jid, msgtxt, tim, encrypted, msg_type,
|
||||||
subject, resource, msg_id, user_nick, advanced_notif_num,
|
subject, resource, msg_id, user_nick, advanced_notif_num,
|
||||||
xhtml=xhtml, form_node=form_node)
|
xhtml=xhtml, form_node=form_node)
|
||||||
|
|
||||||
nickname = gajim.get_name_from_jid(self.conn.name, jid)
|
nickname = gajim.get_name_from_jid(self.conn.name, jid)
|
||||||
# Check and do wanted notifications
|
# Check and do wanted notifications
|
||||||
msg = message
|
msg = msgtxt
|
||||||
if subject:
|
if subject:
|
||||||
msg = _('Subject: %s') % subject + '\n' + msg
|
msg = _('Subject: %s') % subject + '\n' + msg
|
||||||
focused = False
|
focused = False
|
||||||
|
@ -111,7 +176,7 @@ class ChatControlSession(stanza_session.EncryptedStanzaSession):
|
||||||
|
|
||||||
if gajim.interface.remote_ctrl:
|
if gajim.interface.remote_ctrl:
|
||||||
gajim.interface.remote_ctrl.raise_signal('NewMessage',
|
gajim.interface.remote_ctrl.raise_signal('NewMessage',
|
||||||
(self.conn.name, [full_jid_with_resource, message, tim,
|
(self.conn.name, [full_jid_with_resource, msgtxt, tim,
|
||||||
encrypted, msg_type, subject, chatstate, msg_id,
|
encrypted, msg_type, subject, chatstate, msg_id,
|
||||||
composing_xep, user_nick, xhtml, form_node]))
|
composing_xep, user_nick, xhtml, form_node]))
|
||||||
|
|
||||||
|
|
179
src/tictactoe.py
179
src/tictactoe.py
|
@ -9,6 +9,8 @@ import cairo
|
||||||
|
|
||||||
# implements <http://pidgin-games.sourceforge.net/xep/tictactoe.html#invite>
|
# implements <http://pidgin-games.sourceforge.net/xep/tictactoe.html#invite>
|
||||||
|
|
||||||
|
games_ns = 'http://jabber.org/protocol/games'
|
||||||
|
|
||||||
class InvalidMove(Exception):
|
class InvalidMove(Exception):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
@ -24,13 +26,19 @@ class TicTacToeSession(stanza_session.StanzaSession):
|
||||||
else:
|
else:
|
||||||
self.role_o = 'x'
|
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()
|
msg = xmpp.Message()
|
||||||
|
|
||||||
invite = msg.NT.invite
|
invite = msg.NT.invite
|
||||||
invite.setNamespace('http://jabber.org/protocol/games')
|
invite.setNamespace(games_ns)
|
||||||
|
|
||||||
game = invite.NT.game
|
game = invite.NT.game
|
||||||
game.setAttr('var', 'http://jabber.org/protocol/games/tictactoe')
|
game.setAttr('var', games_ns + '/tictactoe')
|
||||||
|
|
||||||
x = xmpp.DataForm(typ='submit')
|
x = xmpp.DataForm(typ='submit')
|
||||||
|
|
||||||
|
@ -38,12 +46,8 @@ class TicTacToeSession(stanza_session.StanzaSession):
|
||||||
|
|
||||||
self.send(msg)
|
self.send(msg)
|
||||||
|
|
||||||
self.next_move_id = 1
|
def read_invitation(self, msg):
|
||||||
self.state = 'sent_invite'
|
invite = msg.getTag('invite', namespace=games_ns)
|
||||||
|
|
||||||
# received an invitation
|
|
||||||
def invited(self, msg):
|
|
||||||
invite = msg.getTag('invite', namespace='http://jabber.org/protocol/games')
|
|
||||||
game = invite.getTag('game')
|
game = invite.getTag('game')
|
||||||
x = game.getTag('x', namespace='jabber:x:data')
|
x = game.getTag('x', namespace='jabber:x:data')
|
||||||
|
|
||||||
|
@ -51,37 +55,47 @@ class TicTacToeSession(stanza_session.StanzaSession):
|
||||||
|
|
||||||
if form.getField('role'):
|
if form.getField('role'):
|
||||||
self.role_o = form.getField('role').getValues()[0]
|
self.role_o = form.getField('role').getValues()[0]
|
||||||
|
else:
|
||||||
|
self.role_o = 'x'
|
||||||
|
|
||||||
if form.getField('rows'):
|
if form.getField('rows'):
|
||||||
self.rows = int(form.getField('rows').getValues()[0])
|
self.rows = int(form.getField('rows').getValues()[0])
|
||||||
|
else:
|
||||||
|
self.rows = 3
|
||||||
|
|
||||||
if form.getField('cols'):
|
if form.getField('cols'):
|
||||||
self.cols = int(form.getField('cols').getValues()[0])
|
self.cols = int(form.getField('cols').getValues()[0])
|
||||||
|
else:
|
||||||
# XXX 'strike'
|
|
||||||
|
|
||||||
if not hasattr(self, 'rows'):
|
|
||||||
self.rows = 3
|
|
||||||
|
|
||||||
if not hasattr(self, 'cols'):
|
|
||||||
self.cols = 3
|
self.cols = 3
|
||||||
|
|
||||||
|
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)
|
||||||
|
|
||||||
|
# XXX prompt user
|
||||||
|
# "accept, reject, ignore"
|
||||||
|
|
||||||
# the number of the move about to be made
|
# the number of the move about to be made
|
||||||
self.next_move_id = 1
|
self.next_move_id = 1
|
||||||
|
|
||||||
|
# display the board
|
||||||
self.board = TicTacToeBoard(self, self.rows, self.cols)
|
self.board = TicTacToeBoard(self, self.rows, self.cols)
|
||||||
|
|
||||||
# accept the invitation, join the game
|
# accept the invitation, join the game
|
||||||
response = xmpp.Message()
|
response = xmpp.Message()
|
||||||
|
|
||||||
join = response.NT.join
|
join = response.NT.join
|
||||||
join.setNamespace('http://jabber.org/protocol/games')
|
join.setNamespace(games_ns)
|
||||||
|
|
||||||
self.send(response)
|
self.send(response)
|
||||||
|
|
||||||
if not hasattr(self, 'role_o') or self.role_o == 'x':
|
if self.role_o == 'x':
|
||||||
self.role_s = 'o'
|
self.role_s = 'o'
|
||||||
self.role_o = 'x'
|
|
||||||
|
|
||||||
self.their_turn()
|
self.their_turn()
|
||||||
else:
|
else:
|
||||||
|
@ -91,27 +105,28 @@ class TicTacToeSession(stanza_session.StanzaSession):
|
||||||
self.our_turn()
|
self.our_turn()
|
||||||
|
|
||||||
def is_my_turn(self):
|
def is_my_turn(self):
|
||||||
return self.state == 'get_input'
|
# XXX not great semantics
|
||||||
|
return self.received == self.ignore
|
||||||
|
|
||||||
def received(self, msg):
|
# just sent an invitation, expecting a reply
|
||||||
# just sent an invitation, expecting a reply
|
def wait_for_invite_response(self, msg):
|
||||||
if self.state == 'sent_invite':
|
if msg.getTag('join', namespace=games_ns):
|
||||||
if msg.getTag('join', namespace='http://jabber.org/protocol/games'):
|
self.board = TicTacToeBoard(self, self.rows, self.cols)
|
||||||
self.board = TicTacToeBoard(self, self.rows, self.cols)
|
|
||||||
|
|
||||||
if self.role_s == 'x':
|
if self.role_s == 'x':
|
||||||
self.our_turn()
|
self.our_turn()
|
||||||
else:
|
else:
|
||||||
self.their_turn()
|
self.their_turn()
|
||||||
|
|
||||||
return
|
elif msg.getTag('decline', namespace=games_ns):
|
||||||
|
self.XXX()
|
||||||
|
|
||||||
# ignore messages unless we're expecting a move
|
# silently ignores any received messages
|
||||||
if self.state != 'waiting':
|
def ignore(self, msg):
|
||||||
return
|
pass
|
||||||
|
|
||||||
turn = msg.getTag('turn', namespace='http://jabber.org/protocol/games')
|
|
||||||
|
|
||||||
|
def wait_for_move(self, msg):
|
||||||
|
turn = msg.getTag('turn', namespace=games_ns)
|
||||||
move = turn.getTag('move', namespace='http://jabber.org/protocol/games/tictactoe')
|
move = turn.getTag('move', namespace='http://jabber.org/protocol/games/tictactoe')
|
||||||
|
|
||||||
row = int(move.getAttr('row'))
|
row = int(move.getAttr('row'))
|
||||||
|
@ -128,40 +143,54 @@ class TicTacToeSession(stanza_session.StanzaSession):
|
||||||
print 'received invalid move'
|
print 'received invalid move'
|
||||||
return
|
return
|
||||||
|
|
||||||
# XXX check win conditions
|
# 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.next_move_id += 1
|
self.our_turn()
|
||||||
|
|
||||||
self.our_turn()
|
|
||||||
|
|
||||||
def our_turn(self):
|
def our_turn(self):
|
||||||
self.state = 'get_input'
|
# ignore messages until we've made our move
|
||||||
|
self.received = self.ignore
|
||||||
self.board.win.set_title(self.board.title + ': your turn')
|
self.board.win.set_title(self.board.title + ': your turn')
|
||||||
|
|
||||||
def their_turn(self):
|
def their_turn(self):
|
||||||
self.state = 'waiting'
|
self.received = self.wait_for_move
|
||||||
self.board.win.set_title(self.board.title + ': their turn')
|
self.board.win.set_title(self.board.title + ': their turn')
|
||||||
|
|
||||||
# called when the board receives input
|
# called when the board receives input
|
||||||
def move(self, row, column):
|
def move(self, row, col):
|
||||||
try:
|
try:
|
||||||
self.board.mark(row, column, self.role_s)
|
self.board.mark(row, col, self.role_s)
|
||||||
except InvalidMove, e:
|
except InvalidMove, e:
|
||||||
print 'invalid move'
|
print 'you made an invalid move'
|
||||||
return
|
return
|
||||||
|
|
||||||
self.send_move(row, column)
|
self.send_move(row, col)
|
||||||
|
|
||||||
# XXX check win conditions
|
# 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()
|
||||||
|
|
||||||
def send_move(self, row, column):
|
def send_move(self, row, column):
|
||||||
msg = xmpp.Message()
|
msg = xmpp.Message()
|
||||||
|
msg.setType('chat')
|
||||||
|
|
||||||
turn = msg.NT.turn
|
turn = msg.NT.turn
|
||||||
turn.setNamespace('http://jabber.org/protocol/games')
|
turn.setNamespace(games_ns)
|
||||||
|
|
||||||
move = turn.NT.move
|
move = turn.NT.move
|
||||||
move.setNamespace('http://jabber.org/protocol/games/tictactoe')
|
move.setNamespace(games_ns+'/tictactoe')
|
||||||
|
|
||||||
move.setAttr('row', str(row))
|
move.setAttr('row', str(row))
|
||||||
move.setAttr('col', str(column))
|
move.setAttr('col', str(column))
|
||||||
|
@ -169,11 +198,49 @@ class TicTacToeSession(stanza_session.StanzaSession):
|
||||||
|
|
||||||
self.send(msg)
|
self.send(msg)
|
||||||
|
|
||||||
self.next_move_id += 1
|
|
||||||
|
|
||||||
self.their_turn()
|
|
||||||
|
|
||||||
class TicTacToeBoard:
|
class TicTacToeBoard:
|
||||||
|
def check_for_strike(self, p, r, c, strike):
|
||||||
|
# up and down, left and right
|
||||||
|
tallyI = 0
|
||||||
|
tally_ = 0
|
||||||
|
|
||||||
|
# right triangles: L\ , F/
|
||||||
|
tallyL = 0
|
||||||
|
tallyF = 0
|
||||||
|
|
||||||
|
# convert real columns to internal columns
|
||||||
|
r -= 1
|
||||||
|
c -= 1
|
||||||
|
|
||||||
|
for d in xrange(-strike, strike):
|
||||||
|
# vertical check
|
||||||
|
try:
|
||||||
|
tallyI = tallyI + 1 if self.board[r+d][c] == p else 0
|
||||||
|
except IndexError:
|
||||||
|
pass
|
||||||
|
|
||||||
|
# horizontal check
|
||||||
|
try:
|
||||||
|
tally_ = tally_ + 1 if self.board[r][c+d] == p else 0
|
||||||
|
except IndexError:
|
||||||
|
pass
|
||||||
|
|
||||||
|
# diagonal checks
|
||||||
|
try:
|
||||||
|
tallyL = tallyL + 1 if self.board[r+d][c+d] == p else 0
|
||||||
|
except IndexError:
|
||||||
|
pass
|
||||||
|
|
||||||
|
try:
|
||||||
|
tallyF = tallyF + 1 if self.board[r+d][c-d] == p else 0
|
||||||
|
except IndexError:
|
||||||
|
pass
|
||||||
|
|
||||||
|
if any([t == strike for t in (tallyL, tallyF, tallyI, tally_)]):
|
||||||
|
return True
|
||||||
|
|
||||||
|
return False
|
||||||
|
|
||||||
def __init__(self, session, rows, cols):
|
def __init__(self, session, rows, cols):
|
||||||
self.session = session
|
self.session = session
|
||||||
|
|
||||||
|
@ -184,6 +251,15 @@ class TicTacToeBoard:
|
||||||
|
|
||||||
self.setup_window()
|
self.setup_window()
|
||||||
|
|
||||||
|
# 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):
|
def setup_window(self):
|
||||||
self.win = gtk.Window()
|
self.win = gtk.Window()
|
||||||
|
|
||||||
|
@ -214,6 +290,7 @@ class TicTacToeBoard:
|
||||||
|
|
||||||
self.session.move(row, column)
|
self.session.move(row, column)
|
||||||
|
|
||||||
|
# this actually draws the board
|
||||||
def expose(self, widget, event):
|
def expose(self, widget, event):
|
||||||
win = widget.window
|
win = widget.window
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue