Massive update

This commit is contained in:
Daniel Ledda
2020-06-10 18:58:30 +02:00
parent b0c37aae52
commit ff73721678
35 changed files with 456 additions and 171 deletions

2
.idea/misc.xml generated
View File

@@ -3,5 +3,5 @@
<component name="JavaScriptSettings">
<option name="languageLevel" value="ES6" />
</component>
<component name="ProjectRootManager" version="2" project-jdk-name="Python 3.6" project-jdk-type="Python SDK" />
<component name="ProjectRootManager" version="2" project-jdk-name="Python 3.8 (schafkopf)" project-jdk-type="Python SDK" />
</project>

2
.idea/schafkopf.iml generated
View File

@@ -4,7 +4,7 @@
<content url="file://$MODULE_DIR$">
<sourceFolder url="file://$MODULE_DIR$/src" isTestSource="false" />
</content>
<orderEntry type="inheritedJdk" />
<orderEntry type="jdk" jdkName="Python 3.8 (schafkopf)" jdkType="Python SDK" />
<orderEntry type="sourceFolder" forTests="false" />
</component>
</module>

View File

@@ -1,41 +1,39 @@
import enum
from typing import *
from collections import namedtuple
from Errors import SchafkopfError
class Card:
class Suit(enum.Enum):
Eichel = 0
Gras = 1
Herz = 2
Schellen = 3
class OpError(SchafkopfError, TypeError):
def __init__(self):
self.message = "An '{}' object may only be operated on with others of the same type.".format(
Card.__class__.__name__)
SUITS_STR: Dict[Suit, str] = {
Suit.Eichel: "",
Suit.Gras: "",
Suit.Herz: "",
Suit.Schellen: "",
}
class Suit(enum.Enum):
Eichel = 3
Gras = 2
Herz = 1
Schellen = 0
class Rank(enum.Enum):
Ober = 0
Unter = 1
Ass = 2
Koenig = 3
Zehn = 4
Neun = 5
Acht = 6
Sieben = 7
Ass = 7
Koenig = 6
Ober = 5
Unter = 4
Zehn = 3
Neun = 2
Acht = 1
Sieben = 0
RANKS_STR: Dict[Rank, str] = {
Rank.Ober: "O",
Rank.Unter: "U",
Rank.Ass: "A",
Rank.Koenig: "K",
Rank.Zehn: "X",
Rank.Neun: "9",
Rank.Acht: "8",
Rank.Sieben: "7",
RANK_SCORE: Dict[Rank, int] = {
Rank.Ass: 11,
Rank.Koenig: 4,
Rank.Ober: 3,
Rank.Unter: 2,
Rank.Zehn: 10,
Rank.Neun: 0,
Rank.Acht: 0,
Rank.Sieben: 0,
}
def __init__(self, suit: Suit, rank: Rank):
@@ -43,11 +41,37 @@ class Card:
self.rank: Card.Rank = rank
def __str__(self):
return "\n".join(self.glyph())
return self.suit.name + " " + self.rank.name
def __repr__(self):
return "Card: <" + self.suit.name + ", " + self.rank.name + ">"
def __gt__(self, other):
if type(other) != Card:
raise Card.OpError()
else:
return self.suit.value > other.suit.value or self.rank.value > other.rank.value
def __lt__(self, other):
if type(other) != Card:
raise Card.OpError()
else:
return self.suit.value < other.suit.value or self.rank.value < other.rank.value
def __add__(self, other):
if type(other) != Card:
raise Card.OpError()
else:
return Card.RANK_SCORE[self.rank] + Card.RANK_SCORE[other.rank]
def __sub__(self, other):
if type(other) != Card:
raise Card.OpError()
else:
return Card.RANK_SCORE[self.rank] - Card.RANK_SCORE[other.rank]
def __int__(self):
return Card.RANK_SCORE[self.rank]
def rep(self) -> Tuple[Suit, Rank]:
return self.suit, self.rank

19
src/DecisionMaker.py Normal file
View File

@@ -0,0 +1,19 @@
from __future__ import annotations
from Game import RoundType
from typing import Union, List
TYPECHECKING = False
if TYPECHECKING:
from Player import Hand, GameChoice
from Card import Card
from Game import TrickState
class DecisionMaker:
def __init__(self):
pass
def make_decision(self, trick_state: TrickState, hand: Hand) -> int:
raise NotImplementedError("This is an abstract base class!")
def choose_round_type(self, hand: Hand, sauspiel_choices: List[Card.Suit]) -> GameChoice:
raise NotImplementedError("This is an abstract base class!")

View File

@@ -1,5 +1,7 @@
from Card import Card
from typing import List
TYPECHECKING = False
if TYPECHECKING:
from typing import List
class Deck(list):

View File

@@ -1,53 +1,168 @@
from Player import Player
from typing import List
from Round import Round
from RufSpiel import RufSpiel
from Card import Card
from Deck import Deck
from Renderer import Renderer
from Errors import GameLevelError
from __future__ import annotations
import random as rn
from itertools import cycle
from enum import Enum
from typing import List, Union, NamedTuple, Dict, Tuple
from Errors import GameLevelError
from Card import Card
from Deck import Deck
TYPECHECKING = False
if TYPECHECKING:
from Player import Player, Hand, GameChoice
from Renderer import Renderer
Stack = List[Card]
class RoundType(Enum):
Sauspiel = "Sauspiel"
Wenz = "Wenz"
Farbsolo = "Farbsolo"
Ramsch = "Ramsch"
class Round(NamedTuple):
type: RoundType
isFarbSolo: bool
trumpSuit: Union[Card.Suit, None]
class Turn(NamedTuple):
suit: Card.Suit
isTrumpTurn: bool
class Move(NamedTuple):
card: Card
playerId: Player.Id
Trick = List[Card]
TrickState = List[Move]
CardRep = Tuple[Card.Suit, Card.Rank]
CardRanking = Dict[CardRep, int]
class Game:
def __init__(self, players: List[Player], renderer: Renderer):
if len(players) != 4:
raise GameLevelError("There must be exactly four players, but received " + str(len(players)) + "!")
self.players: List[Player] = players
self.game_over: bool = False
self.renderer = renderer
self.deck = Deck()
self.stack: List[Card] = []
self.current_round: Round = RufSpiel(self.players)
PLAYER_COUNT = 4
TRICK_SIZE = PLAYER_COUNT
def play(self):
SAUSPIEL_TRUMP_ORDER: List[CardRep] = [
(Card.Suit.Eichel, Card.Rank.Ober),
(Card.Suit.Gras, Card.Rank.Ober),
(Card.Suit.Herz, Card.Rank.Ober),
(Card.Suit.Schellen, Card.Rank.Ober),
(Card.Suit.Eichel, Card.Rank.Unter),
(Card.Suit.Gras, Card.Rank.Unter),
(Card.Suit.Herz, Card.Rank.Unter),
(Card.Suit.Schellen, Card.Rank.Unter),
]
def __init__(self, players: List[Player], renderer: Renderer):
if len(players) != Game.PLAYER_COUNT:
raise GameLevelError("There must be exactly four players, but received " + str(len(players)) + "!")
self.renderer: Renderer = renderer
self.players: List[Player] = players
self.current_player_index: int = 0
self.last_trick_winner_index: int = 0
self.dealer_index: int = 0
self.game_over: bool = False
self.round_over: bool = False
self.round_count: int = 0
self.trick_count: int = 0
self.round_details: Round = Round(
type=RoundType.Sauspiel,
isFarbSolo=False,
trumpSuit=Card.Suit.Herz
)
self.round_trump_ranking: CardRanking = {}
self.trick_details: Turn = Turn(
suit=Card.Suit.Schellen,
isTrumpTurn=False
)
self.deck = Deck()
self.current_trick: TrickState = []
def play(self) -> None:
self.renderer.render_message("Game start!")
while not self.game_over:
self.current_round = Round(self.players)
self.round_count += 1
self.trick_count = 0
self.current_player_index = self.neighbour_index(self.dealer_index, after=True)
self.play_round()
self.game_over = True
self.dealer_index = self.neighbour_index(self.dealer_index, after=True)
self.renderer.render_message("Game end!")
def play_round(self):
def play_round(self) -> None:
self.renderer.render_message("Round {} start!".format(self.round_count))
self.deal_cards()
while not self.current_round.is_over():
self.stack.clear()
self.round_turn()
self.renderer.render()
self.current_round.next_turn()
self.determine_game_type()
self.update_trump_ranking()
for i in range(len(self.deck) // Game.PLAYER_COUNT):
self.trick_count += 1
self.current_trick.clear()
self.play_trick()
self.current_player_index = self.last_trick_winner_index
self.renderer.render_message("Round Results:")
for player in self.players:
score = player.calc_score_for_tricks()
self.renderer.render_message("{}: {} points.".format(player.get_name(), score))
self.renderer.render_message("Round end!")
def round_turn(self):
self.renderer.render_message("Turn {} start.".format(self.current_round.turns_taken() + 1))
def determine_game_type(self) -> None:
player_choosing = self.current_player_index
player = None
for i in range(len(self.players)):
self.renderer.render_hand(self.players[player_choosing])
sauspiel_choices = self.sauspiel_choices_for_hand(self.players[player_choosing].card_options())
self.players[player_choosing].choose_round_type(sauspiel_choices)
player_choosing = self.neighbour_index(player_choosing, after=True)
def sauspiel_choices_for_hand(self, hand: Hand) -> List[Card.Suit]:
has_card = {
Card.Suit.Eichel: {"ass": False, "normal": False},
Card.Suit.Gras: {"ass": False, "normal": False},
Card.Suit.Schellen: {"ass": False, "normal": False}
}
choices: List[Card.Suit] = []
for card in hand:
if card.suit != Card.Suit.Herz:
if card.rank not in [Card.Rank.Ober, Card.Rank.Unter, Card.Rank.Ass]:
has_card[card.suit]["normal"] = True
elif card.rank == Card.Rank.Ass:
has_card[card.suit]["ass"] = True
for suit in has_card:
if has_card[suit]["normal"] and not has_card[suit]["ass"]:
choices.append(suit)
return choices
def update_trump_ranking(self) -> None:
rank_val = 0
if self.round_details.type == RoundType.Sauspiel:
for card_type in Game.SAUSPIEL_TRUMP_ORDER:
self.round_trump_ranking[card_type] = rank_val
rank_val += 1
for rank in Card.Rank:
if rank != Card.Rank.Ober and rank != Card.Rank.Unter:
self.round_trump_ranking[(self.round_details.trumpSuit, rank)] = rank_val
rank_val += 1
def play_trick(self) -> None:
self.renderer.render_message("Turn {} start.".format(self.trick_count))
for i in range(len(self.players)):
self.renderer.render_hand(self.current_player())
self.make_move_for_current_player()
self.renderer.render_stack(self.stack)
if self.current_round.turn_in_progress():
self.current_round.move_turn_to_next_player()
self.renderer.render_stack(self.current_trick)
self.proceed_to_next_player()
winning_move: Move = self.determine_winning_move(self.current_trick)
self.last_trick_winner_index = winning_move.playerId
winner = self.players[self.last_trick_winner_index]
winner.add_trick([move.card for move in self.current_trick])
self.renderer.render_message("{p} won the trick with the card: {c}".format(
p=winner.get_name(), c=winning_move.card))
self.renderer.render_message("Turn end.")
def deal_cards(self) -> None:
@@ -57,32 +172,54 @@ class Game:
dealt_cards = self.deck[i:i + 4]
next(player_iterator).deal_cards(*dealt_cards)
def current_player(self):
return self.players[self.current_round.get_current_player_index()]
def make_move_for_current_player(self) -> None:
cards_to_choose_from: List[Card] = self.current_player().card_options()
card_index_choice = None
while card_index_choice is None:
try:
attempt = int(input("Choose a card -> "))
if len(cards_to_choose_from) >= attempt > 0:
card_index_choice = attempt - 1
else:
print("Choice was outside card range.")
except ValueError:
print("Invalid choice.")
self.stack.append(self.current_player().play_card(card_index_choice))
self.current_trick.append(
self.current_player().make_decision(self.current_trick.copy())
)
if self.last_trick_winner_index == self.current_player_index:
self.trick_details = Turn(
suit=self.current_trick[0].card.suit,
isTrumpTurn=self.current_trick[0].card.suit == self.round_details.trumpSuit)
def last_cards_played(self, num_cards: int) -> Stack:
if len(self.stack) == 0:
return []
elif len(self.stack) == 1:
return [self.stack[0]]
else:
if num_cards > len(self.stack):
num_cards = len(self.stack)
return self.stack[-num_cards:]
def round_is_over(self) -> bool:
return self.round_over
def get_stack(self) -> Stack:
return self.stack.copy()
def proceed_to_next_player(self) -> None:
self.current_player_index = self.neighbour_index(self.current_player_index, after=True)
def neighbour_index(self, player_index: int, after: bool = True) -> int:
neighbour = player_index + 1 if after else player_index - 1
if neighbour >= len(self.players):
neighbour = 0
elif neighbour < 0:
neighbour = len(self.players) - 1
return neighbour
def set_starting_player(self) -> None:
self.current_player_index = rn.randint(0, len(self.players) - 1)
def determine_winning_move(self, trick: TrickState) -> Move:
best_move = trick[0]
for move in trick:
if self.round_details.type == RoundType.Sauspiel:
if move.card.rep() in self.round_trump_ranking:
if best_move.card.rep() in self.round_trump_ranking:
if self.new_move_wins_trump_trick(best_move, move):
best_move = move
else:
best_move = move
elif move.card.suit == self.trick_details.suit and move.card > best_move.card:
best_move = move
return best_move
def new_move_wins_trump_trick(self, old_move: Move, new_move: Move) -> bool:
return self.round_trump_ranking[new_move.card.rep()] < self.round_trump_ranking[old_move.card.rep()]
def trick_value(self, trick: TrickState) -> int:
return sum([move.card for move in trick])
def current_player(self) -> Player:
return self.players[self.current_player_index]
def current_dealer(self) -> Player:
return self.players[self.dealer_index]

View File

@@ -2,7 +2,22 @@ from typing import Dict, List
from Card import Card
from collections import namedtuple
SUITS_STR: Dict[Card.Suit, str] = {
Card.Suit.Eichel: "",
Card.Suit.Gras: "",
Card.Suit.Herz: "",
Card.Suit.Schellen: "",
}
RANKS_STR: Dict[Card.Rank, str] = {
Card.Rank.Ober: "O",
Card.Rank.Unter: "U",
Card.Rank.Ass: "A",
Card.Rank.Koenig: "K",
Card.Rank.Zehn: "X",
Card.Rank.Neun: "9",
Card.Rank.Acht: "8",
Card.Rank.Sieben: "7",
}
SUIT_COLOR: Dict[Card.Suit, str] = {
Card.Suit.Eichel: "Black",
Card.Suit.Gras: "Green",
@@ -54,7 +69,7 @@ GLYPH_CHAR: Dict[str, str] = {
def glyph_for(card: Card) -> Glyph:
glyph = Glyph(CARD_GLYPH_CHARS.copy(), CARD_GLYPH_COLOR.copy())
for i, line in enumerate(glyph.chars):
glyph.chars[i] = line.replace("S", Card.SUITS_STR[card.suit]).replace("R", Card.RANKS_STR[card.rank])
glyph.chars[i] = line.replace("S", SUITS_STR[card.suit]).replace("R", RANKS_STR[card.rank])
for i, line in enumerate(glyph.colors):
glyph.colors[i] = line.replace("S", GLYPH_CHAR[SUIT_COLOR[card.suit]])
return glyph
@@ -83,7 +98,7 @@ def stacked_glyphs(cards: List[Card]):
result_width = len(CARD_GLYPH_CHARS[0]) + len(cards) - 1
result_height = len(CARD_GLYPH_CHARS) + len(cards) - 1
result = Glyph([" " * result_width] * result_height, [GLYPH_CHAR["Default"] * result_width] * result_height)
for i, card in enumerate(reversed(cards)):
for i, card in enumerate(cards):
origin_coord = [i, i]
for j, (chars_line, glyph_colors_line) in enumerate(zip(glyph_for(card).chars, glyph_for(card).colors)):
chars_out = result.chars[j + origin_coord[0]]

View File

@@ -0,0 +1,78 @@
from __future__ import annotations
from DecisionMaker import DecisionMaker
from Player import GameChoice
from Game import RoundType
from typing import List
from Card import Card
TYPECHECKING = False
if TYPECHECKING:
from Player import Hand
from Game import TrickState
class HumanDecisionInterface(DecisionMaker):
def __init__(self):
super().__init__()
def make_decision(self, trick_state: TrickState, hand: Hand) -> int:
card_index_choice = None
while card_index_choice is None:
try:
attempt = int(input("Choose a card -> "))
if len(hand) >= attempt > 0:
card_index_choice = attempt - 1
else:
print("Choice was outside card range.")
except ValueError:
print("Invalid choice.")
return card_index_choice
def choose_round_type(self, hand: Hand, sauspiel_choices: List[Card.Suit]) -> GameChoice:
type_choice = self.prompt_round_type(sauspiel_choices)
suit_choice = None
if type_choice not in [RoundType.Wenz, None]:
suit_choice = self.prompt_suit(type_choice, sauspiel_choices)
playing_tout = False
if type_choice in [RoundType.Wenz, RoundType.Farbsolo]:
playing_tout = self.prompt_tout()
return GameChoice(type_choice, suit_choice, playing_tout)
def prompt_round_type(self, sauspiel_choices: List[Card.Suit]) -> RoundType:
round_types = [None] + \
([RoundType.Sauspiel] if len(sauspiel_choices) > 0 else []) + \
[RoundType.Farbsolo, RoundType.Wenz]
type_choice = None
type_was_chosen = False
while not type_was_chosen:
try:
print("Choose a game to play: ")
print(", ".join(
["Pass (1)"] + ["{} ({})".format(round_type.name, i + 1) for i, round_type in enumerate(round_types)
if round_type is not None]))
attempt = int(input(" -> "))
type_choice = round_types[attempt - 1]
type_was_chosen = True
except ValueError:
print("Invalid input.")
except IndexError:
print("Invalid choice.")
return type_choice
def prompt_suit(self, type_choice: RoundType, sauspiel_choices: List[Card.Suit]) -> Card.Suit:
suit_choice = None
while suit_choice is None:
try:
suit_types = [suit for suit in Card.Suit] if type_choice != RoundType.Sauspiel else sauspiel_choices
print("Choose a suit to play with: ")
print(", ".join(["{} ({})".format(suit.name, i + 1) for i, suit in enumerate(suit_types)]))
attempt = int(input(" -> "))
suit_choice = suit_types[attempt - 1]
except ValueError:
print("Invalid input.")
except IndexError:
print("Invalid choice.")
return suit_choice
def prompt_tout(self) -> bool:
attempt = input("Will you play Tout? (Y/N) -> ")
return attempt == "Y"

View File

@@ -1,10 +1,23 @@
from typing import List, Tuple
from __future__ import annotations
from typing import List, Union, NamedTuple
from Card import Card
from copy import deepcopy
from Game import Move, RoundType
from enum import Enum
TYPECHECKING = False
if TYPECHECKING:
from DecisionMaker import DecisionMaker
from Game import TrickState
Hand = List[Card]
Trick = Tuple[Card, Card, Card, Card]
Trick = List[Card]
class GameChoice(NamedTuple):
type: Union[RoundType, None]
suit: Union[Card.Suit, None]
tout: bool
class Player:
@@ -17,11 +30,13 @@ class Player:
cls.instances += 1
return new_id
def __init__(self, name: str):
def __init__(self, name: str, decision_maker: DecisionMaker, is_human: bool):
self.id = self.get_new_id()
self.human_controlled: bool = is_human
self.name: str = name
self.hand: Hand = []
self.tricks: List[Trick] = []
self.decision_maker: DecisionMaker = decision_maker
def __str__(self):
return self.name
@@ -42,11 +57,30 @@ class Player:
self.tricks = []
self.hand = []
def tricks(self) -> List[Trick]:
def get_tricks(self) -> List[Trick]:
return deepcopy(self.tricks)
def get_name(self):
return self.name
def get_id(self) -> int:
return self.id
return self.id
def make_decision(self, trick_state: TrickState) -> Move:
return Move(
self.play_card(self.decision_maker.make_decision(trick_state, self.hand)),
self.get_id()
)
def choose_round_type(self, sauspiel_choices: List[Card.Suit]) -> None:
self.decision_maker.choose_round_type(self.hand, sauspiel_choices)
def game_choice(self) -> Union[RoundType, None]:
return self.game_choice()
def calc_score_for_tricks(self) -> int:
return sum([int(card) for trick in self.tricks for card in trick])
def is_human(self):
return self.human_controlled

View File

@@ -1,13 +1,15 @@
from Player import Player
from Card import Card
from typing import List
from __future__ import annotations
TYPECHECKING = False
if TYPECHECKING:
from Player import Player
from Game import TrickState
class Renderer:
def __init__(self):
pass
def render_stack(self, cards: List[Card]):
def render_stack(self, cards: TrickState):
pass
def render_hand(self, player: Player):
@@ -15,6 +17,3 @@ class Renderer:
def render_message(self, message: str):
pass
def render(self) -> None:
pass

View File

@@ -1,39 +0,0 @@
from Player import Player
from Errors import RoundLevelError
from typing import List
import random as rn
class Round:
def __init__(self, players: List[Player]):
self.current_player_index: int = 0
self.round_ended: bool = False
self.turn_number: int = 1
self.moves_left_in_turn: int = len(players)
self.num_players = len(players)
def gen_player_list(self, players: List[Player]):
return list(map(lambda x: x.get_id(), players))
def turns_taken(self) -> int:
return self.turn_number - 1
def turn_in_progress(self) -> bool:
return self.moves_left_in_turn > 0
def is_over(self) -> bool:
return self.round_ended or self.turn_number > 8
def next_turn(self) -> None:
self.turn_number += 1
self.current_player_index = 0
def move_turn_to_next_player(self) -> None:
if not self.turn_in_progress():
raise RoundLevelError("Cannot move to the next player if all players have already made their move!")
self.current_player_index += 1
if self.current_player_index >= self.num_players:
self.current_player_index = 0
def get_current_player_index(self) -> int:
return self.current_player_index

View File

@@ -1,11 +0,0 @@
from Card import Card
from Player import Player, Player.Id
from typing import List
from Round import Round
class RufSpiel(Round):
def __init__(self, players: List[Player], spieler_id: Player.Id, spieler):
super().__init__(players)
self.variable_trump: Card.Suit = Card.Suit.Herz
self.spieler: Player.Id =

View File

@@ -0,0 +1,21 @@
from Renderer import Renderer
from typing import List
from Player import Player
from Card import Card
from Glyph import side_by_side_glyphs, stacked_glyphs, glyph_to_colored_string
from Game import TrickState
import os
class SequentialConsoleRenderer(Renderer):
def __init__(self):
super().__init__()
def render_stack(self, trick_state: TrickState):
print(glyph_to_colored_string(stacked_glyphs([move.card for move in trick_state])))
def render_hand(self, player: Player):
print(player.get_name() + "'s hand:\n" + glyph_to_colored_string(side_by_side_glyphs(player.card_options())))
def render_message(self, message: str):
print(message)

View File

@@ -3,18 +3,19 @@ from typing import List
from Player import Player
from Card import Card
from Glyph import side_by_side_glyphs, stacked_glyphs, glyph_to_colored_string
from Game import TrickState
import os
class ConsoleRenderer(Renderer):
class SingleScreenConsoleRenderer(Renderer):
def __init__(self):
super().__init__()
self.header = ""
self.stack = ""
self.hand = ""
def render_stack(self, cards: List[Card]):
self.stack = glyph_to_colored_string(stacked_glyphs(cards))
def render_stack(self, trick_state: TrickState):
self.stack = glyph_to_colored_string(stacked_glyphs([move.card for move in trick_state]))
self.rerender()
def render_hand(self, player: Player):
@@ -32,4 +33,4 @@ class ConsoleRenderer(Renderer):
print()
print("Current Stack: ")
print(self.stack)
print(self.hand)
print(self.hand)

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@@ -1,31 +1,36 @@
from typing import List
from Player import Player
from HumanDecisionInterface import HumanDecisionInterface
from SequentialConsoleRenderer import SequentialConsoleRenderer
from Game import Game
from ConsoleRenderer import ConsoleRenderer
from Player import Player
from typing import List
def main() -> None:
players: List[Player] = get_players()
renderer = ConsoleRenderer()
renderer = SequentialConsoleRenderer()
game: Game = Game(players, renderer)
game.play()
def get_players():
def get_players() -> List[Player]:
return get_default_players()
def get_default_players() -> List[Player]:
names = ["Andy", "Ben", "Chris", "Daniel"]
return list(map(Player, names))
return list(map(make_new_human_player, names))
def make_new_human_player(name: str) -> Player:
return Player(name, HumanDecisionInterface(), True)
def get_input_players() -> List[Player]:
print("Who's playing?")
p1 = Player(input("Player 1: "))
p2 = Player(input("Player 2: "))
p3 = Player(input("Player 3: "))
p4 = Player(input("Player 4: "))
p1 = make_new_human_player(input("Player 1: "))
p2 = make_new_human_player(input("Player 2: "))
p3 = make_new_human_player(input("Player 3: "))
p4 = make_new_human_player(input("Player 4: "))
return [p1, p2, p3, p4]

View File

@@ -1,5 +1,5 @@
import unittest
from Player import Player, PlayerLoop
from Player import Player
class MyTestCase(unittest.TestCase):