Compare commits
16 commits
Author | SHA1 | Date | |
---|---|---|---|
|
538c5b0ab6 | ||
|
14bd90ea92 | ||
|
9dde74381e | ||
|
683d203984 | ||
|
d8dfb438a3 | ||
|
52296e6df8 | ||
|
4c386218b0 | ||
|
393da434e8 | ||
|
fae55f758d | ||
|
92c07d12ad | ||
|
bffd7fb1c3 | ||
|
69dc39bb56 | ||
|
75e3076285 | ||
|
f2e7a14318 | ||
|
0114fe774d | ||
|
615bb35359 |
7 changed files with 399 additions and 96 deletions
110
bot.py
110
bot.py
|
@ -2,7 +2,7 @@
|
||||||
# -*- coding: utf-8 -*-
|
# -*- coding: utf-8 -*-
|
||||||
#
|
#
|
||||||
# Telegram bot to play UNO in group chats
|
# Telegram bot to play UNO in group chats
|
||||||
# Copyright (c) 2016 Jannes Höke <uno@jhoeke.de>
|
# Copyright (c) 2016 - 2017 Jannes Höke <uno@jhoeke.de> and Karho Yau
|
||||||
#
|
#
|
||||||
# This program is free software: you can redistribute it and/or modify
|
# This program is free software: you can redistribute it and/or modify
|
||||||
# it under the terms of the GNU Affero General Public License as
|
# it under the terms of the GNU Affero General Public License as
|
||||||
|
@ -23,9 +23,9 @@ from datetime import datetime
|
||||||
from random import randint
|
from random import randint
|
||||||
|
|
||||||
from telegram import ParseMode, Message, Chat, InlineKeyboardMarkup, \
|
from telegram import ParseMode, Message, Chat, InlineKeyboardMarkup, \
|
||||||
InlineKeyboardButton
|
InlineKeyboardButton, ReplyKeyboardMarkup, Emoji
|
||||||
from telegram.ext import InlineQueryHandler, ChosenInlineResultHandler, \
|
from telegram.ext import InlineQueryHandler, ChosenInlineResultHandler, \
|
||||||
CommandHandler, MessageHandler, Filters, CallbackQueryHandler
|
CommandHandler, MessageHandler, Filters, CallbackQueryHandler, RegexHandler
|
||||||
from telegram.ext.dispatcher import run_async
|
from telegram.ext.dispatcher import run_async
|
||||||
|
|
||||||
from start_bot import start_bot
|
from start_bot import start_bot
|
||||||
|
@ -36,7 +36,7 @@ from user_setting import UserSetting
|
||||||
from utils import display_name
|
from utils import display_name
|
||||||
import card as c
|
import card as c
|
||||||
from errors import (NoGameInChatError, LobbyClosedError, AlreadyJoinedError,
|
from errors import (NoGameInChatError, LobbyClosedError, AlreadyJoinedError,
|
||||||
NotEnoughPlayersError, DeckEmptyError)
|
NotEnoughPlayersError, DeckEmptyError, PlayerLeftError)
|
||||||
from utils import send_async, answer_async, error, TIMEOUT
|
from utils import send_async, answer_async, error, TIMEOUT
|
||||||
from shared_vars import botan, gm, updater, dispatcher
|
from shared_vars import botan, gm, updater, dispatcher
|
||||||
from internationalization import _, __, user_locale, game_locales
|
from internationalization import _, __, user_locale, game_locales
|
||||||
|
@ -55,7 +55,7 @@ logger = logging.getLogger(__name__)
|
||||||
@user_locale
|
@user_locale
|
||||||
def notify_me(bot, update):
|
def notify_me(bot, update):
|
||||||
"""Handler for /notify_me command, pm people for next game"""
|
"""Handler for /notify_me command, pm people for next game"""
|
||||||
chat_id = update.message.chat_id
|
chat_id = update.message.chat.id
|
||||||
if update.message.chat.type == 'private':
|
if update.message.chat.type == 'private':
|
||||||
send_async(bot,
|
send_async(bot,
|
||||||
chat_id,
|
chat_id,
|
||||||
|
@ -64,6 +64,11 @@ def notify_me(bot, update):
|
||||||
else:
|
else:
|
||||||
try:
|
try:
|
||||||
gm.remind_dict[chat_id].add(update.message.from_user.id)
|
gm.remind_dict[chat_id].add(update.message.from_user.id)
|
||||||
|
send_async(bot,
|
||||||
|
chat_id,
|
||||||
|
text=_("You will be notified "
|
||||||
|
"when a new game is started in {title}.").format(
|
||||||
|
title=update.message.chat.title))
|
||||||
except KeyError:
|
except KeyError:
|
||||||
gm.remind_dict[chat_id] = {update.message.from_user.id}
|
gm.remind_dict[chat_id] = {update.message.from_user.id}
|
||||||
|
|
||||||
|
@ -71,7 +76,7 @@ def notify_me(bot, update):
|
||||||
@user_locale
|
@user_locale
|
||||||
def new_game(bot, update):
|
def new_game(bot, update):
|
||||||
"""Handler for the /new command"""
|
"""Handler for the /new command"""
|
||||||
chat_id = update.message.chat_id
|
chat_id = update.message.chat.id
|
||||||
|
|
||||||
if update.message.chat.type == 'private':
|
if update.message.chat.type == 'private':
|
||||||
help(bot, update)
|
help(bot, update)
|
||||||
|
@ -79,19 +84,20 @@ def new_game(bot, update):
|
||||||
else:
|
else:
|
||||||
|
|
||||||
if update.message.chat_id in gm.remind_dict:
|
if update.message.chat_id in gm.remind_dict:
|
||||||
for user in gm.remind_dict[update.message.chat_id]:
|
for user in gm.remind_dict[chat_id]:
|
||||||
send_async(bot,
|
send_async(bot,
|
||||||
user,
|
user,
|
||||||
text=_("A new game has been started in {title}").format(
|
text=_("A new game has been started in {title}.").format(
|
||||||
title=update.message.chat.title))
|
title=update.message.chat.title))
|
||||||
|
|
||||||
del gm.remind_dict[update.message.chat_id]
|
del gm.remind_dict[chat_id]
|
||||||
|
|
||||||
game = gm.new_game(update.message.chat)
|
game = gm.new_game(update.message.chat)
|
||||||
game.owner = update.message.from_user
|
game.owner = update.message.from_user
|
||||||
send_async(bot, chat_id,
|
send_async(bot, chat_id,
|
||||||
text=_("Created a new game! Join the game with /join "
|
text=_("Created a new game! Wait for your friends "
|
||||||
"and start the game with /start"))
|
"and start the game with /start"))
|
||||||
|
gm.join_game(update.message.from_user, update.message.chat)
|
||||||
|
|
||||||
if botan:
|
if botan:
|
||||||
botan.track(update.message, 'New games')
|
botan.track(update.message, 'New games')
|
||||||
|
@ -162,7 +168,7 @@ def leave_game(bot, update):
|
||||||
reply_to_message_id=update.message.message_id)
|
reply_to_message_id=update.message.message_id)
|
||||||
|
|
||||||
except NotEnoughPlayersError:
|
except NotEnoughPlayersError:
|
||||||
gm.end_game(chat, user)
|
gm.end_game(user, chat)
|
||||||
send_async(bot, chat.id, text=__("Game ended!", multi=game.translate))
|
send_async(bot, chat.id, text=__("Game ended!", multi=game.translate))
|
||||||
|
|
||||||
else:
|
else:
|
||||||
|
@ -226,7 +232,7 @@ def status_update(bot, update):
|
||||||
except NoGameInChatError:
|
except NoGameInChatError:
|
||||||
pass
|
pass
|
||||||
except NotEnoughPlayersError:
|
except NotEnoughPlayersError:
|
||||||
gm.end_game(chat, user)
|
gm.end_game(user, chat)
|
||||||
send_async(bot, chat.id, text=__("Game ended!",
|
send_async(bot, chat.id, text=__("Game ended!",
|
||||||
multi=game.translate))
|
multi=game.translate))
|
||||||
else:
|
else:
|
||||||
|
@ -419,6 +425,47 @@ def disable_translations(bot, update):
|
||||||
return
|
return
|
||||||
|
|
||||||
|
|
||||||
|
@game_locales
|
||||||
|
@user_locale
|
||||||
|
def mode(bot, update):
|
||||||
|
"""Handler for the /mode command"""
|
||||||
|
chat = update.message.chat
|
||||||
|
user = update.message.from_user
|
||||||
|
games = gm.chatid_games.get(chat.id)
|
||||||
|
|
||||||
|
if not games:
|
||||||
|
send_async(bot, chat.id,
|
||||||
|
text=__("There is no running game in this chat."))
|
||||||
|
return
|
||||||
|
|
||||||
|
game = games[-1]
|
||||||
|
|
||||||
|
if chat.type == 'private':
|
||||||
|
send_async(bot, chat.id,
|
||||||
|
text=_("Please change the group mode in the public game group with "
|
||||||
|
"the bot."))
|
||||||
|
return
|
||||||
|
|
||||||
|
if game.owner.id == user.id and not games.started:
|
||||||
|
kb = [["🎻 " + _("Original"), "🚴 " + _("Progressive UNO")]]
|
||||||
|
markup = ReplyKeyboardMarkup(kb, resize_keyboard=True, one_time_keyboard=True)
|
||||||
|
choice = send_async(bot, chat.id, text=_("Choose the game mode:"), reply_markup = markup)
|
||||||
|
if choice[0] == "🎻":
|
||||||
|
game.mode = 0
|
||||||
|
send_async(bot, chat.id, text=_("Original rules will be used."))
|
||||||
|
else if choice[0] == "🚴":
|
||||||
|
game.mode = 1
|
||||||
|
send_async(bot, chat.id, text=_("Progressive UNO rules will be used."))
|
||||||
|
return
|
||||||
|
|
||||||
|
else:
|
||||||
|
send_async(bot, chat.id,
|
||||||
|
text=_("Only the game creator ({name}) can do that when the game does not start")
|
||||||
|
.format(name=game.owner.first_name),
|
||||||
|
reply_to_message_id=update.message.message_id)
|
||||||
|
return
|
||||||
|
|
||||||
|
|
||||||
@game_locales
|
@game_locales
|
||||||
@user_locale
|
@user_locale
|
||||||
def skip_player(bot, update):
|
def skip_player(bot, update):
|
||||||
|
@ -475,7 +522,7 @@ def skip_player(bot, update):
|
||||||
try:
|
try:
|
||||||
gm.leave_game(skipped_player.user, chat)
|
gm.leave_game(skipped_player.user, chat)
|
||||||
send_async(bot, chat.id,
|
send_async(bot, chat.id,
|
||||||
text=__("{name1} was skipped four times in a row "
|
text=__("{name1} was skipped three times in a row "
|
||||||
"and has been removed from the game.\n"
|
"and has been removed from the game.\n"
|
||||||
"Next player: {name2}", multi=game.translate)
|
"Next player: {name2}", multi=game.translate)
|
||||||
.format(name1=display_name(skipped_player.user),
|
.format(name1=display_name(skipped_player.user),
|
||||||
|
@ -483,12 +530,17 @@ def skip_player(bot, update):
|
||||||
|
|
||||||
except NotEnoughPlayersError:
|
except NotEnoughPlayersError:
|
||||||
send_async(bot, chat.id,
|
send_async(bot, chat.id,
|
||||||
text=__("{name} was skipped four times in a row "
|
text=__("{name} was skipped three times in a row "
|
||||||
"and has been removed from the game.\n"
|
"and has been removed from the game.\n"
|
||||||
"The game ended.", multi=game.translate)
|
"The game ended.", multi=game.translate)
|
||||||
.format(name=display_name(skipped_player.user)))
|
.format(name=display_name(skipped_player.user)))
|
||||||
|
|
||||||
gm.end_game(chat.id, skipped_player.user)
|
us2 = UserSetting.get(id=skipped_player.user.id)
|
||||||
|
if us2 and us2.stats:
|
||||||
|
us2.games_played += 1
|
||||||
|
|
||||||
|
gm.end_game(skipped_player.user, chat)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@game_locales
|
@game_locales
|
||||||
|
@ -594,7 +646,13 @@ def process_result(bot, update):
|
||||||
elif result_id == 'pass':
|
elif result_id == 'pass':
|
||||||
game.turn()
|
game.turn()
|
||||||
elif result_id in c.COLORS:
|
elif result_id in c.COLORS:
|
||||||
game.choose_color(result_id)
|
try:
|
||||||
|
game.choose_color(result_id)
|
||||||
|
except PlayerLeftError:
|
||||||
|
send_async(bot, chat.id,
|
||||||
|
text=__("There are errors in choosing color. "
|
||||||
|
"Color is now unchanged.", multi=game.translate))
|
||||||
|
game.turn()
|
||||||
else:
|
else:
|
||||||
reset_waiting_time(bot, player)
|
reset_waiting_time(bot, player)
|
||||||
do_play_card(bot, player, result_id)
|
do_play_card(bot, player, result_id)
|
||||||
|
@ -609,10 +667,10 @@ def reset_waiting_time(bot, player):
|
||||||
"""Resets waiting time for a player and sends a notice to the group"""
|
"""Resets waiting time for a player and sends a notice to the group"""
|
||||||
chat = player.game.chat
|
chat = player.game.chat
|
||||||
|
|
||||||
if player.waiting_time < 90:
|
if player.waiting_time < 60:
|
||||||
player.waiting_time = 90
|
player.waiting_time = 60
|
||||||
send_async(bot, chat.id,
|
send_async(bot, chat.id,
|
||||||
text=__("Waiting time for {name} has been reset to 90 "
|
text=__("Waiting time for {name} has been reset to 60 "
|
||||||
"seconds", multi=player.game.translate)
|
"seconds", multi=player.game.translate)
|
||||||
.format(name=display_name(player.user)))
|
.format(name=display_name(player.user)))
|
||||||
|
|
||||||
|
@ -661,7 +719,7 @@ def do_play_card(bot, player, result_id):
|
||||||
if us2 and us2.stats:
|
if us2 and us2.stats:
|
||||||
us2.games_played += 1
|
us2.games_played += 1
|
||||||
|
|
||||||
gm.end_game(chat, user)
|
gm.end_game(user, chat)
|
||||||
|
|
||||||
if botan:
|
if botan:
|
||||||
botan.track(Message(randint(1, 1000000000), user, datetime.now(),
|
botan.track(Message(randint(1, 1000000000), user, datetime.now(),
|
||||||
|
@ -694,9 +752,10 @@ def do_call_bluff(bot, player):
|
||||||
|
|
||||||
if player.prev.bluffing:
|
if player.prev.bluffing:
|
||||||
send_async(bot, chat.id,
|
send_async(bot, chat.id,
|
||||||
text=__("Bluff called! Giving 4 cards to {name}",
|
text=__("Bluff called! Giving {numbers} cards to {name}",
|
||||||
multi=game.translate)
|
multi=game.translate)
|
||||||
.format(name=player.prev.user.first_name))
|
.format(name=player.prev.user.first_name,
|
||||||
|
numbers=game.draw_counter))
|
||||||
|
|
||||||
try:
|
try:
|
||||||
player.prev.draw()
|
player.prev.draw()
|
||||||
|
@ -708,10 +767,11 @@ def do_call_bluff(bot, player):
|
||||||
else:
|
else:
|
||||||
game.draw_counter += 2
|
game.draw_counter += 2
|
||||||
send_async(bot, chat.id,
|
send_async(bot, chat.id,
|
||||||
text=__("{name1} didn't bluff! Giving 6 cards to {name2}",
|
text=__("{name1} didn't bluff! Giving {numbers} cards to {name2}",
|
||||||
multi=game.translate)
|
multi=game.translate)
|
||||||
.format(name1=player.prev.user.first_name,
|
.format(name1=player.prev.user.first_name,
|
||||||
name2=player.user.first_name))
|
name2=player.user.first_name,
|
||||||
|
numbers=game.draw_counter))
|
||||||
try:
|
try:
|
||||||
player.draw()
|
player.draw()
|
||||||
except DeckEmptyError:
|
except DeckEmptyError:
|
||||||
|
@ -738,6 +798,8 @@ dispatcher.add_handler(CommandHandler('disable_translations',
|
||||||
disable_translations))
|
disable_translations))
|
||||||
dispatcher.add_handler(CommandHandler('skip', skip_player))
|
dispatcher.add_handler(CommandHandler('skip', skip_player))
|
||||||
dispatcher.add_handler(CommandHandler('notify_me', notify_me))
|
dispatcher.add_handler(CommandHandler('notify_me', notify_me))
|
||||||
|
dispatcher.add_handler(CommandHandler('mode', mode))
|
||||||
|
dispatcher.add_handler(RegexHandler('^(Original|Progressive UNO)$', mode, pass_groups=True))
|
||||||
simple_commands.register()
|
simple_commands.register()
|
||||||
settings.register()
|
settings.register()
|
||||||
dispatcher.add_handler(MessageHandler([Filters.status_update], status_update))
|
dispatcher.add_handler(MessageHandler([Filters.status_update], status_update))
|
||||||
|
|
|
@ -36,3 +36,7 @@ class NotEnoughPlayersError(Exception):
|
||||||
|
|
||||||
class DeckEmptyError(Exception):
|
class DeckEmptyError(Exception):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
class PlayerLeftError(Exception):
|
||||||
|
pass
|
||||||
|
|
4
game.py
4
game.py
|
@ -2,7 +2,7 @@
|
||||||
# -*- coding: utf-8 -*-
|
# -*- coding: utf-8 -*-
|
||||||
#
|
#
|
||||||
# Telegram bot to play UNO in group chats
|
# Telegram bot to play UNO in group chats
|
||||||
# Copyright (c) 2016 Jannes Höke <uno@jhoeke.de>
|
# Copyright (c) 2016 - 2017 Jannes Höke <uno@jhoeke.de> and Karho Yau
|
||||||
#
|
#
|
||||||
# This program is free software: you can redistribute it and/or modify
|
# This program is free software: you can redistribute it and/or modify
|
||||||
# it under the terms of the GNU Affero General Public License as
|
# it under the terms of the GNU Affero General Public License as
|
||||||
|
@ -36,10 +36,12 @@ class Game(object):
|
||||||
open = True
|
open = True
|
||||||
translate = False
|
translate = False
|
||||||
players_won = 0
|
players_won = 0
|
||||||
|
mode = 0
|
||||||
|
|
||||||
def __init__(self, chat):
|
def __init__(self, chat):
|
||||||
self.chat = chat
|
self.chat = chat
|
||||||
self.last_card = None
|
self.last_card = None
|
||||||
|
self.joined_before = set()
|
||||||
|
|
||||||
while not self.last_card or self.last_card.special:
|
while not self.last_card or self.last_card.special:
|
||||||
self.deck = Deck()
|
self.deck = Deck()
|
||||||
|
|
|
@ -19,6 +19,7 @@
|
||||||
|
|
||||||
|
|
||||||
import logging
|
import logging
|
||||||
|
import random
|
||||||
|
|
||||||
from game import Game
|
from game import Game
|
||||||
from player import Player
|
from player import Player
|
||||||
|
@ -77,7 +78,8 @@ class GameManager(object):
|
||||||
# Don not re-add a player and remove the player from previous games in
|
# Don not re-add a player and remove the player from previous games in
|
||||||
# this chat, if he is in one of them
|
# this chat, if he is in one of them
|
||||||
for player in players:
|
for player in players:
|
||||||
if player in game.players:
|
# Try to pervent someone win or leave then join again.
|
||||||
|
if player in game.players or user.id in game.joined_before:
|
||||||
raise AlreadyJoinedError()
|
raise AlreadyJoinedError()
|
||||||
else:
|
else:
|
||||||
try:
|
try:
|
||||||
|
@ -94,7 +96,13 @@ class GameManager(object):
|
||||||
|
|
||||||
player = Player(game, user)
|
player = Player(game, user)
|
||||||
|
|
||||||
players.append(player)
|
# Randomize player position.
|
||||||
|
game.joined_before.append(user.id)
|
||||||
|
if len(players) > 2:
|
||||||
|
players.insert(random.randrange(len(players)), player)
|
||||||
|
else:
|
||||||
|
players.append(player)
|
||||||
|
|
||||||
self.userid_current[user.id] = player
|
self.userid_current[user.id] = player
|
||||||
|
|
||||||
def leave_game(self, user, chat):
|
def leave_game(self, user, chat):
|
||||||
|
@ -135,7 +143,7 @@ class GameManager(object):
|
||||||
del self.userid_current[user.id]
|
del self.userid_current[user.id]
|
||||||
del self.userid_players[user.id]
|
del self.userid_players[user.id]
|
||||||
|
|
||||||
def end_game(self, chat, user):
|
def end_game(self, user, chat):
|
||||||
"""
|
"""
|
||||||
End a game
|
End a game
|
||||||
"""
|
"""
|
||||||
|
|
|
@ -107,29 +107,28 @@ msgstr ""
|
||||||
msgid ""
|
msgid ""
|
||||||
"Created a new game! Join the game with /join and start the game with /start"
|
"Created a new game! Join the game with /join and start the game with /start"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
"¡Partida nueva creada! Únete a la partida con /join y comienza la partida "
|
"¡Nueva partida creada! Únete con /join. Cuando estéis todos listos, haz /start para empezar."
|
||||||
"con /start "
|
|
||||||
|
|
||||||
#: bot.py:152
|
#: bot.py:152
|
||||||
msgid "The lobby is closed"
|
msgid "The lobby is closed"
|
||||||
msgstr "La sala esta cerrada"
|
msgstr "La sala está cerrada."
|
||||||
|
|
||||||
#: bot.py:156
|
#: bot.py:156
|
||||||
msgid "No game is running at the moment. Create a new game with /new"
|
msgid "No game is running at the moment. Create a new game with /new"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
"No hay ninguna partida activa por el momento. Crea una partida con /new"
|
"No hay ninguna partida en curso. Crea una partida con /new."
|
||||||
|
|
||||||
#: bot.py:162
|
#: bot.py:162
|
||||||
msgid "You already joined the game. Start the game with /start"
|
msgid "You already joined the game. Start the game with /start"
|
||||||
msgstr "Ya te uniste a la partida. Comienza la partida con /start"
|
msgstr "Ya te uniste a esta partida. Comienza la partida con /start."
|
||||||
|
|
||||||
#: bot.py:167
|
#: bot.py:167
|
||||||
msgid "Joined the game"
|
msgid "Joined the game"
|
||||||
msgstr "Te uniste a la partida"
|
msgstr "Te uniste a la partida."
|
||||||
|
|
||||||
#: bot.py:179 bot.py:191
|
#: bot.py:179 bot.py:191
|
||||||
msgid "You are not playing in a game in this group."
|
msgid "You are not playing in a game in this group."
|
||||||
msgstr "No estas jugando una partida en este grupo."
|
msgstr "No estas jugando a una partida en este grupo."
|
||||||
|
|
||||||
#: bot.py:197 bot.py:258 bot.py:595
|
#: bot.py:197 bot.py:258 bot.py:595
|
||||||
msgid "Game ended!"
|
msgid "Game ended!"
|
||||||
|
@ -145,7 +144,7 @@ msgstr "Partida no encontrada."
|
||||||
|
|
||||||
#: bot.py:223
|
#: bot.py:223
|
||||||
msgid "Back to last group"
|
msgid "Back to last group"
|
||||||
msgstr "De vuelta al último grupo"
|
msgstr "De vuelta al último grupo."
|
||||||
|
|
||||||
#: bot.py:227
|
#: bot.py:227
|
||||||
msgid "Please switch to the group you selected!"
|
msgid "Please switch to the group you selected!"
|
||||||
|
@ -163,20 +162,20 @@ msgstr ""
|
||||||
#: bot.py:260
|
#: bot.py:260
|
||||||
#, python-format
|
#, python-format
|
||||||
msgid "Removing {name} from the game"
|
msgid "Removing {name} from the game"
|
||||||
msgstr "Removiendo a {name} de la partida"
|
msgstr "Eliminando a {name} de la partida."
|
||||||
|
|
||||||
#: bot.py:273
|
#: bot.py:273
|
||||||
msgid "There is no game running in this chat. Create a new one with /new"
|
msgid "There is no game running in this chat. Create a new one with /new"
|
||||||
msgstr "No hay ninguna partida en curso en este chat. Crea una nueva con /new"
|
msgstr "No hay ninguna partida en curso en este chat. Crea una nueva con /new."
|
||||||
|
|
||||||
#: bot.py:278
|
#: bot.py:278
|
||||||
msgid "The game has already started"
|
msgid "The game has already started"
|
||||||
msgstr "La partida ya ha comenzado"
|
msgstr "La partida ya ha comenzado."
|
||||||
|
|
||||||
#: bot.py:281
|
#: bot.py:281
|
||||||
msgid "At least two players must /join the game before you can start it"
|
msgid "At least two players must /join the game before you can start it"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
"Antes de iniciar la partida, al menos dos jugadores deben darle al /join"
|
"Antes de iniciar la partida, al menos dos jugadores deben unirse usando /join."
|
||||||
|
|
||||||
#: bot.py:297
|
#: bot.py:297
|
||||||
#, python-format
|
#, python-format
|
||||||
|
@ -187,7 +186,7 @@ msgid ""
|
||||||
msgstr ""
|
msgstr ""
|
||||||
"Primer Jugador: {name}\n"
|
"Primer Jugador: {name}\n"
|
||||||
"Usa /close para evitar que la gente se una a la partida.\n"
|
"Usa /close para evitar que la gente se una a la partida.\n"
|
||||||
"Habilita multi-traducciones con /enable_translations"
|
"Habilita multi-traducciones con /enable_translations."
|
||||||
|
|
||||||
#: bot.py:321
|
#: bot.py:321
|
||||||
msgid "Please select the group you want to play in."
|
msgid "Please select the group you want to play in."
|
||||||
|
@ -195,11 +194,11 @@ msgstr "Elige el grupo en el que deseas jugar."
|
||||||
|
|
||||||
#: bot.py:335 bot.py:361
|
#: bot.py:335 bot.py:361
|
||||||
msgid "There is no running game in this chat."
|
msgid "There is no running game in this chat."
|
||||||
msgstr "No hay ninguna partida ejecutándose en este chat."
|
msgstr "No hay ninguna partida en curso en este grupo."
|
||||||
|
|
||||||
#: bot.py:342
|
#: bot.py:342
|
||||||
msgid "Closed the lobby. No more players can join this game."
|
msgid "Closed the lobby. No more players can join this game."
|
||||||
msgstr "Sala cerrada. No se pueden unir más jugadores a la partida."
|
msgstr "Sala cerrada. No podrán unirse más jugadores a la partida."
|
||||||
|
|
||||||
#: bot.py:348 bot.py:373
|
#: bot.py:348 bot.py:373
|
||||||
#, python-format
|
#, python-format
|
||||||
|
@ -210,7 +209,7 @@ msgstr "Solo el creador de la partida ({name}) puede hacer eso."
|
||||||
#, python-format
|
#, python-format
|
||||||
msgid "Enabled multi-translations. Disable with /disable_translations"
|
msgid "Enabled multi-translations. Disable with /disable_translations"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
"Multi-traducciones habilitadas. Deshabilítalas con /disable_translations"
|
"Multi-traducciones habilitadas. Deshabilítalas con /disable_translations."
|
||||||
|
|
||||||
#: bot.py:377
|
#: bot.py:377
|
||||||
#, python-format
|
#, python-format
|
||||||
|
@ -218,11 +217,11 @@ msgid ""
|
||||||
"Disabled multi-translations. Enable them again with /enable_translations"
|
"Disabled multi-translations. Enable them again with /enable_translations"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
"Multi-traducciones deshabilitadas. Habilítalas de nuevo con /"
|
"Multi-traducciones deshabilitadas. Habilítalas de nuevo con /"
|
||||||
"enable_translations"
|
"enable_translations."
|
||||||
|
|
||||||
#: bot.py:368
|
#: bot.py:368
|
||||||
msgid "Opened the lobby. New players may /join the game."
|
msgid "Opened the lobby. New players may /join the game."
|
||||||
msgstr "Sala abierta. Nuevos jugadores darle al /join."
|
msgstr "Sala abierta. Ahora pueden unirse nuevos jugadores usando /join."
|
||||||
|
|
||||||
#: bot.py:386
|
#: bot.py:386
|
||||||
msgid "You are not playing in a game in this chat."
|
msgid "You are not playing in a game in this chat."
|
||||||
|
@ -232,8 +231,8 @@ msgstr "No estás jugando una partida en este chat."
|
||||||
#, python-format
|
#, python-format
|
||||||
msgid "Please wait {time} second"
|
msgid "Please wait {time} second"
|
||||||
msgid_plural "Please wait {time} seconds"
|
msgid_plural "Please wait {time} seconds"
|
||||||
msgstr[0] "Por favor, espere {time} segundo"
|
msgstr[0] "Por favor, espere un segundo."
|
||||||
msgstr[1] "Por favor, espere {time} segundos"
|
msgstr[1] "Por favor, espere {time} segundos."
|
||||||
|
|
||||||
#: bot.py:413
|
#: bot.py:413
|
||||||
#, python-format
|
#, python-format
|
||||||
|
@ -256,7 +255,7 @@ msgid ""
|
||||||
"{name1} was skipped four times in a row and has been removed from the game.\n"
|
"{name1} was skipped four times in a row and has been removed from the game.\n"
|
||||||
"Next player: {name2}"
|
"Next player: {name2}"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
"{name1} fue saltado cuatro veces consecutivas y ha sido removido de la "
|
"{name1} fue saltado cuatro veces consecutivas y ha sido eliminado de la "
|
||||||
"partida.\n"
|
"partida.\n"
|
||||||
"Siguiente Jugador {name2}"
|
"Siguiente Jugador {name2}"
|
||||||
|
|
||||||
|
@ -266,7 +265,7 @@ msgid ""
|
||||||
"{name} was skipped four times in a row and has been removed from the game.\n"
|
"{name} was skipped four times in a row and has been removed from the game.\n"
|
||||||
"The game ended."
|
"The game ended."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
"{name} fue saltado cuatro veces consecutivas y ha sido removido de la "
|
"{name} fue saltado cuatro veces consecutivas y ha sido eliminado de la "
|
||||||
"partida.\n"
|
"partida.\n"
|
||||||
"Partida finalizada."
|
"Partida finalizada."
|
||||||
|
|
||||||
|
@ -282,11 +281,11 @@ msgstr "Partida actual: {group}"
|
||||||
#: bot.py:545
|
#: bot.py:545
|
||||||
#, python-format
|
#, python-format
|
||||||
msgid "Cheat attempt by {name}"
|
msgid "Cheat attempt by {name}"
|
||||||
msgstr "Intento de trampa por {name}"
|
msgstr "{name} intentó hacer trampa."
|
||||||
|
|
||||||
#: bot.py:562
|
#: bot.py:562
|
||||||
msgid "Next player: {name}"
|
msgid "Next player: {name}"
|
||||||
msgstr "Siguiente Jugador: {name}"
|
msgstr "Siguiente Jugador: {name}."
|
||||||
|
|
||||||
#: bot.py:572
|
#: bot.py:572
|
||||||
#, python-format
|
#, python-format
|
||||||
|
@ -309,12 +308,12 @@ msgstr "No hay más cartas en la baraja."
|
||||||
#: bot.py:627
|
#: bot.py:627
|
||||||
#, python-format
|
#, python-format
|
||||||
msgid "Bluff called! Giving 4 cards to {name}"
|
msgid "Bluff called! Giving 4 cards to {name}"
|
||||||
msgstr "¡Engaño descubierto! {name} recibe 4 cartas"
|
msgstr "¡Era un farol! {name} recibe 4 cartas."
|
||||||
|
|
||||||
#: bot.py:639
|
#: bot.py:639
|
||||||
#, python-format
|
#, python-format
|
||||||
msgid "{name1} didn't bluff! Giving 6 cards to {name2}"
|
msgid "{name1} didn't bluff! Giving 6 cards to {name2}"
|
||||||
msgstr "¡{name1} no ha engañado!, {name2} recibe 6 cartas"
|
msgstr "¡{name1} no se había tirado un farol!, {name2} recibe 6 cartas."
|
||||||
|
|
||||||
#: results.py:38
|
#: results.py:38
|
||||||
msgid "Choose Color"
|
msgid "Choose Color"
|
||||||
|
@ -323,16 +322,16 @@ msgstr "Selecciona un color"
|
||||||
#: results.py:56
|
#: results.py:56
|
||||||
msgid "Last card (tap for game state):"
|
msgid "Last card (tap for game state):"
|
||||||
msgid_plural "Cards (tap for game state):"
|
msgid_plural "Cards (tap for game state):"
|
||||||
msgstr[0] "Última carta (presiona para el estado de la partida):"
|
msgstr[0] "Última carta (pulsa para ver el estado de la partida):"
|
||||||
msgstr[1] "Cartas (presiona para el estado de la partida):"
|
msgstr[1] "Cartas (pulsa para ver el estado de la partida):"
|
||||||
|
|
||||||
#: results.py:60 results.py:123 results.py:165
|
#: results.py:60 results.py:123 results.py:165
|
||||||
msgid "Current player: {name}"
|
msgid "Current player: {name}"
|
||||||
msgstr "Jugador actual: {name}"
|
msgstr "Jugador actual: {name}."
|
||||||
|
|
||||||
#: results.py:61 results.py:124 results.py:167
|
#: results.py:61 results.py:124 results.py:167
|
||||||
msgid "Last card: {card}"
|
msgid "Last card: {card}"
|
||||||
msgstr "Última carta: {card}"
|
msgstr "Última carta: {card}."
|
||||||
|
|
||||||
#: results.py:62 results.py:125 results.py:168
|
#: results.py:62 results.py:125 results.py:168
|
||||||
msgid "Player: {player_list}"
|
msgid "Player: {player_list}"
|
||||||
|
@ -349,30 +348,30 @@ msgstr[1] "{name} ({number} cartas)"
|
||||||
|
|
||||||
#: results.py:81
|
#: results.py:81
|
||||||
msgid "You are not playing"
|
msgid "You are not playing"
|
||||||
msgstr "No estás jugando"
|
msgstr "No estás jugando."
|
||||||
|
|
||||||
#: results.py:83
|
#: results.py:83
|
||||||
msgid ""
|
msgid ""
|
||||||
"Not playing right now. Use /new to start a game or /join to join the current "
|
"Not playing right now. Use /new to start a game or /join to join the current "
|
||||||
"game in this group"
|
"game in this group"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
"No estas jugando en este momento. Usa /new para comenzar una partida o /"
|
"No estás jugando en este momento. Usa /new para comenzar una partida o /"
|
||||||
"join para unirte a la partida actual en este grupo"
|
"join si hay una partida en curso en este grupo."
|
||||||
|
|
||||||
#: results.py:95
|
#: results.py:95
|
||||||
msgid "The game wasn't started yet"
|
msgid "The game wasn't started yet"
|
||||||
msgstr "La partida no ha comenzado todavía"
|
msgstr "La partida no ha comenzado todavía."
|
||||||
|
|
||||||
#: results.py:97
|
#: results.py:97
|
||||||
msgid "Start the game with /start"
|
msgid "Start the game with /start"
|
||||||
msgstr "Comenzar la partida con /start"
|
msgstr "Comienza la partida con /start."
|
||||||
|
|
||||||
#: results.py:108
|
#: results.py:108
|
||||||
#, python-format
|
#, python-format
|
||||||
msgid "Drawing {number} card"
|
msgid "Drawing {number} card"
|
||||||
msgid_plural "Drawing {number} cards"
|
msgid_plural "Drawing {number} cards"
|
||||||
msgstr[0] "Robando {number} carta"
|
msgstr[0] "Robando {number} carta."
|
||||||
msgstr[1] "Robando {number} cartas"
|
msgstr[1] "Robando {number} cartas."
|
||||||
|
|
||||||
#: results.py:136
|
#: results.py:136
|
||||||
msgid "Pass"
|
msgid "Pass"
|
||||||
|
@ -380,7 +379,7 @@ msgstr "Pasar"
|
||||||
|
|
||||||
#: results.py:148
|
#: results.py:148
|
||||||
msgid "I'm calling your bluff!"
|
msgid "I'm calling your bluff!"
|
||||||
msgstr "Me estas engañando!"
|
msgstr "¡Es un farol!"
|
||||||
|
|
||||||
#: settings.py:39
|
#: settings.py:39
|
||||||
msgid "Please edit your settings in a private chat with the bot."
|
msgid "Please edit your settings in a private chat with the bot."
|
||||||
|
@ -404,45 +403,45 @@ msgstr "Ajustes"
|
||||||
|
|
||||||
#: settings.py:68
|
#: settings.py:68
|
||||||
msgid "Enabled statistics!"
|
msgid "Enabled statistics!"
|
||||||
msgstr "Estadísticas habilitadas!"
|
msgstr "¡Estadísticas habilitadas!"
|
||||||
|
|
||||||
#: settings.py:70
|
#: settings.py:70
|
||||||
msgid "Select locale"
|
msgid "Select locale"
|
||||||
msgstr "Seleccionar región"
|
msgstr "Selecciona tu idioma"
|
||||||
|
|
||||||
#: settings.py:81
|
#: settings.py:81
|
||||||
msgid "Deleted and disabled statistics!"
|
msgid "Deleted and disabled statistics!"
|
||||||
msgstr "Estadísticas borradas y deshabilitadas! "
|
msgstr "¡Estadísticas borradas y deshabilitadas! "
|
||||||
|
|
||||||
#: settings.py:94
|
#: settings.py:94
|
||||||
msgid "Set locale!"
|
msgid "Set locale!"
|
||||||
msgstr "Región seleccionada!"
|
msgstr "¡Idioma seleccionada!"
|
||||||
|
|
||||||
#: simple_commands.py
|
#: simple_commands.py
|
||||||
msgid ""
|
msgid ""
|
||||||
"You did not enable statistics. Use /settings in a private chat with the bot "
|
"You did not enable statistics. Use /settings in a private chat with the bot "
|
||||||
"to enable them."
|
"to enable them."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
"No has habilitado las estadísticas. Usa /settings en un chat privado con el "
|
"Tus estadísticas no están habilitadas. Usa /settings en un chat privado con el "
|
||||||
"bot para habilitarlas."
|
"bot para habilitarlas."
|
||||||
|
|
||||||
#: simple_commands.py
|
#: simple_commands.py
|
||||||
msgid "{number} game played"
|
msgid "{number} game played"
|
||||||
msgid_plural "{number} games played"
|
msgid_plural "{number} games played"
|
||||||
msgstr[0] "{number} partida jugada"
|
msgstr[0] "{number} partida jugada."
|
||||||
msgstr[1] "{number} partidas jugadas"
|
msgstr[1] "{number} partidas jugadas."
|
||||||
|
|
||||||
#: simple_commands.py
|
#: simple_commands.py
|
||||||
msgid "{number} first place"
|
msgid "{number} first place"
|
||||||
msgid_plural "{number} first places"
|
msgid_plural "{number} first places"
|
||||||
msgstr[0] "{number} primero lugare"
|
msgstr[0] "{number} primer lugar."
|
||||||
msgstr[1] "{number} primeros lugares"
|
msgstr[1] "{number} primeros lugares."
|
||||||
|
|
||||||
#: simple_commands.py
|
#: simple_commands.py
|
||||||
msgid "{number} card played"
|
msgid "{number} card played"
|
||||||
msgid_plural "{number} cards played"
|
msgid_plural "{number} cards played"
|
||||||
msgstr[0] "{number} carta jugada"
|
msgstr[0] "{number} carta jugada."
|
||||||
msgstr[1] "{number} cartas jugadas"
|
msgstr[1] "{number} cartas jugadas."
|
||||||
|
|
||||||
#: utils.py
|
#: utils.py
|
||||||
msgid "{emoji} Green"
|
msgid "{emoji} Green"
|
||||||
|
|
62
player.py
62
player.py
|
@ -2,7 +2,7 @@
|
||||||
# -*- coding: utf-8 -*-
|
# -*- coding: utf-8 -*-
|
||||||
#
|
#
|
||||||
# Telegram bot to play UNO in group chats
|
# Telegram bot to play UNO in group chats
|
||||||
# Copyright (c) 2016 Jannes Höke <uno@jhoeke.de>
|
# Copyright (c) 2016 - 2017 Jannes Höke <uno@jhoeke.de> and Karho Yau
|
||||||
#
|
#
|
||||||
# This program is free software: you can redistribute it and/or modify
|
# This program is free software: you can redistribute it and/or modify
|
||||||
# it under the terms of the GNU Affero General Public License as
|
# it under the terms of the GNU Affero General Public License as
|
||||||
|
@ -63,7 +63,7 @@ class Player(object):
|
||||||
self.drew = False
|
self.drew = False
|
||||||
self.anti_cheat = 0
|
self.anti_cheat = 0
|
||||||
self.turn_started = datetime.now()
|
self.turn_started = datetime.now()
|
||||||
self.waiting_time = 90
|
self.waiting_time = 60
|
||||||
|
|
||||||
def leave(self):
|
def leave(self):
|
||||||
"""Removes player from the game and closes the gap in the list"""
|
"""Removes player from the game and closes the gap in the list"""
|
||||||
|
@ -160,25 +160,51 @@ class Player(object):
|
||||||
|
|
||||||
is_playable = True
|
is_playable = True
|
||||||
last = self.game.last_card
|
last = self.game.last_card
|
||||||
|
mode = self.game.mode
|
||||||
self.logger.debug("Checking card " + str(card))
|
self.logger.debug("Checking card " + str(card))
|
||||||
|
|
||||||
if (card.color != last.color and card.value != last.value and
|
if mode == 0: # This mode is to apply the original rule
|
||||||
|
if (card.color != last.color and card.value != last.value and
|
||||||
not card.special):
|
not card.special):
|
||||||
self.logger.debug("Card's color or value doesn't match")
|
self.logger.debug("Card's color or value doesn't match")
|
||||||
is_playable = False
|
is_playable = False
|
||||||
elif last.value == c.DRAW_TWO and not \
|
elif last.value == c.DRAW_TWO and self.game.draw_counter:
|
||||||
card.value == c.DRAW_TWO and self.game.draw_counter:
|
self.logger.debug("Player has to draw and can't counter")
|
||||||
self.logger.debug("Player has to draw and can't counter")
|
is_playable = False
|
||||||
is_playable = False
|
elif last.special == c.DRAW_FOUR and self.game.draw_counter:
|
||||||
elif last.special == c.DRAW_FOUR and self.game.draw_counter:
|
self.logger.debug("Player has to draw and can't counter")
|
||||||
self.logger.debug("Player has to draw and can't counter")
|
is_playable = False
|
||||||
is_playable = False
|
elif (last.special == c.CHOOSE or last.special == c.DRAW_FOUR) and \
|
||||||
elif (last.special == c.CHOOSE or last.special == c.DRAW_FOUR) and \
|
|
||||||
(card.special == c.CHOOSE or card.special == c.DRAW_FOUR):
|
(card.special == c.CHOOSE or card.special == c.DRAW_FOUR):
|
||||||
self.logger.debug("Can't play colorchooser on another one")
|
self.logger.debug("Can't play colorchooser on another one")
|
||||||
is_playable = False
|
is_playable = False
|
||||||
elif not last.color:
|
# Prevent game being locked by choosing colors.
|
||||||
self.logger.debug("Last card has no color")
|
# When player is going to leave and he doesn't select a color, it causes game lock.
|
||||||
is_playable = False
|
elif not last.color and (last.special != c.CHOOSE and last.special != c.DRAW_FOUR):
|
||||||
|
self.logger.debug("Last card has no color")
|
||||||
|
is_playable = False
|
||||||
|
|
||||||
|
elif mode == 1: # This mode is to apply the Progressive UNO rule.
|
||||||
|
if (card.color != last.color and card.value != last.value and
|
||||||
|
not card.special):
|
||||||
|
self.logger.debug("Card's color or value doesn't match")
|
||||||
|
is_playable = False
|
||||||
|
elif last.value == c.DRAW_TWO and self.game.draw_counter and not \
|
||||||
|
card.value == c.DRAW_TWO:
|
||||||
|
self.logger.debug("Player has to draw and can't counter")
|
||||||
|
is_playable = False
|
||||||
|
elif last.special == c.DRAW_FOUR and self.game.draw_counter and not \
|
||||||
|
card.special == c.DRAW_FOUR:
|
||||||
|
self.logger.debug("Player has to draw and can't counter")
|
||||||
|
is_playable = False
|
||||||
|
elif (last.special == c.CHOOSE and (card.special == c.CHOOSE or card.special == c.DRAW_FOUR)) or \
|
||||||
|
(last.special == c.DRAW_FOUR and card.special == c.CHOOSE):
|
||||||
|
self.logger.debug("Can't play colorchooser on another one")
|
||||||
|
is_playable = False
|
||||||
|
# Prevent game being locked by choosing colors.
|
||||||
|
# When player is going to leave and he doesn't select a color, it causes game lock.
|
||||||
|
elif not last.color and (last.special != c.CHOOSE and last.special != c.DRAW_FOUR):
|
||||||
|
self.logger.debug("Last card has no color")
|
||||||
|
is_playable = False
|
||||||
|
|
||||||
return is_playable
|
return is_playable
|
||||||
|
|
202
test_player.py
Normal file
202
test_player.py
Normal file
|
@ -0,0 +1,202 @@
|
||||||
|
#!/usr/bin/env python3
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
#
|
||||||
|
# Telegram bot to play UNO in group chats
|
||||||
|
# Copyright (c) 2016 Jannes Höke <uno@jhoeke.de>
|
||||||
|
#
|
||||||
|
# This program is free software: you can redistribute it and/or modify
|
||||||
|
# it under the terms of the GNU Affero General Public License as
|
||||||
|
# published by the Free Software Foundation, either version 3 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 Affero General Public License for more details.
|
||||||
|
#
|
||||||
|
# You should have received a copy of the GNU Affero General Public License
|
||||||
|
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
|
||||||
|
import unittest
|
||||||
|
|
||||||
|
import telegram
|
||||||
|
from game import Game
|
||||||
|
from player import Player
|
||||||
|
import card as c
|
||||||
|
|
||||||
|
import logging
|
||||||
|
logging.basicConfig(
|
||||||
|
format='%(asctime)s - %(name)s - %(levelname)s - %(message)s',
|
||||||
|
level=logging.DEBUG)
|
||||||
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
|
||||||
|
class Test(unittest.TestCase):
|
||||||
|
|
||||||
|
game = None
|
||||||
|
|
||||||
|
def setUp(self):
|
||||||
|
self.game = Game(None)
|
||||||
|
|
||||||
|
def test_insert(self):
|
||||||
|
p0 = Player(self.game, "Player 0")
|
||||||
|
p1 = Player(self.game, "Player 1")
|
||||||
|
p2 = Player(self.game, "Player 2")
|
||||||
|
|
||||||
|
self.assertEqual(p0, p2.next)
|
||||||
|
self.assertEqual(p1, p0.next)
|
||||||
|
self.assertEqual(p2, p1.next)
|
||||||
|
|
||||||
|
self.assertEqual(p0.prev, p2)
|
||||||
|
self.assertEqual(p1.prev, p0)
|
||||||
|
self.assertEqual(p2.prev, p1)
|
||||||
|
|
||||||
|
def test_reverse(self):
|
||||||
|
p0 = Player(self.game, "Player 0")
|
||||||
|
p1 = Player(self.game, "Player 1")
|
||||||
|
p2 = Player(self.game, "Player 2")
|
||||||
|
self.game.reverse()
|
||||||
|
p3 = Player(self.game, "Player 3")
|
||||||
|
|
||||||
|
self.assertEqual(p0, p3.next)
|
||||||
|
self.assertEqual(p1, p2.next)
|
||||||
|
self.assertEqual(p2, p0.next)
|
||||||
|
self.assertEqual(p3, p1.next)
|
||||||
|
|
||||||
|
self.assertEqual(p0, p2.prev)
|
||||||
|
self.assertEqual(p1, p3.prev)
|
||||||
|
self.assertEqual(p2, p1.prev)
|
||||||
|
self.assertEqual(p3, p0.prev)
|
||||||
|
|
||||||
|
def test_leave(self):
|
||||||
|
p0 = Player(self.game, "Player 0")
|
||||||
|
p1 = Player(self.game, "Player 1")
|
||||||
|
p2 = Player(self.game, "Player 2")
|
||||||
|
|
||||||
|
p1.leave()
|
||||||
|
|
||||||
|
self.assertEqual(p0, p2.next)
|
||||||
|
self.assertEqual(p2, p0.next)
|
||||||
|
|
||||||
|
def test_draw(self):
|
||||||
|
p = Player(self.game, "Player 0")
|
||||||
|
|
||||||
|
deck_before = len(self.game.deck.cards)
|
||||||
|
top_card = self.game.deck.cards[-1]
|
||||||
|
|
||||||
|
p.draw()
|
||||||
|
|
||||||
|
self.assertEqual(top_card, p.cards[-1])
|
||||||
|
self.assertEqual(deck_before, len(self.game.deck.cards) + 1)
|
||||||
|
|
||||||
|
def test_draw_two(self):
|
||||||
|
p = Player(self.game, "Player 0")
|
||||||
|
|
||||||
|
deck_before = len(self.game.deck.cards)
|
||||||
|
self.game.draw_counter = 2
|
||||||
|
|
||||||
|
p.draw()
|
||||||
|
|
||||||
|
self.assertEqual(deck_before, len(self.game.deck.cards) + 2)
|
||||||
|
|
||||||
|
def test_playable_cards_simple(self):
|
||||||
|
p = Player(self.game, "Player 0")
|
||||||
|
|
||||||
|
self.game.last_card = c.Card(c.RED, '5')
|
||||||
|
|
||||||
|
p.cards = [c.Card(c.RED, '0'), c.Card(c.RED, '5'), c.Card(c.BLUE, '0'),
|
||||||
|
c.Card(c.GREEN, '5'), c.Card(c.GREEN, '8')]
|
||||||
|
|
||||||
|
expected = [c.Card(c.RED, '0'), c.Card(c.RED, '5'),
|
||||||
|
c.Card(c.GREEN, '5')]
|
||||||
|
|
||||||
|
self.assertListEqual(p.playable_cards(), expected)
|
||||||
|
|
||||||
|
def test_playable_cards_on_draw_two(self):
|
||||||
|
p = Player(self.game, "Player 0")
|
||||||
|
|
||||||
|
self.game.last_card = c.Card(c.RED, c.DRAW_TWO)
|
||||||
|
self.game.draw_counter = 2
|
||||||
|
|
||||||
|
p.cards = [c.Card(c.RED, c.DRAW_TWO), c.Card(c.RED, '5'),
|
||||||
|
c.Card(c.BLUE, '0'), c.Card(c.GREEN, '5'),
|
||||||
|
c.Card(c.GREEN, c.DRAW_TWO)]
|
||||||
|
|
||||||
|
expected = [c.Card(c.RED, c.DRAW_TWO), c.Card(c.GREEN, c.DRAW_TWO)]
|
||||||
|
|
||||||
|
self.assertListEqual(p.playable_cards(), expected)
|
||||||
|
|
||||||
|
def test_playable_cards_on_draw_two_then_four(self):
|
||||||
|
p = Player(self.game, "Player 0")
|
||||||
|
|
||||||
|
self.game.last_card = c.Card(c.RED, c.DRAW_TWO)
|
||||||
|
self.game.draw_counter = 2
|
||||||
|
|
||||||
|
p.cards = [c.Card(c.RED, c.DRAW_TWO), c.Card(c.RED, '5'),
|
||||||
|
c.Card(c.BLUE, '0'), c.Card(c.GREEN, '5'),
|
||||||
|
c.Card(c.GREEN, c.DRAW_TWO),
|
||||||
|
c.Card(None, None, c.DRAW_FOUR)]
|
||||||
|
|
||||||
|
expected = [c.Card(c.RED, c.DRAW_TWO), c.Card(c.GREEN, c.DRAW_TWO), c.Card(None, None, c.DRAW_FOUR)]
|
||||||
|
|
||||||
|
self.assertListEqual(p.playable_cards(), expected)
|
||||||
|
|
||||||
|
def test_playable_cards_on_draw_four(self):
|
||||||
|
p = Player(self.game, "Player 0")
|
||||||
|
|
||||||
|
self.game.last_card = c.Card(c.RED, None, c.DRAW_FOUR)
|
||||||
|
self.game.draw_counter = 4
|
||||||
|
|
||||||
|
p.cards = [c.Card(c.RED, c.DRAW_TWO), c.Card(c.RED, '5'),
|
||||||
|
c.Card(c.BLUE, '0'), c.Card(c.GREEN, '5'),
|
||||||
|
c.Card(c.GREEN, c.DRAW_TWO),
|
||||||
|
c.Card(None, None, c.DRAW_FOUR),
|
||||||
|
c.Card(None, None, c.CHOOSE)]
|
||||||
|
|
||||||
|
expected = [c.Card(None, None, c.DRAW_FOUR)]
|
||||||
|
self.assertListEqual(p.playable_cards(), expected)
|
||||||
|
|
||||||
|
# def test_playable_cards_on_draw_four_then_four(self):
|
||||||
|
# p = Player(self.game, "Player 0")
|
||||||
|
|
||||||
|
# self.game.last_card = c.Card(c.RED, None, c.DRAW_FOUR)
|
||||||
|
# self.game.draw_counter = 4
|
||||||
|
|
||||||
|
# p.cards = [c.Card(c.RED, c.DRAW_TWO), c.Card(c.RED, '5'),
|
||||||
|
# c.Card(c.BLUE, '0'), c.Card(c.GREEN, '5'),
|
||||||
|
# c.Card(c.GREEN, c.DRAW_TWO),
|
||||||
|
# c.Card(None, None, c.DRAW_FOUR)]
|
||||||
|
|
||||||
|
# expected = [c.Card(None, None, c.DRAW_FOUR)]
|
||||||
|
# self.assertListEqual(p.playable_cards(), expected)
|
||||||
|
|
||||||
|
def test_bluffing(self):
|
||||||
|
p = Player(self.game, "Player 0")
|
||||||
|
Player(self.game, "Player 01")
|
||||||
|
|
||||||
|
self.game.last_card = c.Card(c.RED, '1')
|
||||||
|
|
||||||
|
p.cards = [c.Card(c.RED, c.DRAW_TWO), c.Card(c.RED, '5'),
|
||||||
|
c.Card(c.BLUE, '0'), c.Card(c.GREEN, '5'),
|
||||||
|
c.Card(c.RED, '5'), c.Card(c.GREEN, c.DRAW_TWO),
|
||||||
|
c.Card(None, None, c.DRAW_FOUR),
|
||||||
|
c.Card(None, None, c.CHOOSE)]
|
||||||
|
|
||||||
|
p.playable_cards()
|
||||||
|
self.assertTrue(p.bluffing)
|
||||||
|
|
||||||
|
p.cards = [c.Card(c.BLUE, '1'), c.Card(c.GREEN, '1'),
|
||||||
|
c.Card(c.GREEN, c.DRAW_TWO),
|
||||||
|
c.Card(None, None, c.DRAW_FOUR),
|
||||||
|
c.Card(None, None, c.CHOOSE)]
|
||||||
|
|
||||||
|
p.playable_cards()
|
||||||
|
|
||||||
|
p.play(c.Card(None, None, c.DRAW_FOUR))
|
||||||
|
self.game.choose_color(c.GREEN)
|
||||||
|
|
||||||
|
self.assertFalse(self.game.current_player.prev.bluffing)
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
unittest.main()
|
Loading…
Reference in a new issue