mirror of
https://github.com/neogeek23/Dominion-Strategy-Simulator.git
synced 2026-02-04 11:08:18 +00:00
Add files via upload
Generalized out attack cards. Fixed bugs.
This commit is contained in:
parent
03fb263288
commit
e3ff6416ff
@ -2,4 +2,10 @@ from card.basic.card_kingdom import Kingdom
|
|||||||
|
|
||||||
|
|
||||||
class Attack(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
|
pass
|
||||||
|
|||||||
@ -1,10 +1,10 @@
|
|||||||
from card.card import Card
|
from card.basic.card_victory import Victory
|
||||||
|
|
||||||
|
|
||||||
class Curse(Card):
|
class Curse(Victory):
|
||||||
@staticmethod
|
@classmethod
|
||||||
def pile_setup(player_count):
|
def pile_setup(cls, player_count):
|
||||||
if player_count % Card.normal_full_table < Card.normal_full_table/2:
|
if player_count % cls.normal_full_table < cls.normal_full_table/2:
|
||||||
return Card.pile_player_rate
|
return Victory.pile_player_rate
|
||||||
else:
|
else:
|
||||||
return (player_count - 1) * Card.pile_player_rate
|
return (player_count - 1) * cls.pile_player_rate
|
||||||
|
|||||||
@ -5,6 +5,6 @@ from math import floor
|
|||||||
class Kingdom(Card):
|
class Kingdom(Card):
|
||||||
pile_player_rate = 10
|
pile_player_rate = 10
|
||||||
|
|
||||||
@staticmethod
|
@classmethod
|
||||||
def pile_setup(player_count):
|
def pile_setup(cls, player_count):
|
||||||
return (floor(player_count/Card.normal_full_table) + 1) * Card.pile_player_rate
|
return (floor(player_count/cls.normal_full_table) + 1) * cls.pile_player_rate
|
||||||
|
|||||||
@ -5,4 +5,4 @@ from math import floor
|
|||||||
class Treasure(Card):
|
class Treasure(Card):
|
||||||
@classmethod
|
@classmethod
|
||||||
def pile_setup(cls, player_count):
|
def pile_setup(cls, player_count):
|
||||||
return (floor(player_count/Card.normal_full_table) + 1) * cls.pile_player_rate
|
return (floor(player_count/cls.normal_full_table) + 1) * cls.pile_player_rate
|
||||||
|
|||||||
@ -1,5 +1,4 @@
|
|||||||
class Card:
|
class Card:
|
||||||
prevent_attack = False
|
|
||||||
normal_full_table = 6
|
normal_full_table = 6
|
||||||
pile_player_rate = 10
|
pile_player_rate = 10
|
||||||
|
|
||||||
@ -24,6 +23,9 @@ 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 react(self, what_attack):
|
||||||
|
return False
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def pile_setup(cls, player_count):
|
def pile_setup(cls, player_count):
|
||||||
# This is here so that each card can override this function so that the right number of .
|
# This is here so that each card can override this function so that the right number of .
|
||||||
|
|||||||
@ -4,12 +4,10 @@ from random import randint
|
|||||||
|
|
||||||
|
|
||||||
class Militia(Action, Attack):
|
class Militia(Action, Attack):
|
||||||
def effect(self):
|
def attack(self, player):
|
||||||
for player in self._Card__owner.get_table().get_players():
|
|
||||||
if self._Card__owner != player and not player.get_hand().blocks_attack(self.get_name()):
|
|
||||||
player.print_hand()
|
player.print_hand()
|
||||||
print("Player " + str(player.get_player_index()) + ", you MUST discard down to 3 card.")
|
print("Player " + str(player.get_player_index()) + ", you MUST discard down to 3 card.")
|
||||||
self.__force_discard(self._Card__owner.get_std_chances(), player)
|
self.__force_discard(self.get_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:
|
||||||
@ -17,16 +15,17 @@ class Militia(Action, Attack):
|
|||||||
" 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)
|
||||||
|
|||||||
@ -3,4 +3,8 @@ from card.basic.card_reaction import Reaction
|
|||||||
|
|
||||||
|
|
||||||
class Moat(Action, Reaction):
|
class Moat(Action, Reaction):
|
||||||
prevent_attack = True
|
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
5
card/named/province.py
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
from card.basic.card_victory import Victory
|
||||||
|
|
||||||
|
|
||||||
|
class Province(Victory):
|
||||||
|
pass
|
||||||
5
game.py
5
game.py
@ -4,6 +4,7 @@ from player.bots.pure_big_money import Pure_Big_Money
|
|||||||
from card.basic.card_action import Action
|
from card.basic.card_action import Action
|
||||||
from card.basic.card_curse import Curse
|
from card.basic.card_curse import Curse
|
||||||
from card.basic.card_victory import Victory
|
from card.basic.card_victory import Victory
|
||||||
|
from card.named.province import Province
|
||||||
from card.named.estate import Estate
|
from card.named.estate import Estate
|
||||||
from card.named.copper import Copper
|
from card.named.copper import Copper
|
||||||
from card.named.silver import Silver
|
from card.named.silver import Silver
|
||||||
@ -65,7 +66,7 @@ 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():
|
||||||
@ -76,7 +77,7 @@ def get_card_info():
|
|||||||
["Gold", 6, 0, 3, 0, 0, 0, Gold], # 2
|
["Gold", 6, 0, 3, 0, 0, 0, Gold], # 2
|
||||||
["Estate", 2, 1, 0, 0, 0, 0, Estate], # 3
|
["Estate", 2, 1, 0, 0, 0, 0, Estate], # 3
|
||||||
["Dutchy", 5, 3, 0, 0, 0, 0, Victory], # 4
|
["Dutchy", 5, 3, 0, 0, 0, 0, Victory], # 4
|
||||||
["Province", 8, 6, 0, 0, 0, 0, Victory], # 5
|
["Province", 8, 6, 0, 0, 0, 0, Province], # 5
|
||||||
["Curse", 0, -1, 0, 0, 0, 0, Curse], # 6
|
["Curse", 0, -1, 0, 0, 0, 0, Curse], # 6
|
||||||
["Cellar", 2, 0, 0, 1, 0, 0, Cellar], # 7
|
["Cellar", 2, 0, 0, 1, 0, 0, Cellar], # 7
|
||||||
["Market", 5, 0, 1, 1, 1, 1, Action], # 8
|
["Market", 5, 0, 1, 1, 1, 1, Action], # 8
|
||||||
|
|||||||
@ -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:
|
||||||
|
|||||||
@ -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.")
|
||||||
|
|||||||
@ -18,20 +18,11 @@ class Hand(Supply):
|
|||||||
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():
|
for c in self.get_supply():
|
||||||
if c.prevent_attack:
|
attack_blocked |= c.react(what_attack)
|
||||||
found_at = self.get_supply().index(c)
|
return attack_blocked
|
||||||
|
|
||||||
if found_at >= 0:
|
|
||||||
owner = self.get_supply()[found_at].get_owner()
|
|
||||||
yes_no = "Y" == owner.get_general_input("Player " + str(owner.get_player_index()) + ", enter 'Y' if you'd "
|
|
||||||
"like to reveal " + self.get_supply()[found_at].get_name() +
|
|
||||||
" to block the " + what_attack + " attack: ", str)
|
|
||||||
return yes_no
|
|
||||||
|
|
||||||
def __get_unique_class_instances(self):
|
def __get_unique_class_instances(self):
|
||||||
unique_class_instances = list()
|
unique_class_instances = list()
|
||||||
|
|||||||
@ -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)
|
||||||
|
|||||||
@ -42,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
|
||||||
|
|
||||||
@ -129,7 +132,7 @@ class Player:
|
|||||||
|
|
||||||
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:
|
||||||
@ -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):
|
||||||
|
|||||||
@ -43,6 +43,7 @@ class Supply:
|
|||||||
return self.__card[n]
|
return self.__card[n]
|
||||||
|
|
||||||
def get_top_card(self):
|
def get_top_card(self):
|
||||||
|
if len(self.__card) > 0:
|
||||||
return self.__card[len(self.__card) - 1]
|
return self.__card[len(self.__card) - 1]
|
||||||
|
|
||||||
def get_remaining(self):
|
def get_remaining(self):
|
||||||
|
|||||||
@ -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:
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user