Added "Score Mode"

This commit is contained in:
eaocto 2018-10-18 23:26:36 +07:00
parent 37a6c40ebe
commit 10b91f2c98
7 changed files with 177 additions and 7 deletions

View file

@ -7,12 +7,12 @@ from datetime import datetime
from telegram import Message, Chat
from config import TIME_REMOVAL_AFTER_SKIP, MIN_FAST_TURN_TIME
from config import TIME_REMOVAL_AFTER_SKIP, MIN_FAST_TURN_TIME, SCORE_WIN
from errors import DeckEmptyError, NotEnoughPlayersError
from internationalization import __, _
from shared_vars import gm
from user_setting import UserSetting
from utils import send_async, display_name, game_is_running
from utils import send_async, display_name, game_is_running, TIMEOUT
logger = logging.getLogger(__name__)
@ -108,6 +108,77 @@ def do_play_card(bot, player, result_id):
text=__("{name} won!", multi=game.translate)
.format(name=user.first_name))
if game.mode == "score":
game.add_score(player)
score = sum([n[0] for n in game.last_round_score])
bot.sendMessage(chat.id,
text=__("Added {pt} point",
"Added {pt} points",
score)
.format(pt=score))
bot.sendMessage(
chat.id,
text=", ".join(
["{cl} {vl} (+{pt})"
.format(cl=c.COLOR_ICONS[n[1].color],
vl=n[1].value or n[1].special,
pt=n[0])
for n in sorted(game.last_round_score,
key=lambda x: x[0])]))
bot.sendMessage(
chat.id,
text=__("Current standings:\n\n") +
"\n".join([
"{no}. {name}: {pt}".format(
no=i + 1,
name=x[0].user.first_name,
pt=x[1])
for i, x in enumerate(
sorted(game.get_scores(),
key=lambda x: x[1],
reverse=True))]))
bot.sendMessage(
chat.id,
text=__("Points to win: {score}").format(score=game.win_score))
players_cache = game.players
highest = sorted(zip(players_cache, map(
game.get_score, players_cache
)), key=lambda x: x[1])[-1]
if highest[1] >= game.win_score:
send_async(bot, chat.id,
text=__("Game ended! {name} wins the game!",
multi=game.translate)
.format(highest[0].user.first_name))
if us.stats:
us.first_places += 1
for player in players_cache:
us_ = UserSetting.get(id=player.user.id)
if not us:
us_ = UserSetting(id=player.user.id)
us_.games_played += 1
else:
game.reset_cards()
game.new_round()
next_round_message = (
__("Next round!", multi=game.translate))
next_player_message = (
__("First player: {name}\n",
multi=game.translate)
.format(name=display_name(game.current_player.user)))
bot.sendMessage(chat.id,
text=next_round_message,
timeout=TIMEOUT)
bot.sendSticker(chat.id,
sticker=c.STICKERS[str(game.last_card)],
timeout=TIMEOUT)
bot.sendMessage(chat.id,
text=next_player_message,
timeout=TIMEOUT)
return
# If game mode is "score", 'do_play_card' should stop here
if us.stats:
us.games_played += 1

13
bot.py
View file

@ -30,13 +30,15 @@ import card as c
import settings
import simple_commands
from actions import do_skip, do_play_card, do_draw, do_call_bluff, start_player_countdown
from config import WAITING_TIME, DEFAULT_GAMEMODE, MIN_PLAYERS
from config import (WAITING_TIME, DEFAULT_GAMEMODE, MIN_PLAYERS, SCORE_WIN,
SCORE_DUEL, ADDITIONAL_POINT, PLAYER_THRESHOLD)
from errors import (NoGameInChatError, LobbyClosedError, AlreadyJoinedError,
NotEnoughPlayersError, DeckEmptyError)
from internationalization import _, __, user_locale, game_locales
from results import (add_call_bluff, add_choose_color, add_draw, add_gameinfo,
add_no_game, add_not_started, add_other_cards, add_pass,
add_card, add_mode_classic, add_mode_fast, add_mode_wild)
add_card, add_mode_classic, add_mode_fast, add_mode_wild,
add_mode_score)
from shared_vars import gm, updater, dispatcher
from simple_commands import help_handler
from start_bot import start_bot
@ -370,6 +372,12 @@ def start_game(bot, update, args, job_queue):
"before you can start it").format(minplayers=MIN_PLAYERS))
else:
# Set winning score
player_num = len(game.players)
if player_num == 2:
game.win_score = SCORE_DUEL
else:
game.win_score = ADDITIONAL_POINT * player_num
# Starting a game
game.start()
@ -594,6 +602,7 @@ def reply_to_query(bot, update):
add_mode_classic(results)
add_mode_fast(results)
add_mode_wild(results)
add_mode_score(results)
else:
add_not_started(results)

View file

@ -60,6 +60,11 @@ DRAW_FOUR = 'draw_four'
SPECIALS = (CHOOSE, DRAW_FOUR)
# Card score
CARD_SCORES = {v: int(v) for v in VALUES[0:10]}
CARD_SCORES.update({v: 15 for v in VALUES[10:13]})
CARD_SCORES.update({SPECIALS[0]: 20, SPECIALS[1]: 25})
STICKERS = {
'b_0': 'BQADBAAD2QEAAl9XmQAB--inQsYcLTsC',
'b_1': 'BQADBAAD2wEAAl9XmQABBzh4U-rFicEC',

View file

@ -33,3 +33,7 @@ WAITING_TIME = config.get("waiting_time", 120)
TIME_REMOVAL_AFTER_SKIP = config.get("time_removal_after_skip", 20)
MIN_FAST_TURN_TIME = config.get("min_fast_turn_time", 15)
MIN_PLAYERS = config.get("min_players", 2)
SCORE_WIN = config.get("score_mode_win_score", 500)
SCORE_DUEL = config.get("score_mode_win_duel", 100)
ADDITIONAL_POINT = config.get("score_mode_win_per_player_additional", 100)
PLAYER_THRESHOLD = config.get("score_mode_normal_score_threshold_player_count", 5)

54
game.py
View file

@ -19,7 +19,8 @@
import logging
from config import ADMIN_LIST, OPEN_LOBBY, DEFAULT_GAMEMODE, ENABLE_TRANSLATIONS
from config import (ADMIN_LIST, OPEN_LOBBY, DEFAULT_GAMEMODE,
ENABLE_TRANSLATIONS, SCORE_WIN)
from datetime import datetime
from deck import Deck
@ -39,6 +40,9 @@ class Game(object):
owner = ADMIN_LIST
open = OPEN_LOBBY
translate = ENABLE_TRANSLATIONS
scores = dict()
last_round_score = list()
win_score = SCORE_WIN
def __init__(self, chat):
self.chat = chat
@ -137,3 +141,51 @@ class Game(object):
"""Carries out the color choosing and turns the game"""
self.last_card.color = color
self.turn()
def add_score(self, player):
"""Add total value of all card in every players hand
to the winner's score."""
scores = 0
self.last_round_score.clear()
for player in self.players:
for card in player.cards:
sc = c.CARD_SCORES[card.value or card.special]
self.last_round_score.append((sc, card))
scores += sc
try:
self.scores[player.user.id] += scores
except KeyError:
self.scores[player.user.id] = scores
def reset_cards(self):
"""Reset game deck and player's hand"""
players_cache = self.players
# clear player's card, might as well use player.cards.clear()
for player in players_cache:
for card in player.cards:
self.deck.dismiss(card)
player.cards = list()
# fill deck with normal cards set
self.deck._fill_classic_()
# draw player's hand
for player in players_cache:
player.draw_first_hand()
def new_round(self):
lc = self.last_card
while self.last_card == lc or not self.last_card or self.last_card.special:
self.last_card = self.deck.draw()
# If the card drawn was special, return it to the deck and loop again
if self.last_card.special:
self.deck.dismiss(self.last_card)
self.play_card(self.last_card)
def get_score(self, player):
try:
return self.scores[player.user.id]
except KeyError:
self.scores[player.user.id] = 0
return 0
def get_scores(self):
return [(player, self.get_score(player))for player in self.players]

View file

@ -130,6 +130,18 @@ def add_mode_wild(results):
)
def add_mode_score(results):
"""Change mode to classic"""
results.append(
InlineQueryResultArticle(
"mode_score",
title=_("💯 Score mode"),
input_message_content=
InputTextMessageContent(_('Kaching~ 💯'))
)
)
def add_draw(player, results):
"""Add option to draw"""
n = player.game.draw_counter or 1
@ -198,7 +210,10 @@ def add_card(game, card, results, can_play):
def game_info(game):
players = player_list(game)
if game.mode == 'score':
players = score_list(game)
else:
players = player_list(game)
players_numbered = [
'{}. {}'.format(i + 1, p)
for i, p in enumerate(players)
@ -214,3 +229,16 @@ def game_info(game):
len(players))
.format(player_list="\n".join(players_numbered))
)
def score_list(game):
scores = [game.get_score(player) for player in game.players]
plist = [_("{name} ({number} card)",
"{name} ({number} cards)",
len(player.cards))
.format(name=player.user.first_name, number=len(player.cards))
for player in game.players]
return [s + " " +
_("[{point} point]", "[{point} points]", scores[i])
.format(point=scores[i])
for i, s in enumerate(plist)]

View file

@ -75,7 +75,8 @@ attributions = ("Attributions:\n"
modes_explanation = ("This UNO bot has three game modes: Classic, Sanic and Wild.\n\n"
" 🎻 The Classic mode uses the conventional UNO deck and there is no auto skip.\n"
" 🚀 The Sanic mode uses the conventional UNO deck and the bot automatically skips a player if he/she takes too long to play its turn\n"
" 🐉 The Wild mode uses a deck with more special cards, less number variety and no auto skip.\n\n"
" 🐉 The Wild mode uses a deck with more special cards, less number variety and no auto skip.\n"
" 💯 The Score mode is how Uno meant to be played, scored when one player run out of card.\n\n"
"To change the game mode, the GAME CREATOR has to type the bot nickname and a space, just like when playing a card, and all gamemode options should appear.")