PY-2017.3 <Brad@Libra Merge branch 'master'

Conflicts:
	_windows/laf.xml
	editor.xml
This commit is contained in:
bradstein 2018-01-10 23:51:33 -06:00
commit 3d8cf58e5a
48 changed files with 326 additions and 350 deletions

View File

@ -11,11 +11,10 @@ Things done:
6) Input safety 6) Input safety
Things to do: Things to do:
1) Make end of game conditions match actual end of game conditions 1) Testing classes
2) Testing classes 2) Turn Timer
3) Turn Timer 3) Django server and hosting
4) Django server and hosting 4) HTML5 frontend
5) HTML5 frontend 5) Multiplayer
6) Multiplayer 6) Remaining 2nd Edition Base Cards: Bureaucrat, Chapel, Feast, Laboratory, Moneylender, Throne Room, Council Room, Festival, Library, Harbringer, Vassal, Gardens, Poacher, Bandit, Witch, Artisan, & Sentry
7) Remaining 2nd Edition Base Cards: Bureaucrat, Chapel, Feast, Laboratory, Moneylender, Throne Room, Council Room, Festival, Library, Harbringer, Vassal, Gardens, Poacher, Bandit, Witch, Artisan, & Sentry 7) Choosing play sets
8) Choosing play sets

View File

@ -1,5 +0,0 @@
<application>
<component name="Git.Application.Settings">
<option name="SSH_EXECUTABLE" value="IDEA_SSH" />
</component>
</application>

View File

@ -1,5 +1,5 @@
<application> <application>
<component name="LafManager"> <component name="LafManager">
<laf class-name="com.intellij.ide.ui.laf.darcula.DarculaLaf" /> <laf class-name="com.intellij.ide.ui.laf.IntelliJLaf" />
</component> </component>
</application> </application>

View File

@ -0,0 +1,5 @@
from card.basic.card_kingdom import Kingdom
class Action(Kingdom):
pass

11
card/basic/card_attack.py Normal file
View File

@ -0,0 +1,11 @@
from card.basic.card_kingdom import Kingdom
class Attack(Kingdom):
def effect(self):
for player in self.get_owner().get_table().get_players():
if self.get_owner() != player and not player.get_hand().reaction_blocks_attack(self.get_name()):
self.attack(player)
def attack(self, player):
pass

10
card/basic/card_curse.py Normal file
View File

@ -0,0 +1,10 @@
from card.basic.card_victory import Victory
class Curse(Victory):
@classmethod
def pile_setup(cls, player_count):
if player_count % cls.normal_full_table < cls.normal_full_table/2:
return Victory.pile_player_rate
else:
return (player_count - 1) * cls.pile_player_rate

View File

@ -0,0 +1,10 @@
from card.card import Card
from math import floor
class Kingdom(Card):
pile_player_rate = 10
@classmethod
def pile_setup(cls, player_count):
return (floor(player_count/cls.normal_full_table) + 1) * cls.pile_player_rate

View File

@ -0,0 +1,5 @@
from card.basic.card_kingdom import Kingdom
class Reaction(Kingdom):
pass

View File

@ -0,0 +1,8 @@
from card.card import Card
from math import floor
class Treasure(Card):
@classmethod
def pile_setup(cls, player_count):
return (floor(player_count/cls.normal_full_table) + 1) * cls.pile_player_rate

View File

@ -0,0 +1,21 @@
from card.card import Card
from math import floor
class Victory(Card):
two_player_count = 8
four_player_count = 12
five_player_count = 15
six_player_count = 18
@classmethod
def pile_setup(cls, player_count):
if 0 < player_count % Card.normal_full_table < Card.normal_full_table/2:
supplement = cls.two_player_count
elif Card.normal_full_table/2 <= player_count % Card.normal_full_table < Card.normal_full_table - 1:
supplement = cls.four_player_count
elif player_count % Card.normal_full_table == Card.normal_full_table - 1:
supplement = cls.five_player_count
else:
supplement = cls.six_player_count
return (floor(player_count/Card.normal_full_table) * cls.six_player_count) + supplement

View File

@ -1,22 +1,11 @@
from enum import Enum, auto
class Card: class Card:
class CardType(Enum): normal_full_table = 6
Treasure = auto() pile_player_rate = 10
Action = auto()
Reaction = auto()
Attack = auto()
Victory = auto()
Curse = auto()
prevent_attack = False def __init__(self, name, cost, value, coin, action, buy, draw, owner):
def __init__(self, name, cost, cardtype, value, coin, action, buy, draw, owner):
self.__name = name self.__name = name
self.__cost = cost self.__cost = cost
self.__coin = coin self.__coin = coin
self.__type = cardtype
self.__action = action self.__action = action
self.__buy = buy self.__buy = buy
self.__draw = draw self.__draw = draw
@ -34,16 +23,22 @@ class Card:
# This is here so that 'special' card can override this function so that unique card effects can happen. # This is here so that 'special' card can override this function so that unique card effects can happen.
pass pass
def setup(self): def react(self, what_attack):
return False
@classmethod
def pile_setup(cls, player_count):
# This is here so that each card can override this function so that the right number of .
pass
@staticmethod
def setup():
# This is here so that 'special' card can override this function so that unique card setup effects can happen. # This is here so that 'special' card can override this function so that unique card setup effects can happen.
pass pass
def get_name(self): def get_name(self):
return self.__name return self.__name
def get_type(self):
return self.__type
def get_points(self): def get_points(self):
return self.__value return self.__value
@ -60,7 +55,15 @@ class Card:
return self.__owner return self.__owner
def identify(self): def identify(self):
return self.__name + ", " + str(self.__type) + ", " + str(self.__cost) return self.__name + ", " + self.__str__() + ", costing " + str(self.__cost)
def print_card_list(self, card, message):
print("\nPlayer " + str(self._Card__owner.get_player_index()) + " " + message)
counter = 0
for c in card:
print(str(counter) + ": " + c.identify())
counter += 1
def __get_index_not_self(self): def __get_index_not_self(self):
result = -1 result = -1
@ -69,13 +72,5 @@ class Card:
result = self._Card__owner.get_hand().get_player_index() result = self._Card__owner.get_hand().get_player_index()
return result return result
def __print_card_list(self, card, message):
print("\nPlayer " + str(self._Card__owner.get_player_index()) + " " + message)
counter = 0
for c in card:
print(str(counter) + ": " + c.identify())
counter += 1
def __str__(self): def __str__(self):
return "A " + self.__name + " card." return "a " + self.__name + " card"

View File

@ -1,8 +0,0 @@
from card.card import Card
from card.card_gain_trash import CardGainTrash
class Mine(CardGainTrash):
coin_gain = 3
trashable_type_restriction = [Card.CardType.Treasure]
gainable_type_restriction = [Card.CardType.Treasure]

View File

@ -1,5 +0,0 @@
from card.card import Card
class Moat(Card):
prevent_attack = True

View File

@ -1,7 +1,7 @@
from card.card import Card from card.basic.card_action import Action
class Cellar(Card): class Cellar(Action):
def effect(self): def effect(self):
hand_index = 0 hand_index = 0
cards_discarded = 0 cards_discarded = 0

5
card/named/copper.py Normal file
View File

@ -0,0 +1,5 @@
from card.basic.card_treasure import Treasure
class Copper(Treasure):
pile_player_rate = 60

8
card/named/estate.py Normal file
View File

@ -0,0 +1,8 @@
from card.basic.card_victory import Victory
class Estate(Victory):
two_player_count = 14
four_player_count = 18
five_player_count = 21
six_player_count = 24

5
card/named/gold.py Normal file
View File

@ -0,0 +1,5 @@
from card.basic.card_treasure import Treasure
class Gold(Treasure):
pile_player_rate = 30

View File

@ -1,7 +1,7 @@
from card.card import Card from card.basic.card_action import Action
class Merchant(Card): class Merchant(Action):
def effect(self): def effect(self):
silver_card_index = self._Card__owner.get_hand().get_index_of_card_by_name("Silver") silver_card_index = self._Card__owner.get_hand().get_index_of_card_by_name("Silver")
if silver_card_index >= 0: if silver_card_index >= 0:

View File

@ -1,14 +1,13 @@
from card.card import Card from card.basic.card_attack import Attack
from card.basic.card_action import Action
from random import randint from random import randint
class Militia(Card): class Militia(Action, Attack):
def effect(self): def attack(self, player):
for player in self._Card__owner.get_table().get_players(): player.print_hand()
if self._Card__owner != player and not player.get_hand().blocks_attack(self.get_name()): print("Player " + str(player.get_player_index()) + ", you MUST discard down to 3 card.")
player.print_hand() self.__force_discard(self.get_owner().get_std_chances(), player)
print("Player " + str(player.get_player_index()) + ", you MUST discard down to 3 card.")
self.__force_discard(self._Card__owner.get_std_chances(), player)
def __force_discard(self, chances, player): def __force_discard(self, chances, player):
if player.get_hand().get_remaining() > 3 and chances > 0: if player.get_hand().get_remaining() > 3 and chances > 0:
@ -16,16 +15,17 @@ class Militia(Card):
" discard (0 to " + str(player.get_hand().get_remaining() - 1) + "): " " discard (0 to " + str(player.get_hand().get_remaining() - 1) + "): "
, int) , int)
self.__check_discard(hand_index, player, chances) self.__check_discard(hand_index, player, chances)
elif self._Card__owner.get_hand().get_remaining() > 3 and chances <= 0: elif self.get_owner().get_hand().get_remaining() > 3 and chances <= 0:
print("You're out of chances to select a valid card to discard, randomly selecting for you.") print("You're out of chances to select a valid card to discard, randomly selecting for you.")
player.discard_from_hand(randint(0, self.__hand.get_remaining() - 1)) player.discard_from_hand(randint(0, self.get_owner().get_hand().get_remaining() - 1))
def __check_discard(self, index, player, chances): def __check_discard(self, index, player, chances):
if 0 > index or index >= self._Card__owner.get_hand().get_remaining(): if 0 > index >= player.get_hand().get_remaining():
print("Valid inputs range from 0 to " + str(player.get_hand().get_remaining() - 1) + ". 1 chance lost.") print("Valid inputs range from 0 to " + str(player.get_hand().get_remaining() - 1) + ". " + str(chances - 1)
+ "chances to input a valid index.")
self.__force_discard(chances - 1, player) self.__force_discard(chances - 1, player)
else: else:
print("Discarding " + player.get_hand().get_card(index).get_name() + ".") print("Discarding " + player.get_hand().get_card(index).get_name() + ".")
player.discard_from_hand(index) player.discard_from_hand(index)
player.print_hand() player.print_hand()
self.__force_discard(self._Card__owner.get_std_chances(), player) self.__force_discard(self.get_owner().get_std_chances(), player)

9
card/named/mine.py Normal file
View File

@ -0,0 +1,9 @@
from card.basic.card_action import Action
from card.basic.card_treasure import Treasure
from card.special.card_gain_trash import CardGainTrash
class Mine(Action, CardGainTrash):
coin_gain = 3
trashable_type_restriction = Treasure
gainable_type_restriction = Treasure

10
card/named/moat.py Normal file
View File

@ -0,0 +1,10 @@
from card.basic.card_action import Action
from card.basic.card_reaction import Reaction
class Moat(Action, Reaction):
def react(self, what_attack):
owner = self.get_owner()
return "Y" == owner.get_general_input("Player " + str(owner.get_player_index()) + ", enter 'Y' if you'd "
"like to reveal " + str(self) + " to block the " + str(what_attack) +
" attack: ", str)

5
card/named/province.py Normal file
View File

@ -0,0 +1,5 @@
from card.basic.card_victory import Victory
class Province(Victory):
pass

6
card/named/remodel.py Normal file
View File

@ -0,0 +1,6 @@
from card.basic.card_action import Action
from card.special.card_gain_trash import CardGainTrash
class Remodel(Action, CardGainTrash):
coin_gain = 2

6
card/named/silver.py Normal file
View File

@ -0,0 +1,6 @@
from card.basic.card_treasure import Treasure
class Silver(Treasure):
pile_player_rate = 40

9
card/named/workshop.py Normal file
View File

@ -0,0 +1,9 @@
from card.basic.card_action import Action
from card.special.card_gain import CardGain
class Workshop(Action, CardGain):
coin_gain = 4
def effect(self):
self.gain_card(self.coin_gain)

View File

@ -1,5 +0,0 @@
from card.card_gain_trash import CardGainTrash
class Remodel(CardGainTrash):
coin_gain = 2

View File

@ -6,9 +6,9 @@ class CardGain(Card):
def gain_card(self, spending_limit): def gain_card(self, spending_limit):
gainable_cards = self.__get_gainable_cards(spending_limit) gainable_cards = self.__get_gainable_cards(spending_limit)
self._Card__print_card_list(gainable_cards, "Gainable Cards: ") self.print_card_list(gainable_cards, "Gainable Cards: ")
index = 0 index = 0
chances = self._Card__owner.get_std_chances() chances = self.get_owner().get_std_chances()
while len(gainable_cards) > 0 and 0 <= index < len(gainable_cards) - 1 and chances > 0: while len(gainable_cards) > 0 and 0 <= index < len(gainable_cards) - 1 and chances > 0:
index = self.__get_gain_card() index = self.__get_gain_card()
@ -18,24 +18,24 @@ class CardGain(Card):
index = 0 index = 0
chances -= 1 chances -= 1
else: else:
pile_index = self._Card__owner.get_table().get_pile_index_of_card(gainable_cards[index].get_name()) pile_index = self.get_owner().get_table().get_pile_index_of_card(gainable_cards[index].get_name())
print("Player " + str(self._Card__owner.get_player_index()) + " drawing " print("Player " + str(self.get_owner().get_player_index()) + " drawing "
+ self._Card__owner.get_table().get_pile(pile_index).get_card_group().get_name() + " to hand.") + self.get_owner().get_table().get_pile(pile_index).get_card_group().get_name() + " to hand.")
self._Card__owner.get_table().get_pile(pile_index).transfer_top_card(self._Card__owner.get_hand()) self.get_owner().get_table().get_pile(pile_index).transfer_top_card(self.get_owner().get_hand())
self._Card__owner.claim_top_card(self._Card__owner.get_hand()) self.get_owner().claim_top_card(self.get_owner().get_hand())
chances = 0 chances = 0
def __get_gain_card(self): def __get_gain_card(self):
return self.__Card_owner.get_general_input("\nPlease identify the index of which card you would like to " return self.get_owner().get_general_input("\nPlease identify the index of which card you would like to "
"obtain: ", int) "obtain: ", int)
def __get_gainable_cards(self, spending_limit): def __get_gainable_cards(self, spending_limit):
result = list() result = list()
for p in self._Card__owner.get_table().get_piles(): for p in self.get_owner().get_table().get_piles():
if p.get_card_group().get_cost() <= spending_limit: if p.get_card_group().get_cost() <= spending_limit:
if self.gainable_type_restriction is None: if self.gainable_type_restriction is None:
result.append(p.get_card_group()) result.append(p.get_card_group())
elif p.get_card_group().get_type() in self.gainable_type_restriction: elif isinstance(p.get_card_group(), self.gainable_type_restriction):
result.append(p.get_card_group()) result.append(p.get_card_group())
return result return result

View File

@ -1,5 +1,5 @@
from card.card_trash import CardTrash from card.special.card_trash import CardTrash
from card.card_gain import CardGain from card.special.card_gain import CardGain
class CardGainTrash(CardTrash, CardGain): class CardGainTrash(CardTrash, CardGain):

View File

@ -6,10 +6,10 @@ class CardTrash(Card):
def trash_card_get_cost(self): def trash_card_get_cost(self):
tc = self.__get_trashable_cards() tc = self.__get_trashable_cards()
self._Card__print_card_list(tc, " Trashable Cards: ") self.print_card_list(tc, " Trashable Cards: ")
index = 0 index = 0
bonus = 0 bonus = 0
chances = self._Card__owner.get_std_chances() chances = self.get_owner().get_std_chances()
while 0 < len(tc) and 0 <= index < len(tc) - 1 and chances > 0: while 0 < len(tc) and 0 <= index < len(tc) - 1 and chances > 0:
index = self.__get_card_to_trash() index = self.__get_card_to_trash()
@ -19,9 +19,9 @@ class CardTrash(Card):
index = 0 index = 0
chances -= 1 chances -= 1
else: else:
print("Player " + str(self._Card__owner.get_player_index()) + " trashing " + tc[index].get_name() + ".") print("Player " + str(self.get_owner().get_player_index()) + " trashing " + tc[index].get_name() + ".")
bonus = tc[index].get_cost() bonus = tc[index].get_cost()
self._Card__owner.get_hand().transfer_card_by_card(tc[index], self._Card__owner.get_table().get_trash()) self.get_owner().get_hand().transfer_card_by_card(tc[index], self.get_owner().get_table().get_trash())
chances = 0 chances = 0
return bonus return bonus
@ -29,15 +29,15 @@ class CardTrash(Card):
self.trash_card_get_cost() self.trash_card_get_cost()
def __get_card_to_trash(self): def __get_card_to_trash(self):
return self.__Card_owner.get_general_input("\nPlease identify the index of the desired card to trash: ", int) return self.get_owner().get_general_input("\nPlease identify the index of the desired card to trash: ", int)
def __get_trashable_cards(self): def __get_trashable_cards(self):
result = list() result = list()
for c in self._Card__owner.get_hand().get_supply(): for c in self.get_owner().get_hand().get_supply():
if c != self: if c != self:
if self.trashable_type_restriction is None: if self.trashable_type_restriction is None:
result.append(c) result.append(c)
elif c.get_type() in self.trashable_type_restriction: elif isinstance(c, self.trashable_type_restriction):
result.append(c) result.append(c)
return result return result

View File

@ -1,8 +0,0 @@
from card.card_gain import CardGain
class Workshop(CardGain):
coin_gain = 4
def effect(self):
self.gain_card(self.coin_gain)

View File

@ -1,8 +0,0 @@
<code_scheme name="Default" version="173">
<codeStyleSettings language="Python">
<indentOptions>
<option name="USE_TAB_CHARACTER" value="true" />
<option name="SMART_TABS" value="true" />
</indentOptions>
</codeStyleSettings>
</code_scheme>

View File

@ -1,78 +0,0 @@
<application>
<component name="LocalDatabaseDriverManager" version="163">
<driver id="exasol">
<artifact name="Exasol" use="true" />
<option name="auto-sync" value="true" />
</driver>
<driver id="h2.unified">
<artifact name="H2" use="true" />
<option name="auto-sync" value="true" />
</driver>
<driver id="azure.ms">
<artifact name="SQL Server" use="true" />
<option name="auto-sync" value="true" />
<option name="send-app-info" value="false" />
</driver>
<driver id="oracle">
<artifact name="Oracle" use="true" />
<option name="auto-sync" value="true" />
<option name="auto-commit" value="false" />
</driver>
<driver id="derby.embedded">
<artifact name="Apache Derby" use="true" />
<option name="auto-sync" value="true" />
</driver>
<driver id="sybase.jtds">
<artifact name="jTDS (SQL Server and Sybase)" use="true" />
<option name="auto-sync" value="true" />
</driver>
<driver id="sqlserver.jtds">
<artifact name="jTDS (SQL Server and Sybase)" use="true" />
<option name="auto-sync" value="true" />
</driver>
<driver id="hsqldb.local">
<artifact name="HSQLDB" use="true" />
<option name="auto-sync" value="true" />
</driver>
<driver id="derby.remote">
<artifact name="Apache Derby" use="true" />
<option name="auto-sync" value="true" />
</driver>
<driver id="sqlite.xerial">
<artifact name="Xerial SQLiteJDBC" use="true" />
<option name="auto-sync" value="true" />
</driver>
<driver id="sybase.ase">
<option name="auto-sync" value="true" />
</driver>
<driver id="postgresql">
<artifact name="PostgreSQL" use="true" />
<option name="auto-sync" value="true" />
</driver>
<driver id="redshift">
<artifact name="Redshift" use="true" />
<option name="auto-sync" value="true" />
</driver>
<driver id="db2">
<artifact name="DB2" use="true" />
<option name="auto-sync" value="false" />
</driver>
<driver id="sqlserver.ms">
<artifact name="SQL Server" use="true" />
<option name="auto-sync" value="true" />
<option name="send-app-info" value="false" />
</driver>
<driver id="db2.jtopen">
<artifact name="JTOpen (DB2 iSeries)" use="true" />
<option name="auto-sync" value="false" />
</driver>
<driver id="mysql">
<artifact name="MySQL Connector/J" use="true" />
<option name="auto-sync" value="true" />
</driver>
<driver id="hsqldb.remote">
<artifact name="HSQLDB" use="true" />
<option name="auto-sync" value="true" />
</driver>
</component>
</application>

View File

@ -1,26 +0,0 @@
<application>
<component name="DatabaseSettings" version="2">
<csv-formats>
<csv-format name="Tab-separated (TSV)" id="Tab-separated (TSV)_id">
<data>
<record-format prefix="" suffix="" nullText="" quotationPolicy="as needed" valueSeparator="&#9;" recordSeparator="&#10;">
<quotation>
<quotes left="&quot;" right="&quot;" leftEscaped="&quot;&quot;" rightEscaped="&quot;&quot;" />
<quotes left="'" right="'" leftEscaped="''" rightEscaped="''" />
</quotation>
</record-format>
</data>
</csv-format>
<csv-format name="Comma-separated (CSV)" id="Comma-separated (CSV)_id">
<data>
<record-format prefix="" suffix="" nullText="" quotationPolicy="as needed" valueSeparator="," recordSeparator="&#10;">
<quotation>
<quotes left="&quot;" right="&quot;" leftEscaped="&quot;&quot;" rightEscaped="&quot;&quot;" />
<quotes left="'" right="'" leftEscaped="''" rightEscaped="''" />
</quotation>
</record-format>
</data>
</csv-format>
</csv-formats>
</component>
</application>

View File

@ -1,13 +0,0 @@
<application>
<component name="XDebuggerSettings">
<data-views />
<general />
<debuggers>
<debugger id="javascript">
<configuration>
<custom-object-presentation />
</configuration>
</debugger>
</debuggers>
</component>
</application>

View File

@ -3,7 +3,8 @@
<option name="FONT_SIZE" value="18" /> <option name="FONT_SIZE" value="18" />
<option name="FONT_SCALE" value="1.5" /> <option name="FONT_SCALE" value="1.5" />
</component> </component>
<component name="EditorSettings"> <component name="TodoConfiguration">
<option name="USE_SOFT_WRAPS" value="CONSOLE" /> <pattern pattern="\btodo\b.*" />
<pattern pattern="\bfixme\b.*" />
</component> </component>
</application> </application>

View File

@ -1,5 +0,0 @@
<application>
<component name="FileTypeManager" version="17">
<ignoreFiles list="*$py.class;*.hprof;*.pyc;*.pyo;*.rbc;*.yarb;*~;.DS_Store;.git;.hg;.svn;CVS;__pycache__;_svn;vssver.scc;vssver2.scc;" />
</component>
</application>

View File

@ -1,7 +0,0 @@
<application>
<component name="FindSettings">
<option name="customScope" value="All Places" />
<option name="defaultScopeName" value="All Places" />
<option name="SEARCH_SCOPE" value="All Places" />
</component>
</application>

76
game.py
View File

@ -1,14 +1,21 @@
from table.table import Table from table.table import Table
from player.human import Human from player.human import Human
from player.bots.pure_big_money import Pure_Big_Money from player.bots.pure_big_money import Pure_Big_Money
from card.card import Card from card.basic.card_action import Action
from card.militia import Militia from card.basic.card_curse import Curse
from card.moat import Moat from card.basic.card_victory import Victory
from card.cellar import Cellar from card.named.province import Province
from card.merchant import Merchant from card.named.estate import Estate
from card.mine import Mine from card.named.copper import Copper
from card.remodel import Remodel from card.named.silver import Silver
from card.workshop import Workshop from card.named.gold import Gold
from card.named.militia import Militia
from card.named.moat import Moat
from card.named.cellar import Cellar
from card.named.merchant import Merchant
from card.named.mine import Mine
from card.named.remodel import Remodel
from card.named.workshop import Workshop
def main(): def main():
@ -31,14 +38,15 @@ def setup_new_game(game_list, parameter, card_info):
index = 0 index = 0
for p in parameter[2:]: for p in parameter[2:]:
if p: if p:
for i in range(card_info[index][9]): for i in range(card_info[index][7].pile_setup(humans + bots)):
card = card_info[index][8](card_info[index][0], card_info[index][1], card_info[index][2], card = card_info[index][7](card_info[index][0], card_info[index][1], card_info[index][2],
card_info[index][3], card_info[index][4], card_info[index][5], card_info[index][3], card_info[index][4], card_info[index][5],
card_info[index][6], card_info[index][7], None) card_info[index][6], None)
if i == 0: if i == 0:
t.create_pile(card) t.create_pile(card)
else: else:
t.get_pile(t.get_pile_index_of_card(card_info[index][0])).add_card(card) t.get_pile(t.get_pile_index_of_card(card_info[index][0])).add_card(card)
card_info[index][7].setup()
index += 1 index += 1
for i in range(humans): for i in range(humans):
@ -58,29 +66,29 @@ def setup_new_game(game_list, parameter, card_info):
def get_game_parameters(): def get_game_parameters():
# humans, bots, card #1, card #2, ... etc # humans, bots, card #1, card #2, ... etc
return [1, 1, True, True, True, True, True, True, False, True, True, True, True, True, True, True, True, True, True] return [2, 1, True, True, True, True, True, True, False, True, True, True, True, True, True, True, True, True, True]
def get_card_info(): def get_card_info():
# 0 1 2 3 4 5 6 7 8 9 # 0 1 2 3 4 5 6 7
# [name, cost, cardtype, v, c, a, b, d, class, count] - values to pass to Card() # [name, cost, v, c, a, b, d, class] - values to pass to Card()
return [["Copper", 0, Card.CardType.Treasure, 0, 1, 0, 0, 0, Card, 60], # 1 return [["Copper", 0, 0, 1, 0, 0, 0, Copper], # 0
["Silver", 3, Card.CardType.Treasure, 0, 2, 0, 0, 0, Card, 40], # 2 ["Silver", 3, 0, 2, 0, 0, 0, Silver], # 1
["Gold", 6, Card.CardType.Treasure, 0, 3, 0, 0, 0, Card, 30], # 3 ["Gold", 6, 0, 3, 0, 0, 0, Gold], # 2
["Estate", 2, Card.CardType.Victory, 1, 0, 0, 0, 0, Card, 40], # 4 ["Estate", 2, 1, 0, 0, 0, 0, Estate], # 3
["Dutchy", 5, Card.CardType.Victory, 3, 0, 0, 0, 0, Card, 12], # 5 ["Dutchy", 5, 3, 0, 0, 0, 0, Victory], # 4
["Province", 8, Card.CardType.Victory, 6, 0, 0, 0, 0, Card, 12], # 6 ["Province", 8, 6, 0, 0, 0, 0, Province], # 5
["Curse", 0, Card.CardType.Curse, -1, 0, 0, 0, 0, Card, 10], # 7 ["Curse", 0, -1, 0, 0, 0, 0, Curse], # 6
["Cellar", 2, Card.CardType.Action, 0, 0, 1, 0, 0, Cellar, 10], # 8 ["Cellar", 2, 0, 0, 1, 0, 0, Cellar], # 7
["Market", 5, Card.CardType.Action, 0, 1, 1, 1, 1, Card, 10], # 9 ["Market", 5, 0, 1, 1, 1, 1, Action], # 8
["Merchant", 3, Card.CardType.Action, 0, 0, 1, 0, 1, Merchant, 10], # 10 ["Merchant", 3, 0, 0, 1, 0, 1, Merchant], # 9
["Militia", 4, Card.CardType.Attack, 0, 2, 0, 0, 0, Militia, 10], # 11 ["Militia", 4, 0, 2, 0, 0, 0, Militia], # 10
["Mine", 5, Card.CardType.Action, 0, 0, 0, 0, 0, Mine, 10], # 12 ["Mine", 5, 0, 0, 0, 0, 0, Mine], # 11
["Moat", 2, Card.CardType.Reaction, 0, 0, 0, 0, 2, Moat, 10], # 13 ["Moat", 2, 0, 0, 0, 0, 2, Moat], # 12
["Remodel", 4, Card.CardType.Action, 0, 0, 0, 0, 0, Remodel, 10], # 14 ["Remodel", 4, 0, 0, 0, 0, 0, Remodel], # 13
["Smithy", 4, Card.CardType.Action, 0, 0, 0, 0, 3, Card, 10], # 15 ["Smithy", 4, 0, 0, 0, 0, 3, Action], # 14
["Village", 3, Card.CardType.Action, 0, 0, 2, 0, 1, Card, 10], # 16 ["Village", 3, 0, 0, 2, 0, 1, Action], # 15
["Workshop", 4, Card.CardType.Action, 0, 0, 0, 0, 0, Workshop, 10]] # 17 ["Workshop", 4, 0, 0, 0, 0, 0, Workshop]] # 16
# Big Money # Big Money
# ["Adventurer", # ["Adventurer",
# ["Bureaucrat", # ["Bureaucrat",
@ -107,8 +115,8 @@ def get_card_info():
def get_starting_deck(): def get_starting_deck():
# return [["Copper", 7], ["Estate", 3]] return [["Copper", 7], ["Estate", 3]]
return [["Market", 2], ["Merchant", 2], ["Smithy", 2], ["Village", 2], ["Moat", 2]] # return [["Market", 2], ["Merchant", 2], ["Smithy", 2], ["Village", 2], ["Moat", 2]]
# return [["Militia", 4], ["Cellar", 3], ["Moat", 3]] # return [["Militia", 4], ["Cellar", 3], ["Moat", 3]]
# return [["Silver", 7], ["Merchant", 3]] # return [["Silver", 7], ["Merchant", 3]]
# return [["Copper", 4], ["Mine", 2], ["Remodel", 2], ["Workshop", 2]] # return [["Copper", 4], ["Mine", 2], ["Remodel", 2], ["Workshop", 2]]

View File

@ -1,3 +0,0 @@
<profile version="1.0">
<option name="myName" value="Default" />
</profile>

View File

@ -1,6 +1,6 @@
from player.player import Player from player.player import Player
from card.card import Card from card.basic.card_treasure import Treasure
#name943meats23jet
class Pure_Big_Money(Player): class Pure_Big_Money(Player):
def take_action(self): def take_action(self):
@ -12,7 +12,7 @@ class Pure_Big_Money(Player):
hand = self.get_hand().get_supply() hand = self.get_hand().get_supply()
for c in hand: for c in hand:
if c.get_type() == Card.CardType.Treasure: if isinstance(c, Treasure):
choice = hand.index(c) choice = hand.index(c)
print(message + str(choice)) print(message + str(choice))
@ -20,7 +20,7 @@ class Pure_Big_Money(Player):
#This method will only be called when it is time to buy things, a very simple logic will decide its action. #This method will only be called when it is time to buy things, a very simple logic will decide its action.
def get_buy_input(self, message, target_type): def get_buy_input(self, message, target_type):
coin = self._Player__purchase_power coin = self.get_coin()
choice = -1 choice = -1
if coin >= 8: if coin >= 8:
@ -39,7 +39,10 @@ class Pure_Big_Money(Player):
min_coin = self.get_hand().get_supply()[choice].get_purchase_power() min_coin = self.get_hand().get_supply()[choice].get_purchase_power()
for c in self.get_hand().get_supply(): for c in self.get_hand().get_supply():
if c.get_purchase_power() < min_coin and c.get_type() != Card.CardType.Treasure: # We want to do isinstance rather than not isinstance because we only want to evaluate this loop when we are
# evaluating an all treasure card hand as at that point the choice will be a treasure card, otherwise the
# choice will already be non-treasure and we don't need to check anything since this bot doesn't do action
if c.get_purchase_power() < min_coin and isinstance(c, Treasure):
min_coin = c.get_purchase_power() min_coin = c.get_purchase_power()
choice = self.get_hand().get_supply().index(c) choice = self.get_hand().get_supply().index(c)
@ -48,7 +51,7 @@ class Pure_Big_Money(Player):
def __get_first_non_Treasure(self): def __get_first_non_Treasure(self):
for c in self.get_hand().get_supply(): for c in self.get_hand().get_supply():
if c.get_type() != Card.CardType.Treasure: if not isinstance(c, Treasure):
return self.get_hand().get_supply().index(c) return self.get_hand().get_supply().index(c)
return 0 return 0

View File

@ -6,3 +6,9 @@ class Discard(Supply):
while self.get_remaining() > 0: while self.get_remaining() > 0:
self.transfer_top_card(deck) self.transfer_top_card(deck)
deck.shuffle() deck.shuffle()
def print(self):
if len(self.get_supply()) > 0:
print("Discard shows " + str(self.get_top_card()) + " face up.")
else:
print("Discard is empty.")

View File

@ -2,43 +2,32 @@ from table.supply import Supply
class Hand(Supply): class Hand(Supply):
def contains_one_of(self, acceptible_types): def contains_one_of(self, acceptable_class):
result = False result = False
unique_types = self.__get_unique_types() unique_class_instances = self.__get_unique_class_instances()
for at in acceptible_types: for uci in unique_class_instances:
result |= at in unique_types result |= isinstance(uci, acceptable_class)
return result return result
def get_card_type_count(self, card_type): def get_card_type_count(self, card_class):
result = 0 result = 0
for c in self._Supply__card: for c in self.get_supply():
if c.get_type() == card_type: if isinstance(c, card_class):
result += 1 result += 1
return result return result
def blocks_attack(self, what_attack): def reaction_blocks_attack(self, what_attack):
yes_no = False attack_blocked = False
found_at = -1 for c in self.get_supply():
attack_blocked |= c.react(what_attack)
return attack_blocked
for c in self._Supply__card: def __get_unique_class_instances(self):
if c.prevent_attack: unique_class_instances = list()
found_at = self._Supply__card.index(c)
if found_at >= 0: for c in self.get_supply():
owner = self._Supply__card[found_at].get_owner() if c not in unique_class_instances:
yes_no = "Y" == owner.get_general_input("Player " + str(owner.get_player_index()) + ", enter 'Y' if you'd " unique_class_instances.append(c)
"like to reveal " return unique_class_instances
+ self._Supply__card[found_at].get_name() + " to block the "
+ what_attack + " attack: ", str)
return yes_no
def __get_unique_types(self):
unique_type = list()
for c in self._Supply__card:
current_type = c.get_type()
if not current_type in unique_type:
unique_type.append(current_type)
return unique_type

View File

@ -5,5 +5,5 @@ class Human(Player):
def __str__(self): def __str__(self):
return "Player " + str(self.get_player_index()) + " (human)" return "Player " + str(self.get_player_index()) + " (human)"
def militia_input(self, message): def militia_input(self, message, target_type):
return self.get_general_input(message) return self.get_general_input(message, target_type)

View File

@ -2,7 +2,8 @@ from player.deck import Deck
from player.discard import Discard from player.discard import Discard
from player.hand import Hand from player.hand import Hand
from player.counter import Counter from player.counter import Counter
from card.card import Card from card.basic.card_treasure import Treasure
from card.basic.card_action import Action
from random import randint from random import randint
@ -41,6 +42,9 @@ class Player:
def get_player_index(self): def get_player_index(self):
return self.__table.get_players().index(self) return self.__table.get_players().index(self)
def get_coin(self):
return self.__purchase_power
def get_score(self): def get_score(self):
score = 0 score = 0
@ -99,10 +103,10 @@ class Player:
def discard_from_hand(self, n): def discard_from_hand(self, n):
self.__hand.transfer_card_by_index(n, self.__discard) self.__hand.transfer_card_by_index(n, self.__discard)
def play_card(self, acceptable_card_type, chances, counter): def play_card(self, acceptable_card_class, chances, counter):
if chances > 0 and self.__hand.contains_one_of(acceptable_card_type): if chances > 0 and self.__hand.contains_one_of(acceptable_card_class):
hand_index = self.get_play_input("\nPlease identify a card from hand to play by providing its index: ", int) hand_index = self.get_play_input("\nPlease identify a card from hand to play by providing its index: ", int)
self.__check_play_card(hand_index, counter, acceptable_card_type, chances) self.__check_play_card(hand_index, counter, acceptable_card_class, chances)
elif chances <= 0: elif chances <= 0:
print("You have used up all of your chances to enter a valid integer; forfeiting remaining plays.") print("You have used up all of your chances to enter a valid integer; forfeiting remaining plays.")
if counter is not None: if counter is not None:
@ -113,23 +117,22 @@ class Player:
counter.int = 0 counter.int = 0
def take_action(self): def take_action(self):
print("\nPlease play an Action, Attack, or Reaction card until you have no remaining actions.") print("\nPlease play an Action card until you have no remaining actions.")
while self.__actions.int > 0: while self.__actions.int > 0:
self.play_card([Card.CardType.Action, Card.CardType.Attack, Card.CardType.Reaction], self.play_card(Action, self.__std_chances, self.__actions)
self.__std_chances, self.__actions)
def take_buy(self): def take_buy(self):
if self.__hand.contains_one_of([Card.CardType.Treasure]): if self.__hand.contains_one_of(Treasure):
print("\nPlease play all Treasure card that you want to play.") print("\nPlease play all Treasure card that you want to play.")
play_another = Counter(self.__hand.get_card_type_count(Card.CardType.Treasure)) play_another = Counter(self.__hand.get_card_type_count(Treasure))
while play_another.int > 0: while play_another.int > 0:
self.play_card([Card.CardType.Treasure], self.__std_chances, play_another) self.play_card(Treasure, self.__std_chances, play_another)
self.buy_card(self.__std_chances) self.buy_card(self.__std_chances)
def buy_card(self, chances): def buy_card(self, chances):
self.__table.print() self.__table.print()
while self.__buys > 0 and not self.__table.are_there_any_empty_piles() and chances > 0: while self.__buys > 0 and not self.__table.are_there_three_empty_piles() and chances > 0:
pile_index = self.get_buy_input("\nPlease choose a pile from the table that you'd like to purchase: ", int) pile_index = self.get_buy_input("\nPlease choose a pile from the table that you'd like to purchase: ", int)
if pile_index < 0: if pile_index < 0:
@ -169,15 +172,15 @@ class Player:
print("\nPlayer " + str(self.__table.get_players().index(self)) + " Hand:") print("\nPlayer " + str(self.__table.get_players().index(self)) + " Hand:")
self.__hand.print() self.__hand.print()
def __check_play_card(self, hand_index, counter, acceptable_card_type, chances): def __check_play_card(self, hand_index, counter, acceptable_card_class, chances):
if hand_index < 0: if hand_index < 0:
print("You have elected to forfeit any remaining plays.") print("You have elected to forfeit any remaining plays.")
if counter is not None: if counter is not None:
counter.int = 0 counter.int = 0
elif hand_index >= self.__hand.get_remaining(): elif hand_index >= self.__hand.get_remaining():
print("Acceptable inputs range from 0 to " + str(self.__hand.get_remaining() - 1) + ". 1 chance lost.") print("Acceptable inputs range from 0 to " + str(self.__hand.get_remaining() - 1) + ". 1 chance lost.")
self.play_card(acceptable_card_type, chances - 1, counter) self.play_card(acceptable_card_class, chances - 1, counter)
elif self.__hand.get_card(hand_index).get_type() in acceptable_card_type: elif isinstance(self.__hand.get_card(hand_index), acceptable_card_class):
print("Player " + str(self.get_player_index()) + " playing: " + self.__hand.get_card(hand_index).get_name()) print("Player " + str(self.get_player_index()) + " playing: " + self.__hand.get_card(hand_index).get_name())
play_card = self.__hand.get_card(hand_index) play_card = self.__hand.get_card(hand_index)
play_card.play() play_card.play()
@ -187,7 +190,7 @@ class Player:
self.__print() self.__print()
else: else:
print("Index in bounds but not an acceptable card type. Chance to get it right reduced.") print("Index in bounds but not an acceptable card type. Chance to get it right reduced.")
self.play_card(acceptable_card_type, chances - 1, counter) self.play_card(acceptable_card_class, chances - 1, counter)
# The following two methods are identical under different names so they can be overridden by bot classes later # The following two methods are identical under different names so they can be overridden by bot classes later
def get_play_input(self, message, target_type): def get_play_input(self, message, target_type):
@ -232,7 +235,6 @@ class Player:
return True return True
def __print_discard(self): def __print_discard(self):
print("\nPlayer " + str(self.__table.get_players().index(self)) + " Discard:")
self.__discard.print() self.__discard.print()
def __print_deck(self): def __print_deck(self):
@ -244,8 +246,9 @@ class Player:
print("Actions: " + str(self.__actions.int)) print("Actions: " + str(self.__actions.int))
print("Buys: " + str(self.__buys)) print("Buys: " + str(self.__buys))
print("Coin: " + str(self.__purchase_power)) print("Coin: " + str(self.__purchase_power))
self.print_hand() print("Deck Remaining: " + str(self.__deck.get_remaining()))
self.__print_discard() self.__print_discard()
self.print_hand()
print("") print("")
def __turn_setup(self): def __turn_setup(self):

View File

@ -1,5 +1,6 @@
from table.supply import Supply from table.supply import Supply
class Pile(Supply): class Pile(Supply):
def __init__(self, card): def __init__(self, card):
self.__card_group = card self.__card_group = card

View File

@ -43,7 +43,8 @@ class Supply:
return self.__card[n] return self.__card[n]
def get_top_card(self): def get_top_card(self):
return self.__card[len(self.__card) - 1] if len(self.__card) > 0:
return self.__card[len(self.__card) - 1]
def get_remaining(self): def get_remaining(self):
return len(self.__card) return len(self.__card)

View File

@ -1,5 +1,6 @@
from table.trash import Trash from table.trash import Trash
from table.pile import Pile from table.pile import Pile
from card.named.province import Province
class Table: class Table:
@ -45,22 +46,34 @@ class Table:
result = self.__pile.index(p) result = self.__pile.index(p)
return result return result
def are_there_any_empty_piles(self): def are_there_three_empty_piles(self):
result = False count = 0
for p in self.__pile: for p in self.__pile:
result = result or p.get_remaining() == 0 if p.get_remaining() == 0:
return result count += 1
return count > 2
def has_provinces_run_out(self):
for p in self.__pile:
if isinstance(p.get_card_group(), Province):
return p.get_remaining() == 0
return False
def should_game_end(self):
return self.are_there_three_empty_piles() or self. has_provinces_run_out()
def play(self): def play(self):
turn = 0 player_turn = 0
# turn < 10 is for testing, otherwise endless as buying card is not yet done should_continue = True
while not self.are_there_any_empty_piles(): # and turn < 10: while should_continue:
# game ends after
should_continue = not self.should_game_end() or player_turn % len(self.__player) != 0
self.print() self.print()
self.__player[turn % len(self.__player)].take_turn() self.__player[player_turn % len(self.__player)].take_turn()
turn += 1 player_turn += 1
else: else:
self.print() self.print()
print("\n\nGame had " + str(turn) + " turns in " + str(turn/len(self.__player)) + " rounds.") print("\n\nGame had " + str(player_turn) + " turns in " + str(player_turn/len(self.__player)) + " rounds.")
for p in self.__player: for p in self.__player:
print("" + str(p) + " scored " + str(p.get_score()) + " points.") print("" + str(p) + " scored " + str(p.get_score()) + " points.")
if p.get_score() > self.__winning_score: if p.get_score() > self.__winning_score:

View File

@ -1,5 +0,0 @@
<application>
<component name="UISettings">
<option name="HIDE_TOOL_STRIPES" value="false" />
</component>
</application>