#!/usr/bin/env python3
from functools import reduce
from itertools import groupby, zip_longest
from random import randint, sample
from sys import argv, exit
class Card(object):
'''トランプのオブジェクト'''
def __init__(self, suit, number):
self.suit = suit
self.number = number
def __repr__(self):
return f"[{self.suit}:{self.number}]"
def drawCard(player1, player2, pos):
'''カードを引く'''
card = player2[pos]
return card, [card] + player1, player2[:pos] + player2[pos + 1:]
def discardPair(player):
'''カードを捨てる'''
p = [j[0] for j in [list(i) for key, i in \
groupby(sorted(player, key = lambda x: x.number), \
key = lambda x: x.number)] if len(j) != 2]
return list(set(player) - set(p)), p
def selectCard(num):
'''num枚のカードから引くカードを決める'''
return randint(0, num - 1)
def dealCards(deck, n):
'''カードを配る'''
i = len(deck) // n
acc = [deck[x:x + i] for x in range(0, len(deck), i)]
return [i[0] + [i[1]] if i[1] != None else i[0] for i in \
zip_longest(acc[:-1], acc[-1])]
def shuffle_list(lst, n):
'''カードシャッフルする'''
return reduce(lambda x, y: sample(x, len(lst)), range(n), lst)
# メッセージ
message = {"inputSelectCard" : "何枚目のカードを引きますか? (0 〜 {0})\n",
"showNumCard" : "プレイヤー{0}のカード: {1}枚\n",
"showCards" : "プレイヤー{0}のカード: {1}\n",
"showDiscardCards" : "プレイヤー{0}が捨てたカード: {1}\n",
"showDrawCard" : "プレイヤー{0} -> プレイヤー{1} : {2}\n",
"showResult" : "プレイヤー{0}の負けです...\n"}
def showCards(players):
'''手持ちのカードを表示する文字列'''
return "".join([message["showCards"].format(i, getCardsStr(j))\
if i == 0 \
else message["showNumCard"].format(i, len(j))\
for i, j in enumerate(players)])
def showDiscardCards(id, cards):
'''捨てられたカードを表示する文字列'''
if cards == []:
return ""
else:
return message["showDiscardCards"].format(id, getCardsStr(cards))
def showDrawCard(id1, id2, card):
'''カードの交換状況を表示する文字列'''
return message["showDrawCard"].format(id1, id2, getCardStr(card))
def showResult(id):
'''ゲームの結果を表示する文字列'''
return message["showResult"].format(id)
def getCardsStr(cards):
'''Cardオブジェクトのリストを文字列に変換'''
return "".join([getCardStr(i) for i in cards])
def getCardStr(card):
'''Cardオブジェクトを文字列に変換'''
return "{0}".format(card)
def make_deck():
'''トランプのカードを作成する'''
return [Card("J", "0")] + [Card(i, "A" if j == 1 else "J" if j == 11 \
else "Q" if j == 12 else "K" if j == 13 \
else str(j)) for i in \
("D", "H", "S", "C") for j in \
range(1, 14)]
class World(object):
'''環境'''
def __init__(self, card, clist, discarded, pair, id1, id2, players):
self.card = card
self.clist = clist
self.discarded = discarded
self.pair = pair
self.id1 = id1
self.id2 = id2
self.players = players
# read
def read(w):
id1, id2, players = w.id1, w.id2, w.players
k = len(players[id2])
if id1 == 0:
return int(input(message["inputSelectCard"].format(k - 1)))
else:
return selectCard(k)
# eval
def world_go(exp, w):
clist, id1, id2, players = w.clist, w.id1, w.id2, w.players
player1, player2 = players[id1], players[id2]
card, player1, player2 = drawCard(player1, player2, exp)
discarded, player1 = discardPair(player1)
players = insert(id1, player1, insert(id2, player2, players))
new_id1 = next_id(clist, id1 + 1, players)
new_id2 = next_id(clist, new_id1 + 1, players)
return World(card, clist, discarded,
[id1, id2], new_id1, new_id2, players)
# print
def display(w):
card, discarded, pair, players = w.card, w.discarded, w.pair, w.players
head, tail = pair[0], pair[1]
print(showDrawCard(tail, head, card) + \
showDiscardCards(head, discarded) + \
showCards(players), end ="")
return w
def is_game_ends(w):
'''ゲーム終了判定'''
return w.id1 == w.id2
# 補助関数
def insert(i, player, players):
head, tail = players[:i], players[i:]
return head + [player] + tail[1:]
def next_id(clist, i, players):
while True:
pos = clist[i % len(clist)]
player = players[pos]
if player != []:
return pos
i += 1
# 初期化
def initialize(n):
players = dealCards(shuffle_list(make_deck(), 7), n)
print(showCards(players), end = "")
lst = [discardPair(i) for i in players]
discarded = [i[0] for i in lst]
players = [i[1] for i in lst]
[print(showDiscardCards(i, j), end = "") for i, j in enumerate(discarded)]
print(showCards(players), end = "")
return World(False, list(range(n)), [], [], 0, 1, players)
if __name__ == '__main__':
'''REPL'''
w = initialize(int(argv[1]))
while True:
if is_game_ends(w):
print(showResult(w.id1))
exit()
try:
w = display(world_go(read(w), w))
except IndexError:
print("不正な入力です")
except ValueError:
print("不正な入力です")
finally:
w
IyEvdXNyL2Jpbi9lbnYgcHl0aG9uMwoKZnJvbSBmdW5jdG9vbHMgaW1wb3J0IHJlZHVjZQpmcm9tIGl0ZXJ0b29scyBpbXBvcnQgZ3JvdXBieSwgemlwX2xvbmdlc3QKZnJvbSByYW5kb20gaW1wb3J0IHJhbmRpbnQsIHNhbXBsZQpmcm9tIHN5cyBpbXBvcnQgYXJndiwgZXhpdAoKY2xhc3MgQ2FyZChvYmplY3QpOgogICAgJycn44OI44Op44Oz44OX44Gu44Kq44OW44K444Kn44Kv44OIJycnCiAgICBkZWYgX19pbml0X18oc2VsZiwgc3VpdCwgbnVtYmVyKToKICAgICAgICBzZWxmLnN1aXQgPSBzdWl0CiAgICAgICAgc2VsZi5udW1iZXIgPSBudW1iZXIKCiAgICBkZWYgX19yZXByX18oc2VsZik6CiAgICAgICAgcmV0dXJuIGYiW3tzZWxmLnN1aXR9OntzZWxmLm51bWJlcn1dIgoKZGVmIGRyYXdDYXJkKHBsYXllcjEsIHBsYXllcjIsIHBvcyk6CiAgICAnJyfjgqvjg7zjg4njgpLlvJXjgY8nJycKICAgIGNhcmQgPSBwbGF5ZXIyW3Bvc10KICAgIHJldHVybiBjYXJkLCBbY2FyZF0gKyBwbGF5ZXIxLCBwbGF5ZXIyWzpwb3NdICsgcGxheWVyMltwb3MgKyAxOl0KCmRlZiBkaXNjYXJkUGFpcihwbGF5ZXIpOgogICAgJycn44Kr44O844OJ44KS5o2o44Gm44KLJycnCiAgICBwID0gW2pbMF0gZm9yIGogaW4gW2xpc3QoaSkgZm9yIGtleSwgaSBpbiBcCiAgICAgICAgICAgICAgICAgICAgICAgIGdyb3VwYnkoc29ydGVkKHBsYXllciwga2V5ID0gbGFtYmRhIHg6IHgubnVtYmVyKSwgXAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGtleSA9IGxhbWJkYSB4OiB4Lm51bWJlcildIGlmIGxlbihqKSAhPSAyXQogICAgcmV0dXJuIGxpc3Qoc2V0KHBsYXllcikgLSBzZXQocCkpLCBwCgpkZWYgc2VsZWN0Q2FyZChudW0pOgogICAgJycnbnVt5p6a44Gu44Kr44O844OJ44GL44KJ5byV44GP44Kr44O844OJ44KS5rG644KB44KLJycnCiAgICByZXR1cm4gcmFuZGludCgwLCBudW0gLSAxKQoKZGVmIGRlYWxDYXJkcyhkZWNrLCBuKToKICAgICcnJ+OCq+ODvOODieOCkumFjeOCiycnJwogICAgaSA9IGxlbihkZWNrKSAvLyBuCiAgICBhY2MgPSBbZGVja1t4OnggKyBpXSBmb3IgeCBpbiByYW5nZSgwLCBsZW4oZGVjayksIGkpXQogICAgcmV0dXJuIFtpWzBdICsgW2lbMV1dIGlmIGlbMV0gIT0gTm9uZSBlbHNlIGlbMF0gZm9yIGkgaW4gXAogICAgICAgICAgICB6aXBfbG9uZ2VzdChhY2NbOi0xXSwgYWNjWy0xXSldCgpkZWYgc2h1ZmZsZV9saXN0KGxzdCwgbik6CiAgICAnJyfjgqvjg7zjg4njgrfjg6Pjg4Pjg5Xjg6vjgZnjgosnJycKICAgIHJldHVybiByZWR1Y2UobGFtYmRhIHgsIHk6IHNhbXBsZSh4LCBsZW4obHN0KSksIHJhbmdlKG4pLCBsc3QpCgojIOODoeODg+OCu+ODvOOCuAoKbWVzc2FnZSA9IHsiaW5wdXRTZWxlY3RDYXJkIiA6ICLkvZXmnprnm67jga7jgqvjg7zjg4njgpLlvJXjgY3jgb7jgZnjgYs/ICgwIOOAnCB7MH0pXG4iLAogICAgICAgICAgICJzaG93TnVtQ2FyZCIgOiAi44OX44Os44Kk44Ok44O8ezB944Gu44Kr44O844OJOiB7MX3mnppcbiIsCiAgICAgICAgICAgInNob3dDYXJkcyIgOiAi44OX44Os44Kk44Ok44O8ezB944Gu44Kr44O844OJOiB7MX1cbiIsCiAgICAgICAgICAgInNob3dEaXNjYXJkQ2FyZHMiIDogIuODl+ODrOOCpOODpOODvHswfeOBjOaNqOOBpuOBn+OCq+ODvOODiTogezF9XG4iLAogICAgICAgICAgICJzaG93RHJhd0NhcmQiIDogIuODl+ODrOOCpOODpOODvHswfSAtPiDjg5fjg6zjgqTjg6Tjg7x7MX0gOiB7Mn1cbiIsCiAgICAgICAgICAgInNob3dSZXN1bHQiIDogIuODl+ODrOOCpOODpOODvHswfeOBruiyoOOBkeOBp+OBmS4uLlxuIn0KCmRlZiBzaG93Q2FyZHMocGxheWVycyk6CiAgICAnJyfmiYvmjIHjgaHjga7jgqvjg7zjg4njgpLooajnpLrjgZnjgovmloflrZfliJcnJycKICAgIHJldHVybiAiIi5qb2luKFttZXNzYWdlWyJzaG93Q2FyZHMiXS5mb3JtYXQoaSwgZ2V0Q2FyZHNTdHIoaikpXAogICAgICAgICAgICAgICAgICAgIGlmIGkgPT0gMCBcCiAgICAgICAgICAgICAgICAgICAgZWxzZSBtZXNzYWdlWyJzaG93TnVtQ2FyZCJdLmZvcm1hdChpLCBsZW4oaikpXAogICAgICAgICAgICAgICAgICAgICAgICAgZm9yIGksIGogaW4gZW51bWVyYXRlKHBsYXllcnMpXSkKCmRlZiBzaG93RGlzY2FyZENhcmRzKGlkLCBjYXJkcyk6CiAgICAnJyfmjajjgabjgonjgozjgZ/jgqvjg7zjg4njgpLooajnpLrjgZnjgovmloflrZfliJcnJycKICAgIGlmIGNhcmRzID09IFtdOgogICAgICAgIHJldHVybiAiIgogICAgZWxzZToKICAgICAgICByZXR1cm4gbWVzc2FnZVsic2hvd0Rpc2NhcmRDYXJkcyJdLmZvcm1hdChpZCwgZ2V0Q2FyZHNTdHIoY2FyZHMpKQoKZGVmIHNob3dEcmF3Q2FyZChpZDEsIGlkMiwgY2FyZCk6CiAgICAnJyfjgqvjg7zjg4njga7kuqTmj5vnirbms4HjgpLooajnpLrjgZnjgovmloflrZfliJcnJycKICAgIHJldHVybiBtZXNzYWdlWyJzaG93RHJhd0NhcmQiXS5mb3JtYXQoaWQxLCBpZDIsIGdldENhcmRTdHIoY2FyZCkpCgpkZWYgc2hvd1Jlc3VsdChpZCk6CiAgICAnJyfjgrLjg7zjg6Djga7ntZDmnpzjgpLooajnpLrjgZnjgovmloflrZfliJcnJycKICAgIHJldHVybiBtZXNzYWdlWyJzaG93UmVzdWx0Il0uZm9ybWF0KGlkKQoKZGVmIGdldENhcmRzU3RyKGNhcmRzKToKICAgICcnJ0NhcmTjgqrjg5bjgrjjgqfjgq/jg4jjga7jg6rjgrnjg4jjgpLmloflrZfliJfjgavlpInmj5snJycKICAgIHJldHVybiAiIi5qb2luKFtnZXRDYXJkU3RyKGkpIGZvciBpIGluIGNhcmRzXSkKCmRlZiBnZXRDYXJkU3RyKGNhcmQpOgogICAgJycnQ2FyZOOCquODluOCuOOCp+OCr+ODiOOCkuaWh+Wtl+WIl+OBq+WkieaPmycnJwogICAgcmV0dXJuICJ7MH0iLmZvcm1hdChjYXJkKQoKZGVmIG1ha2VfZGVjaygpOgogICAgJycn44OI44Op44Oz44OX44Gu44Kr44O844OJ44KS5L2c5oiQ44GZ44KLJycnCiAgICByZXR1cm4gW0NhcmQoIkoiLCAiMCIpXSArIFtDYXJkKGksICJBIiBpZiBqID09IDEgZWxzZSAiSiIgaWYgaiA9PSAxMSBcCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGVsc2UgIlEiIGlmIGogPT0gMTIgZWxzZSAiSyIgaWYgaiA9PSAxMyBcCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZWxzZSBzdHIoaikpIGZvciBpIGluIFwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICgiRCIsICJIIiwgIlMiLCAiQyIpIGZvciBqIGluIFwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHJhbmdlKDEsIDE0KV0KCmNsYXNzIFdvcmxkKG9iamVjdCk6CiAgICAnJyfnkrDlooMnJycKICAgIGRlZiBfX2luaXRfXyhzZWxmLCBjYXJkLCBjbGlzdCwgZGlzY2FyZGVkLCBwYWlyLCBpZDEsIGlkMiwgcGxheWVycyk6CiAgICAgICAgc2VsZi5jYXJkID0gY2FyZAogICAgICAgIHNlbGYuY2xpc3QgPSBjbGlzdAogICAgICAgIHNlbGYuZGlzY2FyZGVkID0gZGlzY2FyZGVkCiAgICAgICAgc2VsZi5wYWlyID0gcGFpcgogICAgICAgIHNlbGYuaWQxID0gaWQxCiAgICAgICAgc2VsZi5pZDIgPSBpZDIKICAgICAgICBzZWxmLnBsYXllcnMgPSBwbGF5ZXJzCgojIHJlYWQKCmRlZiByZWFkKHcpOgogICAgaWQxLCBpZDIsIHBsYXllcnMgPSB3LmlkMSwgdy5pZDIsIHcucGxheWVycwogICAgayA9IGxlbihwbGF5ZXJzW2lkMl0pCiAgICBpZiBpZDEgPT0gMDoKICAgICAgICByZXR1cm4gaW50KGlucHV0KG1lc3NhZ2VbImlucHV0U2VsZWN0Q2FyZCJdLmZvcm1hdChrIC0gMSkpKQogICAgZWxzZToKICAgICAgICByZXR1cm4gc2VsZWN0Q2FyZChrKQoKIyBldmFsCgpkZWYgd29ybGRfZ28oZXhwLCB3KToKICAgIGNsaXN0LCBpZDEsIGlkMiwgcGxheWVycyA9IHcuY2xpc3QsIHcuaWQxLCB3LmlkMiwgdy5wbGF5ZXJzCiAgICBwbGF5ZXIxLCBwbGF5ZXIyID0gcGxheWVyc1tpZDFdLCBwbGF5ZXJzW2lkMl0KICAgIGNhcmQsIHBsYXllcjEsIHBsYXllcjIgPSBkcmF3Q2FyZChwbGF5ZXIxLCBwbGF5ZXIyLCBleHApCiAgICBkaXNjYXJkZWQsIHBsYXllcjEgPSBkaXNjYXJkUGFpcihwbGF5ZXIxKQogICAgcGxheWVycyA9IGluc2VydChpZDEsIHBsYXllcjEsIGluc2VydChpZDIsIHBsYXllcjIsIHBsYXllcnMpKQogICAgbmV3X2lkMSA9IG5leHRfaWQoY2xpc3QsIGlkMSArIDEsIHBsYXllcnMpCiAgICBuZXdfaWQyID0gbmV4dF9pZChjbGlzdCwgbmV3X2lkMSArIDEsIHBsYXllcnMpCiAgICByZXR1cm4gV29ybGQoY2FyZCwgY2xpc3QsIGRpc2NhcmRlZCwKICAgICAgICAgICAgICAgICBbaWQxLCBpZDJdLCBuZXdfaWQxLCBuZXdfaWQyLCBwbGF5ZXJzKQoKIyBwcmludAoKZGVmIGRpc3BsYXkodyk6CiAgICBjYXJkLCBkaXNjYXJkZWQsIHBhaXIsIHBsYXllcnMgPSB3LmNhcmQsIHcuZGlzY2FyZGVkLCB3LnBhaXIsIHcucGxheWVycwogICAgaGVhZCwgdGFpbCA9IHBhaXJbMF0sIHBhaXJbMV0KICAgIHByaW50KHNob3dEcmF3Q2FyZCh0YWlsLCBoZWFkLCBjYXJkKSArIFwKICAgICAgICAgIHNob3dEaXNjYXJkQ2FyZHMoaGVhZCwgZGlzY2FyZGVkKSArIFwKICAgICAgICAgIHNob3dDYXJkcyhwbGF5ZXJzKSwgZW5kID0iIikKICAgIHJldHVybiB3CgpkZWYgaXNfZ2FtZV9lbmRzKHcpOgogICAgJycn44Ky44O844Og57WC5LqG5Yik5a6aJycnCiAgICByZXR1cm4gdy5pZDEgPT0gdy5pZDIKCiMg6KOc5Yqp6Zai5pWwCgpkZWYgaW5zZXJ0KGksIHBsYXllciwgcGxheWVycyk6CiAgICBoZWFkLCB0YWlsID0gcGxheWVyc1s6aV0sIHBsYXllcnNbaTpdCiAgICByZXR1cm4gaGVhZCArIFtwbGF5ZXJdICsgdGFpbFsxOl0KCmRlZiBuZXh0X2lkKGNsaXN0LCBpLCBwbGF5ZXJzKToKICAgIHdoaWxlIFRydWU6CiAgICAgICAgcG9zID0gY2xpc3RbaSAlIGxlbihjbGlzdCldCiAgICAgICAgcGxheWVyID0gcGxheWVyc1twb3NdCiAgICAgICAgaWYgcGxheWVyICE9IFtdOgogICAgICAgICAgICByZXR1cm4gcG9zCiAgICAgICAgaSArPSAxCgojIOWIneacn+WMlgoKZGVmIGluaXRpYWxpemUobik6CiAgICBwbGF5ZXJzID0gZGVhbENhcmRzKHNodWZmbGVfbGlzdChtYWtlX2RlY2soKSwgNyksIG4pCiAgICBwcmludChzaG93Q2FyZHMocGxheWVycyksIGVuZCA9ICIiKQogICAgbHN0ID0gW2Rpc2NhcmRQYWlyKGkpIGZvciBpIGluIHBsYXllcnNdCiAgICBkaXNjYXJkZWQgPSBbaVswXSBmb3IgaSBpbiBsc3RdCiAgICBwbGF5ZXJzID0gW2lbMV0gZm9yIGkgaW4gbHN0XQogICAgW3ByaW50KHNob3dEaXNjYXJkQ2FyZHMoaSwgaiksIGVuZCA9ICIiKSBmb3IgaSwgaiBpbiBlbnVtZXJhdGUoZGlzY2FyZGVkKV0KICAgIHByaW50KHNob3dDYXJkcyhwbGF5ZXJzKSwgZW5kID0gIiIpCiAgICByZXR1cm4gV29ybGQoRmFsc2UsIGxpc3QocmFuZ2UobikpLCBbXSwgW10sIDAsIDEsIHBsYXllcnMpCgppZiBfX25hbWVfXyA9PSAnX19tYWluX18nOgogICAgJycnUkVQTCcnJwogICAgdyA9IGluaXRpYWxpemUoaW50KGFyZ3ZbMV0pKQogICAgd2hpbGUgVHJ1ZToKICAgICAgICBpZiBpc19nYW1lX2VuZHModyk6CiAgICAgICAgICAgIHByaW50KHNob3dSZXN1bHQody5pZDEpKQogICAgICAgICAgICBleGl0KCkKICAgICAgICB0cnk6CiAgICAgICAgICAgIHcgPSBkaXNwbGF5KHdvcmxkX2dvKHJlYWQodyksIHcpKQogICAgICAgIGV4Y2VwdCBJbmRleEVycm9yOgogICAgICAgICAgICBwcmludCgi5LiN5q2j44Gq5YWl5Yqb44Gn44GZIikKICAgICAgICBleGNlcHQgVmFsdWVFcnJvcjoKICAgICAgICAgICAgcHJpbnQoIuS4jeato+OBquWFpeWKm+OBp+OBmSIpCiAgICAgICAgZmluYWxseToKICAgICAgICAgICAgdwo=