Skip to content

Commit 82b2ef4

Browse files
committed
game_handler: add widget_content support
1 parent 25f7901 commit 82b2ef4

File tree

1 file changed

+56
-35
lines changed

1 file changed

+56
-35
lines changed

zulip_bots/zulip_bots/game_handler.py

Lines changed: 56 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
import random
44
import logging
55
from copy import deepcopy
6-
from typing import Any, Dict, Tuple, List
6+
from typing import Any, Dict, Tuple, List, Union
77
from zulip_bots.test_lib import BotTestCase
88
import operator
99
import random
@@ -16,13 +16,15 @@ def __init__(self, message: str) -> None:
1616
def __str__(self) -> str:
1717
return self.message
1818

19+
1920
class SamePlayerMove(Exception):
2021
def __init__(self, message: str) -> None:
2122
self.message = message
2223

2324
def __str__(self) -> str:
2425
return self.message
2526

27+
2628
class GameAdapter(object):
2729
'''
2830
Class that serves as a template to easily
@@ -40,9 +42,9 @@ def __init__(
4042
model: Any,
4143
gameMessageHandler: Any,
4244
rules: str,
43-
max_players: int=2,
44-
min_players: int=2,
45-
supports_computer: bool=False
45+
max_players: int = 2,
46+
min_players: int = 2,
47+
supports_computer: bool = False
4648
) -> None:
4749
self.game_name = game_name
4850
self.bot_name = bot_name
@@ -155,16 +157,17 @@ def confirm_invitation_declined(self, game_id: str) -> str:
155157
host = self.invites[game_id]['host']
156158
return 'Declined invitation to play **{}** from @**{}**.'.format(self.game_name, self.get_username_by_email(host))
157159

158-
def send_message(self, to: str, content: str, is_private: bool, subject: str='') -> None:
160+
def send_message(self, to: str, content: str, is_private: bool, subject: str = '', widget_content: str = '') -> None:
159161
self.bot_handler.send_message(dict(
160162
type='private' if is_private else 'stream',
161163
to=to,
162164
content=content,
163-
subject=subject
165+
subject=subject,
166+
widget_content=widget_content
164167
))
165168

166-
def send_reply(self, original_message: Dict[str, Any], content: str) -> None:
167-
self.bot_handler.send_reply(original_message, content)
169+
def send_reply(self, original_message: Dict[str, Any], content: str, widget_content: str = '') -> None:
170+
self.bot_handler.send_reply(original_message, content, widget_content)
168171

169172
def usage(self) -> str:
170173
return '''
@@ -280,7 +283,8 @@ def command_start_game_with(self, message: Dict[str, Any], sender: str, content:
280283
def command_start_game(self, message: Dict[str, Any], sender: str, content: str) -> None:
281284
if message['type'] == 'private':
282285
if self.is_single_player:
283-
self.send_reply(message, 'You are not allowed to play games in private messages.')
286+
self.send_reply(
287+
message, 'You are not allowed to play games in private messages.')
284288
return
285289
else:
286290
self.send_reply(
@@ -309,7 +313,7 @@ def command_accept(self, message: Dict[str, Any], sender: str, content: str) ->
309313
game_id, '@**{}** has accepted the invitation.'.format(self.get_username_by_email(sender)))
310314
self.start_game_if_ready(game_id)
311315

312-
def create_game_lobby(self, message: Dict[str, Any], users: List[str]=[]) -> None:
316+
def create_game_lobby(self, message: Dict[str, Any], users: List[str] = []) -> None:
313317
if self.is_game_in_subject(message['subject'], message['display_recipient']):
314318
self.send_reply(message, 'There is already a game in this stream.')
315319
return
@@ -379,14 +383,16 @@ def command_decline(self, message: Dict[str, Any], sender: str, content: str) ->
379383
def command_quit(self, message: Dict[str, Any], sender: str, content: str) -> None:
380384
game_id = self.get_game_id_by_email(sender)
381385
if message['type'] == 'private' and self.is_single_player:
382-
self.send_reply(message, 'You are not allowed to play games in private messages.')
386+
self.send_reply(
387+
message, 'You are not allowed to play games in private messages.')
383388
return
384389
if game_id is '':
385390
self.send_reply(
386391
message, 'You are not in a game. Type `help` for all commands.')
387392
sender_avatar = "!avatar({})".format(sender)
388393
sender_name = self.get_username_by_email(sender)
389-
self.cancel_game(game_id, reason='{} **{}** quit.'.format(sender_avatar, sender_name))
394+
self.cancel_game(
395+
game_id, reason='{} **{}** quit.'.format(sender_avatar, sender_name))
390396

391397
def command_join(self, message: Dict[str, Any], sender: str, content: str) -> None:
392398
if not self.is_user_not_player(sender, message):
@@ -417,7 +423,8 @@ def command_play(self, message: Dict[str, Any], sender: str, content: str) -> No
417423
self.start_game(game_id)
418424
else:
419425
self.send_reply(
420-
message, 'Join {} more players to start the game'.format(self.max_players-num_players)
426+
message, 'Join {} more players to start the game'.format(
427+
self.max_players-num_players)
421428
)
422429

423430
def command_leaderboard(self, message: Dict[str, Any], sender: str, content: str) -> None:
@@ -451,13 +458,13 @@ def get_sorted_player_statistics(self) -> List[Tuple[str, Dict[str, int]]]:
451458
reverse=True
452459
)
453460

454-
def send_invite(self, game_id: str, user_email: str, message: Dict[str, Any]={}) -> None:
461+
def send_invite(self, game_id: str, user_email: str, message: Dict[str, Any] = {}) -> None:
455462
self.invites[game_id].update({user_email.lower(): 'p'})
456463
self.send_message(user_email, self.alert_new_invitation(game_id), True)
457464
if message != {}:
458465
self.send_reply(message, self.confirm_new_invitation(user_email))
459466

460-
def cancel_game(self, game_id: str, reason: str='') -> None:
467+
def cancel_game(self, game_id: str, reason: str = '') -> None:
461468
if game_id in self.invites.keys():
462469
self.broadcast(game_id, 'Game cancelled.\n' + reason)
463470
del self.invites[game_id]
@@ -497,7 +504,7 @@ def get_formatted_game_object(self, game_id: str) -> str:
497504
instance.stream, instance.subject)
498505
return object
499506

500-
def join_game(self, game_id: str, user_email: str, message: Dict[str, Any]={}) -> None:
507+
def join_game(self, game_id: str, user_email: str, message: Dict[str, Any] = {}) -> None:
501508
if len(self.get_players(game_id)) >= self.max_players:
502509
if message != {}:
503510
self.send_reply(message, 'This game is full.')
@@ -507,7 +514,7 @@ def join_game(self, game_id: str, user_email: str, message: Dict[str, Any]={}) -
507514
game_id, '@**{}** has joined the game'.format(self.get_username_by_email(user_email)))
508515
self.start_game_if_ready(game_id)
509516

510-
def get_players(self, game_id: str, parameter: str='a') -> List[str]:
517+
def get_players(self, game_id: str, parameter: str = 'a') -> List[str]:
511518
if game_id in self.invites.keys():
512519
players = [] # type: List[str]
513520
if (self.invites[game_id]['subject'] == '###private###' and 'p' in parameter) or 'p' not in parameter:
@@ -590,7 +597,7 @@ def change_game_subject(
590597
game_id: str,
591598
stream_name: str,
592599
subject_name: str,
593-
message: Dict[str, Any]={}
600+
message: Dict[str, Any] = {}
594601
) -> None:
595602
if self.get_game_instance_by_subject(stream_name, subject_name) is not None:
596603
if message != {}:
@@ -645,7 +652,7 @@ def get_user_cache(self) -> Dict[str, Any]:
645652
self.user_cache = json.loads(user_cache_str)
646653
return self.user_cache
647654

648-
def verify_users(self, users: List[str], message: Dict[str, Any]={}) -> List[str]:
655+
def verify_users(self, users: List[str], message: Dict[str, Any] = {}) -> List[str]:
649656
verified_users = []
650657
failed = False
651658
for u in users:
@@ -687,7 +694,7 @@ def is_game_in_subject(self, subject_name: str, stream_name: str) -> bool:
687694
self.get_game_instance_by_subject(
688695
subject_name, stream_name) is not None
689696

690-
def is_user_not_player(self, user_email: str, message: Dict[str, Any]={}) -> bool:
697+
def is_user_not_player(self, user_email: str, message: Dict[str, Any] = {}) -> bool:
691698
user = self.get_user_by_email(user_email)
692699
if user == {}:
693700
if message != {}:
@@ -713,20 +720,20 @@ def generate_game_id(self) -> str:
713720
id += valid_characters[random.randrange(0, len(valid_characters))]
714721
return id
715722

716-
def broadcast(self, game_id: str, content: str, include_private: bool=True) -> bool:
723+
def broadcast(self, game_id: str, content: str, include_private: bool = True, widget_content: str = '') -> bool:
717724
if include_private:
718725
private_recipients = self.get_players(game_id, parameter='p')
719726
if private_recipients is not None:
720727
for user in private_recipients:
721-
self.send_message(user, content, True)
728+
self.send_message(user, content, True, '', widget_content)
722729
if game_id in self.invites.keys():
723730
if self.invites[game_id]['subject'] != '###private###':
724731
self.send_message(
725-
self.invites[game_id]['stream'], content, False, self.invites[game_id]['subject'])
732+
self.invites[game_id]['stream'], content, False, self.invites[game_id]['subject'], widget_content)
726733
return True
727734
if game_id in self.instances.keys():
728735
self.send_message(
729-
self.instances[game_id].stream, content, False, self.instances[game_id].subject)
736+
self.instances[game_id].stream, content, False, self.instances[game_id].subject, widget_content)
730737
return True
731738
return False
732739

@@ -774,7 +781,7 @@ def __init__(self, gameAdapter: GameAdapter, is_private: bool, subject: str, gam
774781
self.board = self.model.current_board
775782
self.turn = random.randrange(0, len(players)) - 1
776783
self.current_draw = {} # type: Dict[str, bool]
777-
self.current_messages = [] # type: List[str]
784+
self.current_messages = [] # type: List[Union[str, Tuple[str, str]]]
778785
self.is_changing_subject = False
779786

780787
def start(self) -> None:
@@ -828,20 +835,21 @@ def handle_message(self, content: str, player_email: str) -> None:
828835
if self.gameAdapter.is_single_player:
829836
self.broadcast('It\'s your turn')
830837
else:
831-
user_turn_avatar = "!avatar({})".format(self.players[self.turn])
838+
user_turn_avatar = "!avatar({})".format(
839+
self.players[self.turn])
832840
if self.gameAdapter.gameMessageHandler.get_player_color(self.turn) is None:
833841
self.broadcast('{} It\'s **{}**\'s turn.'.format(
834-
user_turn_avatar,
835-
self.gameAdapter.get_username_by_email(
836-
self.players[self.turn])))
842+
user_turn_avatar,
843+
self.gameAdapter.get_username_by_email(
844+
self.players[self.turn])))
837845
else:
838846
self.broadcast('{} It\'s **{}**\'s ({}) turn.'.format(
839847
user_turn_avatar,
840848
self.gameAdapter.get_username_by_email(
841849
self.players[self.turn]),
842850
self.gameAdapter.gameMessageHandler.get_player_color(self.turn)))
843851

844-
def broadcast(self, content: str) -> None:
852+
def broadcast(self, content: str, widget_content: str = '') -> None:
845853
self.gameAdapter.broadcast(self.game_id, content)
846854

847855
def check_draw(self) -> bool:
@@ -866,7 +874,11 @@ def make_move(self, content: str, is_computer: bool) -> None:
866874
return
867875
except BadMoveException as e:
868876
self.broadcast(e.message)
869-
self.broadcast(self.parse_current_board())
877+
current_board_message = self.parse_current_board
878+
if isinstance(current_board_message, tuple):
879+
self.broadcast(
880+
current_board_message[0], current_board_message[1])
881+
self.broadcast(str(current_board_message))
870882
return
871883
if not is_computer:
872884
self.current_messages.append(self.gameAdapter.gameMessageHandler.alert_move_message(
@@ -918,16 +930,24 @@ def next_turn(self) -> None:
918930
user_turn_avatar = "!avatar({})".format(self.players[self.turn])
919931
self.current_messages.append('{} It\'s **{}**\'s ({}) turn.'.format(
920932
user_turn_avatar,
921-
self.gameAdapter.get_username_by_email(self.players[self.turn]),
933+
self.gameAdapter.get_username_by_email(
934+
self.players[self.turn]),
922935
self.gameAdapter.gameMessageHandler.get_player_color(self.turn)
923936
))
924937
self.broadcast_current_message()
925938
if self.players[self.turn] == self.gameAdapter.email:
926939
self.make_move('', True)
927940

928941
def broadcast_current_message(self) -> None:
929-
content = '\n\n'.join(self.current_messages)
930-
self.broadcast(content)
942+
# if there are no widgets, send all the messages all at once
943+
if len(list(filter(lambda x: isinstance(x, tuple), self.current_messages))) == 0:
944+
self.broadcast("\n\n".join(str(m) for m in self.current_messages))
945+
else:
946+
for message in self.current_messages:
947+
if isinstance(message, tuple):
948+
self.broadcast(message[0], message[1])
949+
else:
950+
self.broadcast(str(message))
931951
self.current_messages = []
932952

933953
def parse_current_board(self) -> Any:
@@ -942,7 +962,8 @@ def end_game(self, winner: str) -> None:
942962
else:
943963
winner_avatar = "!avatar({})".format(winner)
944964
winner_name = self.gameAdapter.get_username_by_email(winner)
945-
self.broadcast('{} **{}** won! :tada:'.format(winner_avatar, winner_name))
965+
self.broadcast(
966+
'{} **{}** won! :tada:'.format(winner_avatar, winner_name))
946967
for u in self.players:
947968
values = {'total_games': 1, 'games_won': 0,
948969
'games_lost': 0, 'games_drawn': 0}

0 commit comments

Comments
 (0)