mau_mau_bot/card.py

351 lines
14 KiB
Python
Raw Normal View History

2016-05-08 20:37:25 +08:00
#!/usr/bin/env python3
2016-05-20 05:15:46 +08:00
# -*- coding: utf-8 -*-
2016-05-08 20:37:25 +08:00
#
# 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/>.
2016-02-29 06:57:24 +08:00
# Colors
RED = 'r'
BLUE = 'b'
GREEN = 'g'
YELLOW = 'y'
2016-04-29 22:21:03 +08:00
BLACK = 'x'
2016-02-29 06:57:24 +08:00
2016-04-30 18:20:44 +08:00
COLORS = (RED, BLUE, GREEN, YELLOW)
2016-02-29 06:57:24 +08:00
2016-04-19 06:41:23 +08:00
COLOR_ICONS = {
RED: '❤️',
BLUE: '💙',
GREEN: '💚',
YELLOW: '💛',
2016-04-29 22:21:03 +08:00
BLACK: '⬛️'
2016-04-19 06:41:23 +08:00
}
2016-02-29 06:57:24 +08:00
# Values
ZERO = '0'
ONE = '1'
TWO = '2'
THREE = '3'
FOUR = '4'
FIVE = '5'
SIX = '6'
SEVEN = '7'
EIGHT = '8'
NINE = '9'
DRAW_TWO = 'draw'
REVERSE = 'reverse'
SKIP = 'skip'
VALUES = (ZERO, ONE, TWO, THREE, FOUR, FIVE, SIX, SEVEN, EIGHT, NINE, DRAW_TWO,
REVERSE, SKIP)
WILD_VALUES = (ONE, TWO, THREE, FOUR, FIVE, DRAW_TWO, REVERSE, SKIP)
2016-02-29 06:57:24 +08:00
# Special cards
CHOOSE = 'colorchooser'
DRAW_FOUR = 'draw_four'
SPECIALS = (CHOOSE, DRAW_FOUR)
CARDS_CLASSIC = {
"normal": {
"b_0": "BQADBAAD2QEAAl9XmQAB--inQsYcLTsC",
"b_1": "BQADBAAD2wEAAl9XmQABBzh4U-rFicEC",
"b_2": "BQADBAAD3QEAAl9XmQABo3l6TT0MzKwC",
"b_3": "BQADBAAD3wEAAl9XmQAB2y-3TSapRtIC",
"b_4": "BQADBAAD4QEAAl9XmQABT6nhOuolqKYC",
"b_5": "BQADBAAD4wEAAl9XmQABwRfmekGnpn0C",
"b_6": "BQADBAAD5QEAAl9XmQABQITgUsEsqxsC",
"b_7": "BQADBAAD5wEAAl9XmQABVhPF6EcfWjEC",
"b_8": "BQADBAAD6QEAAl9XmQABP6baig0pIvYC",
"b_9": "BQADBAAD6wEAAl9XmQAB0CQdsQs_pXIC",
"b_draw": "BQADBAAD7QEAAl9XmQAB00Wii7R3gDUC",
"b_skip": "BQADBAAD8QEAAl9XmQAB_RJHYKqlc-wC",
"b_reverse": "BQADBAAD7wEAAl9XmQABo7D0B9NUPmYC",
"g_0": "BQADBAAD9wEAAl9XmQABb8CaxxsQ-Y8C",
"g_1": "BQADBAAD-QEAAl9XmQAB9B6ti_j6UB0C",
"g_2": "BQADBAAD-wEAAl9XmQABYpLjOzbRz8EC",
"g_3": "BQADBAAD_QEAAl9XmQABKvc2ZCiY-D8C",
"g_4": "BQADBAAD_wEAAl9XmQABJB52wzPdHssC",
"g_5": "BQADBAADAQIAAl9XmQABp_Ep1I4GA2cC",
"g_6": "BQADBAADAwIAAl9XmQABaaMxxa4MihwC",
"g_7": "BQADBAADBQIAAl9XmQABv5Q264Crz8gC",
"g_8": "BQADBAADBwIAAl9XmQABjMH-X9UHh8sC",
"g_9": "BQADBAADCQIAAl9XmQAB26fZ2fW7vM0C",
"g_draw": "BQADBAADCwIAAl9XmQAB64jIZrgXrQUC",
"g_skip": "BQADBAADDwIAAl9XmQAB17yhhnh46VQC",
"g_reverse": "BQADBAADDQIAAl9XmQAB_xcaab0DkegC",
"r_0": "BQADBAADEQIAAl9XmQABiUfr1hz-zT8C",
"r_1": "BQADBAADEwIAAl9XmQAB5bWfwJGs6Q0C",
"r_2": "BQADBAADFQIAAl9XmQABHR4mg9Ifjw0C",
"r_3": "BQADBAADFwIAAl9XmQABYBx5O_PG2QIC",
"r_4": "BQADBAADGQIAAl9XmQABTQpGrlvet3cC",
"r_5": "BQADBAADGwIAAl9XmQABbdLt4gdntBQC",
"r_6": "BQADBAADHQIAAl9XmQABqEI274p3lSoC",
"r_7": "BQADBAADHwIAAl9XmQABCw8u67Q4EK4C",
"r_8": "BQADBAADIQIAAl9XmQAB8iDJmLxp8ogC",
"r_9": "BQADBAADIwIAAl9XmQAB_HCAww1kNGYC",
"r_draw": "BQADBAADJQIAAl9XmQABuz0OZ4l3k6MC",
"r_skip": "BQADBAADKQIAAl9XmQAC2AL5Ok_ULwI",
"r_reverse": "BQADBAADJwIAAl9XmQABu2tIeQTpDvUC",
"y_0": "BQADBAADKwIAAl9XmQAB_nWoNKe8DOQC",
"y_1": "BQADBAADLQIAAl9XmQABVprAGUDKgOQC",
"y_2": "BQADBAADLwIAAl9XmQABqyT4_YTm54EC",
"y_3": "BQADBAADMQIAAl9XmQABGC-Xxg_N6fIC",
"y_4": "BQADBAADMwIAAl9XmQABbc-ZGL8kApAC",
"y_5": "BQADBAADNQIAAl9XmQAB67QJZIF6XAcC",
"y_6": "BQADBAADNwIAAl9XmQABJg_7XXoITsoC",
"y_7": "BQADBAADOQIAAl9XmQABVrd7OcS2k34C",
"y_8": "BQADBAADOwIAAl9XmQABRpJSahBWk3EC",
"y_9": "BQADBAADPQIAAl9XmQAB9MwJWKLJogYC",
"y_draw": "BQADBAADPwIAAl9XmQABaPYK8oYg84cC",
"y_skip": "BQADBAADQwIAAl9XmQABO_AZKtxY6IMC",
"y_reverse": "BQADBAADQQIAAl9XmQABZdQFahGG6UQC",
"draw_four": "BQADBAAD9QEAAl9XmQABVlkSNfhn76cC",
"colorchooser": "BQADBAAD8wEAAl9XmQABl9rUOPqx4E4C",
},
"not_playable": {
"b_0": "BQADBAADRQIAAl9XmQAB1IfkQ5xAiK4C",
"b_1": "BQADBAADRwIAAl9XmQABbWvhTeKBii4C",
"b_2": "BQADBAADSQIAAl9XmQABS1djHgyQokMC",
"b_3": "BQADBAADSwIAAl9XmQABwQ6VTbgY-MIC",
"b_4": "BQADBAADTQIAAl9XmQABAlKUYha8YccC",
"b_5": "BQADBAADTwIAAl9XmQABMvx8xVDnhUEC",
"b_6": "BQADBAADUQIAAl9XmQABDEbhP1Zd31kC",
"b_7": "BQADBAADUwIAAl9XmQABXb5XQBBaAnIC",
"b_8": "BQADBAADVQIAAl9XmQABgL5HRDLvrjgC",
"b_9": "BQADBAADVwIAAl9XmQABtO3XDQWZLtYC",
"b_draw": "BQADBAADWQIAAl9XmQAB2kk__6_2IhMC",
"b_skip": "BQADBAADXQIAAl9XmQABEGJI6CaH3vcC",
"b_reverse": "BQADBAADWwIAAl9XmQAB_kZA6UdHXU8C",
"g_0": "BQADBAADYwIAAl9XmQABGD5a9oG7Yg4C",
"g_1": "BQADBAADZQIAAl9XmQABqwABZHAXZIg0Ag",
"g_2": "BQADBAADZwIAAl9XmQABTI3mrEhojRkC",
"g_3": "BQADBAADaQIAAl9XmQABVi3rUyzWS3YC",
"g_4": "BQADBAADawIAAl9XmQABZIf5ThaXnpUC",
"g_5": "BQADBAADbQIAAl9XmQABNndVJSQCenIC",
"g_6": "BQADBAADbwIAAl9XmQABpoy1c4ZkrvwC",
"g_7": "BQADBAADcQIAAl9XmQABDeaT5fzxwREC",
"g_8": "BQADBAADcwIAAl9XmQABLIQ06ZM5NnAC",
"g_9": "BQADBAADdQIAAl9XmQABel-mC7eXGsMC",
"g_draw": "BQADBAADdwIAAl9XmQABOHEpxSztCf8C",
"g_skip": "BQADBAADewIAAl9XmQABDaQdMxjjPsoC",
"g_reverse": "BQADBAADeQIAAl9XmQABek1lGz7SJNAC",
"r_0": "BQADBAADfQIAAl9XmQABWrxoiXcsg0EC",
"r_1": "BQADBAADfwIAAl9XmQABlav-bkgSgRcC",
"r_2": "BQADBAADgQIAAl9XmQABDjZkqfJ4AdAC",
"r_3": "BQADBAADgwIAAl9XmQABT7lH7VVcy3MC",
"r_4": "BQADBAADhQIAAl9XmQAB1arPC5x0LrwC",
"r_5": "BQADBAADhwIAAl9XmQABWvs7xkCDldkC",
"r_6": "BQADBAADiQIAAl9XmQABjwABH5ZonWn8Ag",
"r_7": "BQADBAADiwIAAl9XmQABjekJfm4fBDIC",
"r_8": "BQADBAADjQIAAl9XmQABqFjchpsJeEkC",
"r_9": "BQADBAADjwIAAl9XmQAB-sKdcgABdNKDAg",
"r_draw": "BQADBAADkQIAAl9XmQABtw9RPVDHZOQC",
"r_skip": "BQADBAADlQIAAl9XmQABtG2GixCxtX4C",
"r_reverse": "BQADBAADkwIAAl9XmQABz2qyEbabnVsC",
"y_0": "BQADBAADlwIAAl9XmQABAb3ZwTGS1lMC",
"y_1": "BQADBAADmQIAAl9XmQAB9v5qJk9R0x8C",
"y_2": "BQADBAADmwIAAl9XmQABCsgpRHC2g-cC",
"y_3": "BQADBAADnQIAAl9XmQAB3kLLXCv-qY0C",
"y_4": "BQADBAADnwIAAl9XmQAB7R_y-NexNLIC",
"y_5": "BQADBAADoQIAAl9XmQABl-7mwsjD-cMC",
"y_6": "BQADBAADowIAAl9XmQABwbVsyv2MfPkC",
"y_7": "BQADBAADpQIAAl9XmQABoBqC0JsemVwC",
"y_8": "BQADBAADpwIAAl9XmQABpkwAAeh9ldlHAg",
"y_9": "BQADBAADqQIAAl9XmQABpSBEUfd4IM8C",
"y_draw": "BQADBAADqwIAAl9XmQABMt-2zW0VYb4C",
"y_skip": "BQADBAADrwIAAl9XmQABIDf-_TuuxtEC",
"y_reverse": "BQADBAADrQIAAl9XmQABm9M0Zh-_UwkC",
"draw_four": "BQADBAADYQIAAl9XmQAB_HWlvZIscDEC",
"colorchooser": "BQADBAADXwIAAl9XmQABY_ksDdMex-wC",
},
}
CARDS_CLASSIC_COLORBLIND = {
"normal": {
"colorchooser": "CAADBAADrg4AAvX2mVEpx_BiDIE5nQI",
"draw_four": "CAADBAADYRAAArnkmVGmqXHhjWEBxAI",
"r_0": "CAADBAAD6A8AAn_ckVHPWHqiBR_3jAI",
"r_1": "CAADBAAD5Q0AAg-ImVEx-blQI88RrQI",
"r_2": "CAADBAAD1g0AAuMjmVEkQsVhN49DMAI",
"r_3": "CAADBAADlhAAAqy4mVHWovoaWfQG_gI",
"r_4": "CAADBAADCRoAAqf_kVFnl8ACL1rjpwI",
"r_5": "CAADBAADVw8AAjmamVEEv2TVeL9cpQI",
"r_6": "CAADBAADHQ4AAuuUkVH2I-yn6nRBVAI",
"r_7": "CAADBAADNQ8AArP1kVF5rqHtk0pQ-AI",
"r_8": "CAADBAAD1BAAAuQDkVEPiIodUi6WvwI",
"r_9": "CAADBAAD2Q4AAq1nkFHM6z5C0Kff2QI",
"r_draw": "CAADBAADvQ8AAqZukFGEmkRSoSZQEwI",
"r_reverse": "CAADBAAD5RAAAg89mVE8-EY_2DifcAI",
"r_skip": "CAADBAADRg4AAp8bmVFOC6xdEZZRwwI",
"g_0": "CAADBAADTg4AAoQxmFF07jR_vfB4xgI",
"g_1": "CAADBAADQg4AAhkgmFGlsif9nNtXwgI",
"g_2": "CAADBAAD2BUAAue_mFGENiPSjZxbiQI",
"g_3": "CAADBAADpw4AAjO9mFHAOz8KD2n7BwI",
"g_4": "CAADBAADRhAAAqF7kFEcwLalLfDfaAI",
"g_5": "CAADBAADAg8AAqXLmFHJyg2F_ybbvwI",
"g_6": "CAADBAADVhYAAtK7mVGigRq_EkCuVgI",
"g_7": "CAADBAAD2RIAArccmFEj-8LIVNAbsgI",
"g_8": "CAADBAAD6AwAAuvmmFHBRarMimOWawI",
"g_9": "CAADBAADExEAAsNkmVFr8DaHGOwsggI",
"g_draw": "CAADBAADhA8AArxYmVH9ch5Jp00AAboC",
"g_reverse": "CAADBAADMhAAAvVOmFGH284LIY7cegI",
"g_skip": "CAADBAADbBcAAqinkVEOwkJtDRfk2gI",
"b_0": "CAADBAAD-BAAAkj8kFG61GJdw29QOAI",
"b_1": "CAADBAADcRMAAu-EmFFT1i4LcqO4OQI",
"b_2": "CAADBAAD0xQAAqVhmVHyrFSAbxtfjwI",
"b_3": "CAADBAADNg0AAn-xmFHev8IdF_ie0wI",
"b_4": "CAADBAADlQ4AAjZamVFcIL_pVB5cFwI",
"b_5": "CAADBAADrgwAAuL5mVHvEBZ8CG5p5QI",
"b_6": "CAADBAADDhUAAuGRmVGQYvmEOxczBAI",
"b_7": "CAADBAADIxEAAv_dmFEuVt39kkgZgwI",
"b_8": "CAADBAAD2w0AAoE6kVHG7WscV4F2hwI",
"b_9": "CAADBAADvQ0AArRMmVErWaSRP_giKQI",
"b_draw": "CAADBAADlw4AAjF_kFHPWSoYKBwtwQI",
"b_reverse": "CAADBAADog8AAqDJmVEJQp5WocnUnQI",
"b_skip": "CAADBAAD-QwAAgbZmFGltUlnslDNUQI",
"y_0": "CAADBAADrQ4AAr5WmVHNf69eBn2YOAI",
"y_1": "CAADBAADcg8AAmqKmVHfVeUI3u_i7AI",
"y_2": "CAADBAADkA4AAuDImFEQ8qjFlcKplQI",
"y_3": "CAADBAAD-QwAAmromFGAqVn-Y8N72wI",
"y_4": "CAADBAADjQ4AAmNLmFG80k7kfgx1NAI",
"y_5": "CAADBAADqQ8AAmgYmFH1_ey_bMQNYwI",
"y_6": "CAADBAADdQ0AAuWcmFEbG_gm1wGYCQI",
"y_7": "CAADBAAD6QwAApQAAZhRI8OfRvLX3vkC",
"y_8": "CAADBAADARAAAi-2kVEifJ-O9WVilgI",
"y_9": "CAADBAADxA0AAhQ8mFHjnl9tUCHSLAI",
"y_draw": "CAADBAADzw4AAncZmVEhLhX17eqX8AI",
"y_reverse": "CAADBAADTxAAAqgFmVEJRBw4eWgnDwI",
"y_skip": "CAADBAADPhYAAiGbkFG9hptFPLgj7wI",
},
"not_playable": {
"colorchooser": "CAADBAADpQ4AAlfDmFFHGkwyGFeCFQI",
"draw_four": "CAADBAADMRMAAv7amFHvKGLoNyFbNQI",
"r_0": "CAADBAADsBMAAuGdkFHTZ-jl4eNn-gI",
"r_1": "CAADBAADVA4AAhpfkFEKt19qveGSPgI",
"r_2": "CAADBAADrw0AAoWsmVHguULNoYJwUwI",
"r_3": "CAADBAADzxMAAjvkkFFdtKJu5WGwUgI",
"r_4": "CAADBAAD1Q8AAoHZkFFvyQnFHzfwiQI",
"r_5": "CAADBAADWxEAAvkHkFGUo86qxKV0kwI",
"r_6": "CAADBAAD_hIAAjx0mVGmlm-b_FHQBAI",
"r_7": "CAADBAADmhEAAslomFHOv7bqcDJkDAI",
"r_8": "CAADBAADtw0AAgqVmVG2HdSbcJYxZgI",
"r_9": "CAADBAADNxEAAuF6mVE3WzTMJkSVAgI",
"r_draw": "CAADBAADVxAAAiNukFE1K2xORNnfMwI",
"r_reverse": "CAADBAADQxMAAvH0mVHKznpt-uu9ngI",
"r_skip": "CAADBAADZA4AApbPkFFB9E2Px-HFpgI",
"g_0": "CAADBAAD8w4AAjDEmFG7DwKggUEj9QI",
"g_1": "CAADBAAD2g0AAo_DmVHIPG84WdIo1wI",
"g_2": "CAADBAADEhEAAoRXmVGIG2nuN45P6AI",
"g_3": "CAADBAADug8AAsSRmFFzk0TcRuG8VAI",
"g_4": "CAADBAADrQ8AAvgmkFESfo9BjF7-3gI",
"g_5": "CAADBAADVhAAAnPqkFFtxtFX9HlT-AI",
"g_6": "CAADBAADMg8AAiSBmFHIQw1jFjv6UwI",
"g_7": "CAADBAADvREAAv0BkVGDq3H1DCq_DQI",
"g_8": "CAADBAADWQ4AAhOEkVG96JDgCtFrEwI",
"g_9": "CAADBAAD2xYAAruDmFFAUMFryEwjoAI",
"g_draw": "CAADBAADLA4AAu9tkVGTzBbeeYydIQI",
"g_reverse": "CAADBAADVAwAAhYYmFExJS0ozE8-rAI",
"g_skip": "CAADBAADYg4AAulsmFHxOkaz9OsTiwI",
"b_0": "CAADBAADVxUAAtnOkFEIAAGw5CZEIxgC",
"b_1": "CAADBAAD1RAAAnQqkFF9kDqD0wp3ngI",
"b_2": "CAADBAADZg4AAvcUmVHTXwldirf1hAI",
"b_3": "CAADBAADfBAAAkX1mVHw0CWX0h31iQI",
"b_4": "CAADBAADPBAAAuTCmFFDpvXzes4qjwI",
"b_5": "CAADBAADTQ4AAsWQmVHcrxDQUWOB4AI",
"b_6": "CAADBAAD_hAAAoUhmVG8kjd65J8EngI",
"b_7": "CAADBAADlRAAArtjkFGko5TuFNnncwI",
"b_8": "CAADBAADZQ8AAltEmFE_fDYIXBrV3QI",
"b_9": "CAADBAADrhAAAtM-mVGwhrWTD9IaYgI",
"b_draw": "CAADBAADtQ0AAnVbmFGC1hI60JaOQQI",
"b_reverse": "CAADBAADShEAAlcOmFHStPeFzfVIEwI",
"b_skip": "CAADBAAD_xEAAgZFmVFMRA1J8Y1gxAI",
"y_0": "CAADBAAD7xAAAqjjmFHnCu7eKJvSBgI",
"y_1": "CAADBAADJQwAAp6tmFE2zDPVMieQ2QI",
"y_2": "CAADBAADNA4AAl2mmVFpQOxJ41gk_gI",
"y_3": "CAADBAAD3A4AAsxPmFGyZFv42UlxAQI",
"y_4": "CAADBAADwg8AAm88kVEc9HZpl2gmzQI",
"y_5": "CAADBAAD5hIAAkQ6mFHS-aGVuYZAnAI",
"y_6": "CAADBAADvQ8AAs3RmVHVkVBfEF7eIwI",
"y_7": "CAADBAAD1gwAAjlbmFGGH6rBdqP8QQI",
"y_8": "CAADBAADbg8AAqvXkVH1ESeZFcGVrgI",
"y_9": "CAADBAADOQ8AAnjokVG96pmCP7aZ3AI",
"y_draw": "CAADBAAD6w4AAgsJmVETUteFwqTVJgI",
"y_reverse": "CAADBAADtg8AAqiFmFFwothyN9TrXwI",
"y_skip": "CAADBAADSxEAAhcSmFGu_F5LffmsZgI",
},
}
STICKERS_OPTIONS = {
"option_draw": "BQADBAAD-AIAAl9XmQABxEjEcFM-VHIC",
"option_pass": "BQADBAAD-gIAAl9XmQABcEkAAbaZ4SicAg",
"option_bluff": "BQADBAADygIAAl9XmQABJoLfB9ntI2UC",
"option_info": "BQADBAADxAIAAl9XmQABC5v3Z77VLfEC",
}
# TODO: Support multiple card packs
# For now, just use classic colorblind
STICKERS = {
**CARDS_CLASSIC_COLORBLIND["normal"],
**STICKERS_OPTIONS,
}
STICKERS_GREY = {
**CARDS_CLASSIC_COLORBLIND["not_playable"],
}
2016-02-29 06:57:24 +08:00
class Card(object):
"""This class represents an UNO card"""
2016-02-29 06:57:24 +08:00
def __init__(self, color, value, special=None):
self.color = color
self.value = value
self.special = special
def __str__(self):
if self.special:
return self.special
else:
return '%s_%s' % (self.color, self.value)
def __repr__(self):
2016-04-19 06:41:23 +08:00
if self.special:
2016-04-29 22:21:03 +08:00
return '%s%s%s' % (COLOR_ICONS.get(self.color, ''),
COLOR_ICONS[BLACK],
' '.join([s.capitalize()
for s in self.special.split('_')]))
2016-04-19 06:41:23 +08:00
else:
return '%s%s' % (COLOR_ICONS[self.color], self.value.capitalize())
2016-02-29 06:57:24 +08:00
2016-02-29 08:53:59 +08:00
def __eq__(self, other):
"""Needed for sorting the cards"""
2016-02-29 08:53:59 +08:00
return str(self) == str(other)
2016-03-01 08:25:26 +08:00
def __lt__(self, other):
"""Needed for sorting the cards"""
2016-03-01 08:25:26 +08:00
return str(self) < str(other)
2016-02-29 06:57:24 +08:00
def from_str(string):
"""Decodes a Card object from a string"""
2016-02-29 19:16:12 +08:00
if string not in SPECIALS:
2016-02-29 06:57:24 +08:00
color, value = string.split('_')
return Card(color, value)
else:
2016-02-29 19:16:12 +08:00
return Card(None, None, string)