{ "cells": [ { "cell_type": "code", "execution_count": 1, "metadata": { "collapsed": true }, "outputs": [], "source": [ "import numpy as np\n", "import random" ] }, { "cell_type": "code", "execution_count": 2, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "[(9, 0), (10, 0), (11, 0), (12, 0), (13, 0), (14, 0), (9, 1), (10, 1), (11, 1), (12, 1), (13, 1), (14, 1), (9, 2), (10, 2), (11, 2), (12, 2), (13, 2), (14, 2), (9, 3), (10, 3), (11, 3), (12, 3), (13, 3), (14, 3)]\n" ] } ], "source": [ "### Generate cards from 9 to 14 (ace) for all colors/symbols (0, 1, 2, 3)\n", "def getDeck():\n", " return [(number, color) for color in range(4) for number in range(9, 15)]\n", " \n", "print(getDeck())" ] }, { "cell_type": "code", "execution_count": 5, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "[(13, 1), (13, 2), (9, 1), (11, 2), (10, 1), (13, 0), (12, 3), (10, 2)]\n", "[(12, 2), (9, 0), (12, 0), (9, 2), (11, 3), (14, 1), (14, 2), (10, 3)]\n" ] } ], "source": [ "### Shuffle the cards randomly. Each player gets 9 cards\n", "### (so one player cannot be certain which cards the other player has)\n", "\n", "def getShuffled(deck):\n", " D = set(deck)\n", " A = set(random.sample(deck, 8))\n", " B = set(random.sample(list(D - A), 8))\n", " C = D - A - B\n", " if len(A.intersection(B)) > 0: print(\"Shuffle error 1\")\n", " if len(A.intersection(B)) > 0: print(\"Shuffle error 2\")\n", " if len(A.intersection(C)) > 0: print(\"Shuffle error 3\") \n", " DS = A | B | C\n", " if not DS == D: print(\"Shuffle error 4\") \n", " return list(A), list(B), list(C)\n", "\n", "p1, p2, notUsed, = getShuffled(getDeck())\n", "print(p1)\n", "print(p2)\n" ] }, { "cell_type": "code", "execution_count": 6, "metadata": { "collapsed": true }, "outputs": [], "source": [ "class Player():\n", " def __init__(self, name):\n", " \n", " self.name = name\n", " self.cards = None\n", " \n", " ### -------------------------------------------------------------\n", " \n", " ### TO BE IMPLEMENTED - player's strategy \n", " ### input: declared card, i.e., the card which is supposed\n", " ### to be the top card of the pile: If None - you can put any card you want because\n", " ### (a) it is the first turn (pile is empty) or (b) some cards were drawn in the previous turn)\n", " ### output: - player's true decision, player's declaration (if not equal - (s)he cheats)\n", " \n", " def putCard(self, declared_card):\n", " ### DO NOT REMOVE TRUE CARD cards.remove!!!\n", " ### return an object (not id): self.cards[id], not id\n", " ### for instance: return self.cards[0], self.cards[0] \n", " ### IMPORTANT: If you want to draw cards instead of put, return \"draw\"\n", " ### for instance: return \"draw\" \n", " return self.cards[0], self.cards[0] \n", " \n", " ### TO BE IMPLEMENTED - Decide whether to check or not opponent's move (return True or False)\n", " def checkCard(self, opponent_declaration):\n", " pass\n", " \n", " ### Notification sent at the end of a round\n", " ### One may implement this method, capture data, and use it to get extra info\n", " ### -- checked = TRUE -> someone checked. If FALSE, the remaining inputs do not play any role\n", " ### -- iChecked = TRUE -> I decided to check my opponent (so it was my turn); \n", " ### FALSE -> my opponent checked and it was his turn\n", " ### -- iDrewCards = TRUE -> I drew cards (so I checked but was wrong or my opponent checked and was right); \n", " ### FALSE -> otherwise\n", " ### -- revealedCard - some card (X, Y). Only if I checked.\n", " ### -- noTakenCards - number of taken cards\n", " def getCheckFeedback(self, checked, iChecked, iDrewCards, revealedCard, noTakenCards, log=True):\n", " if log: print(\"Feedback = \" + self.name + \" : checked this turn = \" + str(checked) +\n", " \"; I checked = \" + str(iChecked) + \"; I drew cards = \" + \n", " str(iDrewCards) + \"; revealed card = \" + \n", " str(revealedCard) + \"; number of taken cards = \" + str(noTakenCards))\n", " \n", " \n", " ### -------------------------------------------------------------\n", " \n", " ### Init player's hand\n", " def startGame(self, cards):\n", " self.cards = cards\n", " \n", " ### Add some cards to player's hand (if (s)he checked opponent's move, but (s)he was wrong)\n", " def takeCards(self, cards_to_take):\n", " self.cards = self.cards + cards_to_take" ] }, { "cell_type": "code", "execution_count": 7, "metadata": { "collapsed": true }, "outputs": [], "source": [ "# Some examplary random player\n", "\n", "class RandomPlayer(Player):\n", " \n", " ### player's random strategy\n", " def putCard(self, declared_card):\n", " \n", " ### check if must draw\n", " if len(self.cards) == 1 and declared_card is not None and self.cards[0][0] < declared_card[0]:\n", " return \"draw\"\n", " \n", " ### player randomly decides which card put on the table\n", " card = random.choice(self.cards)\n", " declaration = card\n", " \n", " ### player randomly decides whether to cheat or not\n", " cheat = np.random.choice([True, False])\n", " \n", " ### if (s)he decides to cheat, (s)he randomly declares the card.\n", " if cheat:\n", " declaration = random.choice(self.cards) \n", " \n", " ### Yet, declared card should be no worse than a card on the top of the pile . \n", " if declared_card is not None and declaration[0] < declared_card[0]:\n", " declaration = (min(declared_card[0]+1,14), declaration[1])\n", "\n", " ### return the decision (true card) and declaration (player's declaration)\n", " return card, declaration\n", " \n", " ### randomly decides whether to check or not\n", " def checkCard(self, opponent_declaration):\n", " return np.random.choice([True, False])\n", " " ] }, { "cell_type": "code", "execution_count": 8, "metadata": { "collapsed": true }, "outputs": [], "source": [ "class Game():\n", " def __init__(self, players, log = True):\n", " self.players = players\n", " self.deck = getDeck()\n", " self.player_cards = getShuffled(self.deck)\n", " self.game_deck = self.player_cards[0] + self.player_cards[1]\n", " \n", " self.cheats = [0, 0]\n", " self.moves = [0, 0]\n", " self.checks = [0, 0]\n", " self.draw_decisions = [0, 0]\n", " \n", " for i, cards in zip([0, 1], self.player_cards):\n", " self.players[i].startGame(cards.copy())\n", " if log:\n", " print(\"Player (\" + str(i + 1) + \"): \" + self.players[i].name + \" received:\")\n", " print(self.players[i].cards)\n", " \n", " ### Which card is on top\n", " self.true_card = None\n", " ### Which card was declared by active player\n", " self.declared_card = None\n", " \n", " ### Init pile: [-1] = top card\n", " self.pile = []\n", " \n", " ### Which player moves\n", " self.player_move = np.random.randint(2)\n", " \n", " def takeTurn(self, log = True):\n", " \n", " self.player_move = 1 - self.player_move\n", " \n", " if log: \n", " print(\"\")\n", " print(\"\")\n", " print(\"==== CURRENT STATE ================================\")\n", " print(\"==== \" + self.players[self.player_move].name + \" MOVES ====\")\n", " print(\"Player (0): \" + self.players[0].name + \" hand:\")\n", " print(self.players[0].cards)\n", " print(\"Player (1): \" + self.players[1].name + \" hand:\")\n", " print(self.players[1].cards)\n", " print(\"Pile: \")\n", " print(self.pile)\n", " print(\"Declared top card:\")\n", " print(self.declared_card)\n", " print(\"\")\n", " \n", " activePlayer = self.players[self.player_move]\n", " opponent = self.players[1 - self.player_move]\n", " self.moves[self.player_move] += 1\n", " \n", " self.previous_declaration = self.declared_card\n", " decision = activePlayer.putCard(self.declared_card)\n", " \n", " if decision == \"draw\":\n", " \n", " if log: print(\"[+] \" + activePlayer.name + \" decides to draw cards\")\n", " \n", " self.draw_decisions[self.player_move] += 1\n", " \n", " toTake = self.pile[max([-3, -len(self.pile)]):]\n", " for c in toTake: self.pile.remove(c)\n", " activePlayer.takeCards(toTake)\n", " for c in toTake: self.player_cards[self.player_move].append(c)\n", " \n", " self.declared_card = None\n", " self.true_card = None\n", " \n", " activePlayer.getCheckFeedback(False, False, False, None, None, log)\n", " opponent.getCheckFeedback(False, False, False, None, None, log)\n", "\n", " else:\n", " self.true_card, self.declared_card = decision\n", " if self.true_card != self.declared_card: self.cheats[self.player_move] += 1\n", " \n", " if log: print(\"[+] \" + activePlayer.name + \" puts \" + str(self.true_card) +\n", " \" and declares \" + str(self.declared_card))\n", " \n", " if not self.debugMove(): return False, self.player_move\n", " \n", " activePlayer.cards.remove(self.true_card)\n", " self.player_cards[self.player_move].remove(self.true_card) \n", " self.pile.append(self.true_card)\n", " \n", " if opponent.checkCard(self.declared_card):\n", " \n", " self.checks[1 - self.player_move] += 1\n", " \n", " if log: print(\"[!] \" + opponent.name + \": \" + \"I want to check\")\n", " toTake = self.pile[max([-3, -len(self.pile)]):]\n", " for c in toTake: self.pile.remove(c)\n", "\n", " if not self.true_card == self.declared_card:\n", " if log: print(\"\\tYou are right!\")\n", " activePlayer.takeCards(toTake)\n", " \n", " activePlayer.getCheckFeedback(True, False, True, None, len(toTake), log)\n", " opponent.getCheckFeedback(True, True, False, tuple(toTake[-1]), len(toTake), log)\n", " \n", " for c in toTake: self.player_cards[self.player_move].append(c)\n", " else:\n", " if log: print(\"\\tYou are wrong!\")\n", " opponent.takeCards(toTake) \n", " \n", " activePlayer.getCheckFeedback(True, False, False, None, len(toTake), log)\n", " opponent.getCheckFeedback(True, True, True, tuple(toTake[-1]), len(toTake), log)\n", " \n", " for c in toTake: self.player_cards[1 - self.player_move].append(c)\n", " \n", " if log:\n", " print(\"Cards taken: \")\n", " print(toTake)\n", "\n", " self.declared_card = None\n", " self.true_card = None\n", " else:\n", " activePlayer.getCheckFeedback(False, False, False, None, None, log)\n", " opponent.getCheckFeedback(False, False, False, None, None, log)\n", "\n", " \n", " if not self.debugGeneral(): return False, self.player_move\n", " return True, self.player_move\n", " \n", " def isFinished(self, log = True):\n", " if len(self.players[self.player_move].cards) == 0:\n", " if log: print(self.players[self.player_move].name + \" wins!\")\n", " return True\n", " return False\n", "\n", " def debugMove(self):\n", " if (self.previous_declaration is not None) and (self.true_card[0] < self.previous_declaration[0]) and \\\n", " len(self.players[self.player_move].cards) == 1:\n", " print(\"[ERROR] Last played card should be valid (it is revealed, you cannot cheat)!\")\n", " return False\n", " if np.array(self.true_card).size != 2: \n", " print(\"[ERROR] You put too many cards!\")\n", " return False\n", " if self.true_card not in self.player_cards[self.player_move]:\n", " print(\"[ERROR] You do not have this card!\")\n", " return False\n", " if self.true_card not in self.deck:\n", " print(\"[ERROR] There is no such card!\")\n", " return False\n", " if (self.previous_declaration is not None) and len(self.pile) == 0:\n", " print(\"[ERROR] Inconsistency\")\n", " return False\n", " if (self.previous_declaration is not None) and (self.declared_card[0] < self.previous_declaration[0]):\n", " print(len(self.pile))\n", " print(self.previous_declaration)\n", " print(self.declared_card)\n", " print(self.pile[-1])\n", " print(\"[ERROR] Improper move!\")\n", " return False\n", " return True\n", " \n", " def debugGeneral(self):\n", " A = set(self.players[0].cards)\n", " B = set(self.players[1].cards)\n", " C = set(self.player_cards[0])\n", " D = set(self.player_cards[1])\n", " P = set(self.pile)\n", " E = set(self.game_deck)\n", " \n", " if not A == C: \n", " print(\"Error 001\")\n", " return False\n", " if not B == D:\n", " print(\"Error 002\")\n", " return False\n", " if not A | B | P == E:\n", " print(\"Error 003\")\n", " print(A)\n", " print(B)\n", " print(P)\n", " print(E)\n", " return False\n", " return True" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Analyze few moves..." ] }, { "cell_type": "code", "execution_count": 9, "metadata": { "scrolled": false }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Player (1): Player A received:\n", "[(9, 0), (9, 1), (9, 3), (14, 1), (14, 3), (14, 2), (10, 3), (12, 3)]\n", "Player (2): Player B received:\n", "[(12, 1), (13, 2), (12, 0), (9, 2), (11, 0), (11, 1), (13, 0), (10, 2)]\n", "\n", "\n", "==== CURRENT STATE ================================\n", "==== Player A MOVES ====\n", "Player (0): Player A hand:\n", "[(9, 0), (9, 1), (9, 3), (14, 1), (14, 3), (14, 2), (10, 3), (12, 3)]\n", "Player (1): Player B hand:\n", "[(12, 1), (13, 2), (12, 0), (9, 2), (11, 0), (11, 1), (13, 0), (10, 2)]\n", "Pile: \n", "[]\n", "Declared top card:\n", "None\n", "\n", "[+] Player A puts (12, 3) and declares (9, 3)\n", "[!] Player B: I want to check\n", "\tYou are right!\n", "Feedback = Player A : checked this turn = True; I checked = False; I drew cards = True; revealed card = None; number of taken cards = 1\n", "Feedback = Player B : checked this turn = True; I checked = True; I drew cards = False; revealed card = (12, 3); number of taken cards = 1\n", "Cards taken: \n", "[(12, 3)]\n", "\n", "\n", "==== CURRENT STATE ================================\n", "==== Player B MOVES ====\n", "Player (0): Player A hand:\n", "[(9, 0), (9, 1), (9, 3), (14, 1), (14, 3), (14, 2), (10, 3), (12, 3)]\n", "Player (1): Player B hand:\n", "[(12, 1), (13, 2), (12, 0), (9, 2), (11, 0), (11, 1), (13, 0), (10, 2)]\n", "Pile: \n", "[]\n", "Declared top card:\n", "None\n", "\n", "[+] Player B puts (9, 2) and declares (11, 0)\n", "[!] Player A: I want to check\n", "\tYou are right!\n", "Feedback = Player B : checked this turn = True; I checked = False; I drew cards = True; revealed card = None; number of taken cards = 1\n", "Feedback = Player A : checked this turn = True; I checked = True; I drew cards = False; revealed card = (9, 2); number of taken cards = 1\n", "Cards taken: \n", "[(9, 2)]\n", "\n", "\n", "==== CURRENT STATE ================================\n", "==== Player A MOVES ====\n", "Player (0): Player A hand:\n", "[(9, 0), (9, 1), (9, 3), (14, 1), (14, 3), (14, 2), (10, 3), (12, 3)]\n", "Player (1): Player B hand:\n", "[(12, 1), (13, 2), (12, 0), (11, 0), (11, 1), (13, 0), (10, 2), (9, 2)]\n", "Pile: \n", "[]\n", "Declared top card:\n", "None\n", "\n", "[+] Player A puts (9, 3) and declares (9, 3)\n", "[!] Player B: I want to check\n", "\tYou are wrong!\n", "Feedback = Player A : checked this turn = True; I checked = False; I drew cards = False; revealed card = None; number of taken cards = 1\n", "Feedback = Player B : checked this turn = True; I checked = True; I drew cards = True; revealed card = (9, 3); number of taken cards = 1\n", "Cards taken: \n", "[(9, 3)]\n", "\n", "\n", "==== CURRENT STATE ================================\n", "==== Player B MOVES ====\n", "Player (0): Player A hand:\n", "[(9, 0), (9, 1), (14, 1), (14, 3), (14, 2), (10, 3), (12, 3)]\n", "Player (1): Player B hand:\n", "[(12, 1), (13, 2), (12, 0), (11, 0), (11, 1), (13, 0), (10, 2), (9, 2), (9, 3)]\n", "Pile: \n", "[]\n", "Declared top card:\n", "None\n", "\n", "[+] Player B puts (12, 1) and declares (12, 1)\n", "[!] Player A: I want to check\n", "\tYou are wrong!\n", "Feedback = Player B : checked this turn = True; I checked = False; I drew cards = False; revealed card = None; number of taken cards = 1\n", "Feedback = Player A : checked this turn = True; I checked = True; I drew cards = True; revealed card = (12, 1); number of taken cards = 1\n", "Cards taken: \n", "[(12, 1)]\n", "\n", "\n", "==== CURRENT STATE ================================\n", "==== Player A MOVES ====\n", "Player (0): Player A hand:\n", "[(9, 0), (9, 1), (14, 1), (14, 3), (14, 2), (10, 3), (12, 3), (12, 1)]\n", "Player (1): Player B hand:\n", "[(13, 2), (12, 0), (11, 0), (11, 1), (13, 0), (10, 2), (9, 2), (9, 3)]\n", "Pile: \n", "[]\n", "Declared top card:\n", "None\n", "\n", "[+] Player A puts (14, 3) and declares (9, 1)\n", "[!] Player B: I want to check\n", "\tYou are right!\n", "Feedback = Player A : checked this turn = True; I checked = False; I drew cards = True; revealed card = None; number of taken cards = 1\n", "Feedback = Player B : checked this turn = True; I checked = True; I drew cards = False; revealed card = (14, 3); number of taken cards = 1\n", "Cards taken: \n", "[(14, 3)]\n", "\n", "\n", "==== CURRENT STATE ================================\n", "==== Player B MOVES ====\n", "Player (0): Player A hand:\n", "[(9, 0), (9, 1), (14, 1), (14, 2), (10, 3), (12, 3), (12, 1), (14, 3)]\n", "Player (1): Player B hand:\n", "[(13, 2), (12, 0), (11, 0), (11, 1), (13, 0), (10, 2), (9, 2), (9, 3)]\n", "Pile: \n", "[]\n", "Declared top card:\n", "None\n", "\n", "[+] Player B puts (11, 1) and declares (9, 3)\n", "Feedback = Player B : checked this turn = False; I checked = False; I drew cards = False; revealed card = None; number of taken cards = None\n", "Feedback = Player A : checked this turn = False; I checked = False; I drew cards = False; revealed card = None; number of taken cards = None\n" ] } ], "source": [ "player1 = RandomPlayer(\"Player A\")\n", "player2 = RandomPlayer(\"Player B\")\n", "game = Game([player1, player2])\n", "\n", "for i in range(6):\n", " game.takeTurn()" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "collapsed": true }, "outputs": [], "source": [ "### Some debug players\n", "class DrawPlayer(Player):\n", " \n", " ### player's random strategy\n", " def putCard(self, declared_card):\n", " return \"draw\"\n", " \n", " ### randomly decides whether to check or not\n", " def checkCard(self, opponent_declaration):\n", " return np.random.choice([False, False])\n", " \n", "class SimplePlayer(Player):\n", " \n", " ### player's simple strategy\n", " def putCard(self, declared_card):\n", " \n", " ### check if must draw\n", " if len(self.cards) == 1 and declared_card is not None and self.cards[0][0] < declared_card[0]:\n", " return \"draw\"\n", " \n", " card = min(self.cards, key=lambda x: x[0])\n", " declaration = (card[0], card[1])\n", " if declared_card is not None:\n", " min_val = declared_card[0]\n", " if card[0] < min_val: declaration = (min(min_val + 1, 14), declaration[1])\n", " return card, declaration\n", " \n", " def checkCard(self, opponent_declaration):\n", " if opponent_declaration in self.cards: return True\n", " return np.random.choice([True, False], p=[0.3, 0.7])" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "### Perform a full game 100 times\n", "stats_wins = [0, 0]\n", "stats_moves = [0, 0]\n", "stats_cheats = [0, 0]\n", "stats_errors = [0, 0]\n", "stats_cards = [0, 0]\n", "stats_checks = [0, 0]\n", "stats_draw_decisions = [0, 0]\n", "stats_pile_size = 0\n", "\n", "repeats = 100\n", "errors = 0\n", "\n", "for t in range(100):\n", " player1 = SimplePlayer(\"Player A\")\n", " player2 = RandomPlayer(\"Player B\")\n", " game = Game([player1, player2], log = False)\n", " \n", " error = False\n", " while True:\n", " valid, player = game.takeTurn(log = False)\n", " if not valid:\n", " error = True\n", " stats_errors[player] += 1\n", " errors += 1\n", " break\n", " if game.isFinished(log = False):\n", " stats_wins[player] += 1\n", " break\n", " \n", " stats_pile_size += len(game.pile)\n", " if not error:\n", " for j in range(2):\n", " stats_moves[j] += game.moves[j]\n", " stats_cheats[j] += game.cheats[j]\n", " stats_checks[j] += game.checks[j]\n", " stats_draw_decisions[j] += game.draw_decisions[j]\n", " stats_cards[j] += len(game.player_cards[j])\n", "\n", "stats_pile_size /= (repeats - errors) \n", "for j in range(2):\n", " stats_moves[j] /= (repeats - errors)\n", " stats_cheats[j] /= (repeats - errors)\n", " stats_checks[j] /= (repeats - errors)\n", " stats_draw_decisions[j] /= (repeats - errors)\n", " stats_cards[j] /= (repeats - errors)\n", "\n", " \n", "print(\"Wins:\")\n", "print(stats_wins)\n", "print(\"Moves:\")\n", "print(stats_moves)\n", "print(\"Cards:\")\n", "print(stats_cards)\n", "print(\"Pile size:\")\n", "print(stats_pile_size)\n", "print(\"Checks:\")\n", "print(stats_checks)\n", "print(\"Draw decisions:\")\n", "print(stats_draw_decisions)\n", "print(\"Cheats:\")\n", "print(stats_cheats)\n", "print(\"Errors:\")\n", "print(stats_errors)\n", "print(\"Total errors:\")\n", "print(errors)" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "collapsed": true }, "outputs": [], "source": [ "### Implement player's strategy. You can compare it with random player \n", "### (or some strategy implemented by one of you colleagues)\n", "### Time limit per decision 0.01s !!!\n", "\n", "class YourPlayer(Player):\n", " \n", " ### player's random strategy\n", " def putCard(self, declared_card):\n", " return None, None\n", " \n", " ### randomly decides whether to check or not\n", " def checkCard(self, opponent_declaration):\n", " return False" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "collapsed": true }, "outputs": [], "source": [] }, { "cell_type": "code", "execution_count": null, "metadata": { "collapsed": true }, "outputs": [], "source": [] } ], "metadata": { "kernelspec": { "display_name": "Python 3", "language": "python", "name": "python3" }, "language_info": { "codemirror_mode": { "name": "ipython", "version": 3 }, "file_extension": ".py", "mimetype": "text/x-python", "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", "version": "3.5.0" }, "widgets": { "state": {}, "version": "1.1.2" } }, "nbformat": 4, "nbformat_minor": 2 }