From 447e8b88c17f48bc05447faa66290908a4591dc9 Mon Sep 17 00:00:00 2001 From: kohrlund <39636053+kohrlund@users.noreply.github.com> Date: Sun, 5 Jan 2020 14:38:16 -0600 Subject: [PATCH 01/13] Create project file --- projects/ohrlundk | 1 + 1 file changed, 1 insertion(+) create mode 100644 projects/ohrlundk diff --git a/projects/ohrlundk b/projects/ohrlundk new file mode 100644 index 0000000..8b13789 --- /dev/null +++ b/projects/ohrlundk @@ -0,0 +1 @@ + From 0054cc5edd65ac183815ca0c3d3444edea849040 Mon Sep 17 00:00:00 2001 From: kohrlund <39636053+kohrlund@users.noreply.github.com> Date: Sun, 5 Jan 2020 16:19:59 -0600 Subject: [PATCH 02/13] Delete ohrlundk --- projects/ohrlundk | 1 - 1 file changed, 1 deletion(-) delete mode 100644 projects/ohrlundk diff --git a/projects/ohrlundk b/projects/ohrlundk deleted file mode 100644 index 8b13789..0000000 --- a/projects/ohrlundk +++ /dev/null @@ -1 +0,0 @@ - From 57f47f967bedcb8a71e5d411b780af2df26d1776 Mon Sep 17 00:00:00 2001 From: kohrlund <39636053+kohrlund@users.noreply.github.com> Date: Sun, 5 Jan 2020 16:20:33 -0600 Subject: [PATCH 03/13] Create testfile --- projects/ohrlundk/testfile | 1 + 1 file changed, 1 insertion(+) create mode 100644 projects/ohrlundk/testfile diff --git a/projects/ohrlundk/testfile b/projects/ohrlundk/testfile new file mode 100644 index 0000000..8b13789 --- /dev/null +++ b/projects/ohrlundk/testfile @@ -0,0 +1 @@ + From 6484800a322638a7adcf6d46048e75e0ef4f007b Mon Sep 17 00:00:00 2001 From: kohrlund <39636053+kohrlund@users.noreply.github.com> Date: Sun, 5 Jan 2020 16:21:23 -0600 Subject: [PATCH 04/13] Delete testfile --- projects/ohrlundk/testfile | 1 - 1 file changed, 1 deletion(-) delete mode 100644 projects/ohrlundk/testfile diff --git a/projects/ohrlundk/testfile b/projects/ohrlundk/testfile deleted file mode 100644 index 8b13789..0000000 --- a/projects/ohrlundk/testfile +++ /dev/null @@ -1 +0,0 @@ - From 5b0b9dcb1fe9cb9874f97c0632bdfa04fd5aec9b Mon Sep 17 00:00:00 2001 From: kohrlund <39636053+kohrlund@users.noreply.github.com> Date: Sun, 5 Jan 2020 16:30:48 -0600 Subject: [PATCH 05/13] Create somefile --- projects/ohrlundk/somefile | 1 + 1 file changed, 1 insertion(+) create mode 100644 projects/ohrlundk/somefile diff --git a/projects/ohrlundk/somefile b/projects/ohrlundk/somefile new file mode 100644 index 0000000..8b13789 --- /dev/null +++ b/projects/ohrlundk/somefile @@ -0,0 +1 @@ + From dec28016dc460aed21c26bd2f60361d5d971b6ce Mon Sep 17 00:00:00 2001 From: kohrlund <39636053+kohrlund@users.noreply.github.com> Date: Sun, 5 Jan 2020 16:31:20 -0600 Subject: [PATCH 06/13] Add files via upload --- projects/ohrlundk/CS362-W2020-master.zip | Bin 0 -> 29252 bytes 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 projects/ohrlundk/CS362-W2020-master.zip diff --git a/projects/ohrlundk/CS362-W2020-master.zip b/projects/ohrlundk/CS362-W2020-master.zip new file mode 100644 index 0000000000000000000000000000000000000000..fe37a746ecaa8c21bdfdeec2479aad706c40d2d5 GIT binary patch literal 29252 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 Date: Sun, 5 Jan 2020 16:34:33 -0600 Subject: [PATCH 07/13] Create somefile --- projects/ohrlundk/dominion/somefile | 1 + 1 file changed, 1 insertion(+) create mode 100644 projects/ohrlundk/dominion/somefile diff --git a/projects/ohrlundk/dominion/somefile b/projects/ohrlundk/dominion/somefile new file mode 100644 index 0000000..8b13789 --- /dev/null +++ b/projects/ohrlundk/dominion/somefile @@ -0,0 +1 @@ + From 9583b42635d6993ddfd539efae5fd897838c16e2 Mon Sep 17 00:00:00 2001 From: kohrlund <39636053+kohrlund@users.noreply.github.com> Date: Sun, 5 Jan 2020 16:35:24 -0600 Subject: [PATCH 08/13] Add files via upload --- projects/ohrlundk/dominion/Dominion.py | 762 ++++++++++++++++++ projects/ohrlundk/dominion/README.md | 10 + projects/ohrlundk/dominion/REPLdominion.py | 853 +++++++++++++++++++++ projects/ohrlundk/dominion/playDominion.py | 119 +++ 4 files changed, 1744 insertions(+) create mode 100644 projects/ohrlundk/dominion/Dominion.py create mode 100644 projects/ohrlundk/dominion/README.md create mode 100644 projects/ohrlundk/dominion/REPLdominion.py create mode 100644 projects/ohrlundk/dominion/playDominion.py diff --git a/projects/ohrlundk/dominion/Dominion.py b/projects/ohrlundk/dominion/Dominion.py new file mode 100644 index 0000000..6a0a534 --- /dev/null +++ b/projects/ohrlundk/dominion/Dominion.py @@ -0,0 +1,762 @@ +# -*- coding: utf-8 -*- +""" +Created on Tue Oct 13 15:26:55 2015 + +@author: tfleck +""" +import random +from collections import Counter, OrderedDict +from operator import itemgetter +import re +import pandas + +class Card(): + def __init__(self,name,category,cost,buypower,vpoints): + self.name = name + self.category = category + self.cost = cost + self.buypower = buypower + self.vpoints = vpoints + def react(self,player): + return False + +class Coin_card(Card): + def __init__(self,name,cost,buypower): + Card.__init__(self,name,"coin",cost,buypower,0) + +class Copper(Coin_card): + def __init__(self): + Coin_card.__init__(self,"Copper",0,1) + +class Silver(Coin_card): + def __init__(self): + Coin_card.__init__(self,"Silver",3,2) + +class Gold(Coin_card): + def __init__(self): + Coin_card.__init__(self,"Gold",6,3) + +class Victory_card(Card): + def __init__(self,name,cost,vpoints): + Card.__init__(self,name,"victory",cost,0,vpoints) + +class Estate(Victory_card): + def __init__(self): + Victory_card.__init__(self,"Estate",2,1) + +class Duchy(Victory_card): + def __init__(self): + Victory_card.__init__(self,"Duchy",5,3) + +class Province(Victory_card): + def __init__(self): + Victory_card.__init__(self,"Province",8,6) + +class Gardens(Victory_card): + def __init__(self): + Victory_card.__init__(self,"Gardens",4,0) + +class Curse(Card): + def __init__(self): + Card.__init__(self,"Curse","curse",0,0,-1) + +class Action_card(Card): + def __init__(self,name,cost,actions,cards,buys,coins): + Card.__init__(self,name,"action",cost,0,0) + self.actions = actions + self.cards = cards + self.buys = buys + self.coins = coins + def use(self,player,trash): + player.played.append(self) + player.hand.remove(self) + def augment(self,player): + player.actions+=self.actions + player.buys+=self.buys + player.purse+=self.coins + for i in range(self.cards): + player.draw() + def play(self,player,players,supply,trash): + pass + +class Woodcutter(Action_card): + def __init__(self): + Action_card.__init__(self,"Woodcutter",3,0,0,1,2) + +class Smithy(Action_card): + def __init__(self): + Action_card.__init__(self,"Smithy",4,0,3,0,0) + +class Laboratory(Action_card): + def __init__(self): + Action_card.__init__(self,"Laboratory",5,1,2,0,0) + +class Village(Action_card): + def __init__(self): + Action_card.__init__(self,"Village",3,2,1,0,0) + +class Festival(Action_card): + def __init__(self): + Action_card.__init__(self,"Festival",5,2,0,1,2) + +class Market(Action_card): + def __init__(self): + Action_card.__init__(self,"Market",5,1,1,1,1) + +class Chancellor(Action_card): + def __init__(self): + Action_card.__init__(self,"Chancellor",3,0,0,0,2) + def play(self,player,players,supply,trash): + if player.yesnoinput('Would you like to discard your entire deck?'): + player.discard = player.discard + player.deck + player.deck = [] + +class Workshop(Action_card): + def __init__(self): + Action_card.__init__(self,"Workshop",3,0,0,0,0) + def play(self,player,players,supply,trash): + player.gaincard(supply,4) + +class Moneylender(Action_card): + def __init__(self): + Action_card.__init__(self,"Moneylender",4,0,0,0,0) + def play(self,player,players,supply,trash): + c = getcard("Copper",supply,player.hand,"your hand") + if c: + trash.append(c) + player.hand.remove(c) + player.purse += 3 + +class Chapel(Action_card): + def __init__(self): + Action_card.__init__(self,"Chapel",2,0,0,0,0) + def play(self,player,players,supply,trash): + trashed=0 + while trashed<4 and len(player.hand)>0: + trashcard = input("Choose a card from your hand to trash: ") + if not trashcard: + break + c = getcard(trashcard,supply,player.hand,"your hand") + if c: + trash.append(c) + player.hand.remove(c) + trashed+=1 + +class Cellar(Action_card): + def __init__(self): + Action_card.__init__(self,"Cellar",2,1,0,0,0) + def play(self,player,players,supply,trash): + discarded=0 + while len(player.hand)>0: + dis_card=input("Choose a card from your hand to discard: ") + if not dis_card: + break + c = getcard(dis_card,supply,player.hand,"your hand") + if c: + player.discard.append(c) + player.hand.remove(c) + discarded+=1 + for j in range(discarded): + player.draw() + +class Remodel(Action_card): + def __init__(self): + Action_card.__init__(self,"Remodel",4,0,0,0,0) + def play(self,player,players,supply,trash): + while len(player.hand)>0: + this_card = input("Choose a card from your hand to remodel: ") + c = getcard(this_card,supply,player.hand,"your hand") + if c: + trash.append(c) + player.hand.remove(c) + player.gaincard(supply,c.cost+2) + break + +class Adventurer(Action_card): + def __init__(self): + Action_card.__init__(self,"Adventurer",6,0,0,0,0) + def play(self,player,players,supply,trash): + coins_added = 0 + while (player.deck or player.discard) and coins_added <2: + player.draw() + if player.hand[-1].category == "coin": + coins_added +=1 + else: + player.aside.append(player.hand.pop()) + +class Feast(Action_card): + def __init__(self): + Action_card.__init__(self,"Feast",4,0,0,0,0) + def use(self,player,trash): + trash.append(self) + player.hand.remove(self) + def play(self,player,players,supply,trash): + player.gaincard(supply,5) + +class Mine(Action_card): + def __init__(self): + Action_card.__init__(self,"Mine",5,0,0,0,0) + def play(self,player,players,supply,trash): + while "coin" in catinlist(player.hand): + this_card = input("Choose a coin from your hand to upgrade: ") + c = getcard(this_card,supply,player.hand,"your hand",["coin"]) + if c: + trash.append(c) + player.hand.remove(c) + while c.cost>2 or len(supply["Copper"])>0 or len(supply["Silver"])>0: + pick = input("Choose a coin to gain. Any coin up to " + str(c.cost+3)+": ") + g = getcard(pick,supply,categories=["coin"],upto=c.cost+3) + if g: + player.hand.append(g) + supply[pick].remove(g) + break + break + +class Library(Action_card): + def __init__(self): + Action_card.__init__(self,"Library",5,0,0,0,0) + def play(self,player,players,supply,trash): + while (player.deck or player.discard) and len(player.hand) <7: + player.draw(player.hold) + if (player.hold[-1].category == "action" and not player.yesnoinput("You drew " + player.hold[-1].name + ". Would you like to keep it?",", add to my hand", ", set it aside")): + player.aside.append(player.hold.pop()) + else: + player.hand.append(player.hold.pop()) + +class Moat(Action_card): + def __init__(self): + Action_card.__init__(self,"Moat",2,0,2,0,0) + def react(self,player): + player.show() + return player.yesnoinput(player.name + ", you have a " + self.name + + " in your hand. Do you want to block the attack?") + +class Council_Room(Action_card): + def __init__(self): + Action_card.__init__(self,"Council Room",5,0,3,1,0) + def play(self,this_player,players,supply,trash): + for player in players: + player.draw() + +class Witch(Action_card): + def __init__(self): + Action_card.__init__(self,"Witch",5,0,2,0,0) + def play(self,this_player,players,supply,trash): + if len(supply["Curse"])>0: + for player in players: + if player==this_player: + pass + else: + for c in player.hand: + if c.react(player): + break + else: + if len(supply["Curse"])>0: + player.discard.append(supply["Curse"].pop()) + +class Bureaucrat(Action_card): + def __init__(self): + Action_card.__init__(self,"Bureaucrat",4,0,0,0,0) + def play(self,this_player,players,supply,trash): + if len(supply["Silver"])>0: + this_player.deck.insert(0,supply["Silver"].pop()) + for player in players: + if (not player==this_player) and ("victory" in catinlist(player.hand)): + for c in player.hand: + if c.react(player): + break + else: + player.show() + while True: + putback = player.choose_discard(player.name + ", which victory card" + + " do you want to put on top of your deck?\n--> ") + c = getcard(putback,supply,player.hand,"your hand",["victory"]) + if c: + player.hand.remove(c) + player.deck.insert(0,c) + break + +class Militia(Action_card): + def __init__(self): + Action_card.__init__(self,"Militia",4,0,0,0,2) + def play(self,this_player,players,supply,trash): + for player in players: + if (not player==this_player) and len(player.hand)>3: + for c in player.hand: + if c.react(player): + break + else: + player.show() + while len(player.hand)>3: + dis_card=player.choose_discard(player.name + ", choose a card from your hand to discard: ") + if dis_card: + c = getcard(dis_card,supply,player.hand,"your hand") + if c: + player.hand.remove(c) + player.discard.append(c) + +class Spy(Action_card): + def __init__(self): + Action_card.__init__(self,"Spy",4,1,1,0,0) + def play(self,this_player,players,supply,trash): + for player in players: + for c in player.hand: + if c.react(player): + break + else: + b = player.draw([]) + if not b: + continue + else: + print("The first card in the deck of " + player.name + " is " + b.name) + if this_player.yesnoinput(this_player.name + ", do you want " + player.name + " to discard this?", + ", discard",", keep"): + player.discard.append(b) + else: + player.deck.insert(0,b) + #check logic of this structure + +class Thief(Action_card): + def __init__(self): + Action_card.__init__(self,"Thief",4,0,0,0,0) + def play(self,this_player,players,supply,trash): + for player in players: + if player == this_player: + continue + for c in player.hand: + if c.react(player): + break + else: + for i in range(2): + player.draw(player.hold) + print( player.name, namesinlist(player.hold)) + if "coin" in catinlist(player.hold): + while True: + burn = input("Which card would you like " + player.name + " to trash?\n-->") + c = getcard(burn,supply,player.hold," the top 2 cards",["coin"]) + if c: + player.hold.remove(c) + break + if this_player.yesnoinput("Do you want to steal it?",", it's mine!",", leave it in the trash."): + this_player.discard.append(c) + else: + trash.append(c) + player.discard=player.discard+player.hold + player.hold = [] + +class Throne_Room(Action_card): + def __init__(self): + Action_card.__init__(self,"Throne Room",4,0,0,0,0) + def play(self,player,players,supply,trash): + if "action" in catinlist(player.hand): + while True: + double = input("What card would you like to double?\n--> ") + c = getcard(double,supply,player.hand," your hand",["action"]) + if c: + c.use(player,trash) + c.augment(player) + c.play(player,players,supply,trash) + player.show() + c.augment(player) + c.play(player,players,supply,trash) + break + + +class Player(): + def __init__(self,name): + self.name = name + self.hand = [] + self.deck = [Copper()]*7 + [Estate()]*3 + random.shuffle(self.deck) + self.played = [] + self.discard = [] + self.aside = [] + self.hold = [] + for i in range(5): + self.draw() + + def other(self): + return self.played+self.discard+self.hold+self.aside + def stack(self): + return (self.deck + self.hand + self.played + self.discard + self.aside + self.hold) + def draw(self,dest=None): + #defualt destination is player's hand + if dest==None: + dest = self.hand + #Replenish deck if necessary. + if len(self.deck)==0: + self.deck = self.discard + self.discard = [] + random.shuffle(self.deck) + #If deck has cards, add card to destination list + if len(self.deck)>0: + c = self.deck.pop(0) + dest.append(c) + return c + def turn(self,players,supply,trash): + self.show() + self.actions = 1 + self.buys = 1 + self.purse = 0 + #action phase + while self.actions>0 and 'action' in catinlist(self.hand): + playthis = input("Which card would you like to play? You have " + + str(self.actions) + " action(s). \n-Hit enter for no play. --> ") + if playthis: + c = getcard(playthis,supply,self.hand,"your hand",['action']) + if c: + self.actions = self.actions - 1 + c.use(self,trash) + c.augment(self) + c.play(self,players,supply,trash) + self.show() + else: + self.actions=0 + #buy phase + for c in self.hand: + self.purse += c.buypower + while self.buys>0: + buy_string = "Buying power is " + str(self.purse) + ". You have " + str(self.buys) + " buy" + if self.buys>1: + buy_string += "s" + buy_string += "." + print( buy_string) + purchase = input("What would you like to purchase? -Hit enter for no purchase.-\n--> ") + if not purchase: + break + else: + c = getcard(purchase,supply,upto=self.purse) + if c: + self.discard.append(supply[purchase].pop()) + self.buys = self.buys -1 + self.purse = self.purse - c.cost + + #cleanup phase + self.discard = self.discard + self.played + self.hand + self.aside + self.played = [] + self.hand = [] + self.aside = [] + for i in range(5): + self.draw() + + def gaincard(self,supply,upto): + while True: + gain = input("What would you like to get? Any card up to " + str(upto) + "\n--> ") + c = getcard(gain,supply,upto=upto) + if c: + self.discard.append(c) + supply[gain].remove(c) + break + def yesnoinput(self,prompt,yesstring='',nostring=''): + print(prompt + "\n1 - Yes" + yesstring + "\n0 - No" + nostring) + while True: + r = input("--> ") + if r == "0": + return False + if r == "1": + return True + + def choose_discard(self,prompt): + return input(prompt) + + def show(self): + print (self.name) + print ("hand:", ", ".join(sorted(namesinlist(self.hand)))) + if len(self.deck)>0: + print ("deck (alphabetical order):", ", ".join(sorted(namesinlist(self.deck)))) + if len(self.discard)>0: + print ("discard:", ", ".join(sorted(namesinlist(self.discard)))) + if len(self.played)>0: + print ("played:", ", ".join(sorted(namesinlist(self.played)))) + if len(self.aside)>0: + print ("aside:", ", ".join(sorted(namesinlist(self.aside)))) + print ("\r") + + def action_balance(self): + balance = 0 + for c in self.stack(): + if c.category == "action": + balance = balance - 1 + c.actions + return 70*balance / len(self.stack()) + + def cardsummary(self): + summary = {} + for c in self.stack(): + if c.name in summary: + summary[c.name] += 1 + else: + summary[c.name] = 1 + summary['VICTORY POINTS']=self.calcpoints() + return summary + + def calcpoints(self): + tally = 0 + gardens = 0 + n = 0 + for c in self.stack(): + tally += c.vpoints + n += 1 + if c.name == "Gardens": + gardens+=1 + return tally + n//10 * gardens + +class ComputerPlayer(Player): + def __init__(self,name): + Player.__init__(self,name) + self.index = 0 + self.buygaintable = [] + #beginning and middle of game + self.buygaintable1 = ["Province","Gold","Laboratory","Festival","Witch", + "Council Room","Market","Militia","Adventurer","Smithy","Bureaucrat","Silver","Moat",""] + #end of game + self.buygaintable2 = ["Province","Gardens","Duchy","Estate","Gold","Silver",""] + #beginning and middle of the game, too many action cards + self.buygaintable3 = ["Province","Gold","Festival","Laboratory","Market","Village", + "Silver",""] + self.playtable1 = ["Village","Festival","Market","Laboratory","Witch", + "Council Room","Militia","Adventurer","Smithy","Bureaucrat","Moat",""] + self.discardtable1 = ["Gardens","Duchy","Province","Estate","Curse","Copper", + "Village","Bureaucrat","Silver","Militia","Smithy","Council Room","Witch", + "Festival","Market","Adventurer","Laboratory","Gold","Moat"] + + def turn(self,players,supply,trash): + self.show() + self.actions = 1 + self.buys = 1 + self.purse = 0 + #action phase + self.index = 0 + while self.actions>0 and 'action' in catinlist(self.hand): + playthis = self.playtable1[self.index] + if playthis: + c = self.getcard(playthis,supply,self.hand,"your hand",['action']) + if c: + print (self.name + " plays " + c.name) + self.actions = self.actions - 1 + c.use(self,trash) + self.index=0 + c.augment(self) + c.play(self,players,supply,trash) + self.show() + else: + self.index += 1 + else: + self.actions=0 + #buy phase + if len(supply["Province"])>len(players)+totalbuypower(self.deck)/8: + if self.action_balance()<-10: + self.buygaintable = self.buygaintable3 + else: + self.buygaintable = self.buygaintable1 + else: + self.buygaintable = self.buygaintable2 + self.index = 0 + for c in self.hand: + self.purse += c.buypower + while self.buys>0: + purchase = self.buygaintable[self.index] + if not purchase: + break + else: + c = self.getcard(purchase,supply,upto=self.purse) + if c: + self.discard.append(supply[purchase].pop()) + self.index = 0 + self.buys = self.buys -1 + self.purse = self.purse - c.cost + print (self.name + " bought " + c.name) + else: + self.index += 1 + + #cleanup phase + self.discard = self.discard + self.played + self.hand + self.aside + self.played = [] + self.hand = [] + self.aside = [] + for i in range(5): + self.draw() + + def getcard(self,name,supply,target_list=None,target_name= "the supply anymore",categories=['action','coin','curse','victory'],upto=100): + if not name in supply: + #print name + " is not in this game." + return None + if not target_list: + target_list = supply[name] + nameslist = namesinlist(target_list) + if not name in nameslist: + #print "There is no " + name + " in " + target_name + return None + i = nameslist.index(name) + c = target_list[i] + if c.category not in categories: + catstring = categories[0] + for i in categories[1:]: + catstring = catstring + " or " + categories[i] + #print name + " is not a " + catstring + " card." + return None + if c.cost > upto: + #print name + " costs " + str(c.cost) + return None + return c + + def choose_discard(self,prompt): + index = 0 + while True: + dis_card = self.discardtable1[index] + c = self.getcard(dis_card,[dis_card],self.hand) + if c: + return c.name + else: + index+=1 + + def yesnoinput(self,prompt,yesstring='',nostring=''): + return True + + def show(self): + pass + +class TablePlayer(ComputerPlayer): + def __init__(self,name): + ComputerPlayer.__init__(self,name) + self.index=0 + self.buygaintable=[] + q=re.match(r'([a-zA-Z]+)(\d+)',name) + if q: + self.number = q.group(2) + else: + print(name) + self.playtable1 = ["Village","Festival","Market","Laboratory","Witch", + "Council Room","Militia","Adventurer","Smithy","Bureaucrat","Moat",""] + self.discardtable1 = ["Gardens","Duchy","Province","Estate","Curse","Copper", + "Village","Bureaucrat","Silver","Militia","Smithy","Council Room","Witch", + "Festival","Market","Adventurer","Laboratory","Gold","Moat"] + + def turn(self,players,supply,trash): + self.show() + self.actions = 1 + self.buys = 1 + self.purse = 0 + #action phase + self.index = 0 + while self.actions>0 and 'action' in catinlist(self.hand): + playthis = self.playtable1[self.index] + if playthis: + c = self.getcard(playthis,supply,self.hand,"your hand",['action']) + if c: + #print (self.name + " plays " + c.name) + self.actions = self.actions - 1 + c.use(self,trash) + self.index=0 + c.augment(self) + c.play(self,players,supply,trash) + self.show() + else: + self.index += 1 + else: + self.actions=0 + #buy phase + v= self.number + csvstring = r"Dominionbuy" + str(v) + ".csv" + buydf=pandas.read_csv(csvstring,na_filter=False) + sortedbuydf=buydf.sort_values("Buyvalues",ascending=False) + ranktable = sortedbuydf.Cardname + self.index = 0 + for c in self.hand: + self.purse += c.buypower + while self.buys>0: + purchase = ranktable.iloc[self.index] + if not purchase: + break + else: + c = self.getcard(purchase,supply,upto=self.purse) + if c: + self.discard.append(supply[purchase].pop()) + self.index = 0 + self.buys = self.buys -1 + self.purse = self.purse - c.cost + else: + self.index += 1 + + #cleanup phase + self.discard = self.discard + self.played + self.hand + self.aside + self.played = [] + self.hand = [] + self.aside = [] + for i in range(5): + self.draw() + + +def gameover(supply): + if len(supply["Province"])==0: + return True + out = 0 + for stack in supply: + if len(supply[stack])==0: + out+=1 + if out>=3: + return True + return False + +def namesinlist(cardlist): + namelist = [] + for c in cardlist: + namelist.append(c.name) + return namelist + +def catinlist(cardlist): + catlist = [] + for c in cardlist: + catlist.append(c.category) + return catlist + +def getcard(name,supply,target_list=None,target_name= "the supply anymore",categories=['action','coin','curse','victory'],upto=100): + if not name in supply: + print( name + " is not in this game.") + return None + if not target_list: + target_list = supply[name] + nameslist = namesinlist(target_list) + if not name in nameslist: + print ("There is no " + name + " in " + target_name) + return None + i = nameslist.index(name) + c = target_list[i] + if c.category not in categories: + catstring = categories[0] + for i in categories[1:]: + catstring = catstring + " or " + categories[i] + print (name + " is not a " + catstring + " card.") + return None + if c.cost > upto: + print (name + " costs " + str(c.cost)) + return None + return c + +def totalbuypower(cardlist): + TBP = 0 + for c in cardlist: + TBP += c.buypower + if c.category == "action": + TBP += c.coins + return TBP + +def cardsummaries(players): + cardsums={} + for player in players: + cardsums[player.name]=player.cardsummary() + cardsdf = pandas.DataFrame(cardsums).fillna(0).sort_index() + vp=cardsdf.loc[['VICTORY POINTS']] + cardsdf.drop(['VICTORY POINTS'],inplace=True) + return pandas.concat([cardsdf,vp],axis=0).fillna(0).astype(int) + +def countsupply(supply,form): + return [len(supply[a]) for a in form] + +def countcards(cards,form): + dcount = Counter(namesinlist(cards)) + return [dcount[a] for a in form] + +def rankcards(form,vector): + od = OrderedDict(zip(form,vector)) + sd = OrderedDict(sorted(od.items(),key = itemgetter(1),reverse=True)) + return list(sd.keys()) \ No newline at end of file diff --git a/projects/ohrlundk/dominion/README.md b/projects/ohrlundk/dominion/README.md new file mode 100644 index 0000000..9e00834 --- /dev/null +++ b/projects/ohrlundk/dominion/README.md @@ -0,0 +1,10 @@ +# Dominion +complete Dominion game in python, text-only + +Dominion is a popular deck-building game, for 2-4 players. Each card in the deck gives a player points or money, or lets a player perform a certain action when played. Each player tries to get the most points before the end of the game. As of July 2016, I have only programmed the base version. + +There are two versions of the game--one that uses a module and a main page, and one that includes all the code in one main page, useful for sharing with a friend who doesn't have python. (It can be executed in an online REPL, hence the name.) + +The list of players is hard-coded, so edit to play. Add a * at the beginning of the name for a computer player. + +The computer (currently) plays a very simple direct strategy. Its main advantage is that is has a perfect memory of every transaction, and an accurate, dispassionate calculation of when the game is likely to end. diff --git a/projects/ohrlundk/dominion/REPLdominion.py b/projects/ohrlundk/dominion/REPLdominion.py new file mode 100644 index 0000000..5499972 --- /dev/null +++ b/projects/ohrlundk/dominion/REPLdominion.py @@ -0,0 +1,853 @@ +import random +from collections import Counter, OrderedDict +from operator import itemgetter +import re +import pandas + +class Card(): + def __init__(self,name,category,cost,buypower,vpoints): + self.name = name + self.category = category + self.cost = cost + self.buypower = buypower + self.vpoints = vpoints + def react(self,player): + return False + +class Coin_card(Card): + def __init__(self,name,cost,buypower): + Card.__init__(self,name,"coin",cost,buypower,0) + +class Copper(Coin_card): + def __init__(self): + Coin_card.__init__(self,"Copper",0,1) + +class Silver(Coin_card): + def __init__(self): + Coin_card.__init__(self,"Silver",3,2) + +class Gold(Coin_card): + def __init__(self): + Coin_card.__init__(self,"Gold",6,3) + +class Victory_card(Card): + def __init__(self,name,cost,vpoints): + Card.__init__(self,name,"victory",cost,0,vpoints) + +class Estate(Victory_card): + def __init__(self): + Victory_card.__init__(self,"Estate",2,1) + +class Duchy(Victory_card): + def __init__(self): + Victory_card.__init__(self,"Duchy",5,3) + +class Province(Victory_card): + def __init__(self): + Victory_card.__init__(self,"Province",8,6) + +class Garden(Victory_card): + def __init__(self): + Victory_card.__init__(self,"Garden",4,0) + +class Curse(Card): + def __init__(self): + Card.__init__(self,"Curse","curse",0,0,-1) + +class Action_card(Card): + def __init__(self,name,cost,actions,cards,buys,coins): + Card.__init__(self,name,"action",cost,0,0) + self.actions = actions + self.cards = cards + self.buys = buys + self.coins = coins + def use(self,player,trash): + player.played.append(self) + player.hand.remove(self) + def augment(self,player): + player.actions+=self.actions + player.buys+=self.buys + player.purse+=self.coins + for i in range(self.cards): + player.draw() + def play(self,player,players,supply,trash): + pass + +class Woodcutter(Action_card): + def __init__(self): + Action_card.__init__(self,"Woodcutter",3,0,0,1,2) + +class Smithy(Action_card): + def __init__(self): + Action_card.__init__(self,"Smithy",4,0,3,0,0) + +class Laboratory(Action_card): + def __init__(self): + Action_card.__init__(self,"Laboratory",5,1,2,0,0) + +class Village(Action_card): + def __init__(self): + Action_card.__init__(self,"Village",3,2,1,0,0) + +class Festival(Action_card): + def __init__(self): + Action_card.__init__(self,"Festival",5,2,0,1,2) + +class Market(Action_card): + def __init__(self): + Action_card.__init__(self,"Market",5,1,1,1,1) + +class Chancellor(Action_card): + def __init__(self): + Action_card.__init__(self,"Chancellor",3,0,0,0,2) + def play(self,player,players,supply,trash): + if player.yesnoinput('Would you like to discard your entire deck?'): + player.discard = player.discard + player.deck + player.deck = [] + +class Workshop(Action_card): + def __init__(self): + Action_card.__init__(self,"Workshop",3,0,0,0,0) + def play(self,player,players,supply,trash): + player.gaincard(supply,4) + +class Moneylender(Action_card): + def __init__(self): + Action_card.__init__(self,"Moneylender",4,0,0,0,0) + def play(self,player,players,supply,trash): + c = getcard("Copper",supply,player.hand,"your hand") + if c: + trash.append(c) + player.hand.remove(c) + player.purse += 3 + +class Chapel(Action_card): + def __init__(self): + Action_card.__init__(self,"Chapel",2,0,0,0,0) + def play(self,player,players,supply,trash): + trashed=0 + while trashed<4 and len(player.hand)>0: + trashcard = input("Choose a card from your hand to trash: ") + if not trashcard: + break + c = getcard(trashcard,supply,player.hand,"your hand") + if c: + trash.append(c) + player.hand.remove(c) + trashed+=1 + +class Cellar(Action_card): + def __init__(self): + Action_card.__init__(self,"Cellar",2,1,0,0,0) + def play(self,player,players,supply,trash): + discarded=0 + while len(player.hand)>0: + dis_card=input("Choose a card from your hand to discard: ") + if not dis_card: + break + c = getcard(dis_card,supply,player.hand,"your hand") + if c: + player.discard.append(c) + player.hand.remove(c) + discarded+=1 + for j in range(discarded): + player.draw() + +class Remodel(Action_card): + def __init__(self): + Action_card.__init__(self,"Remodel",4,0,0,0,0) + def play(self,player,players,supply,trash): + while len(player.hand)>0: + this_card = input("Choose a card from your hand to remodel: ") + c = getcard(this_card,supply,player.hand,"your hand") + if c: + trash.append(c) + player.hand.remove(c) + player.gaincard(supply,c.cost+2) + break + +class Adventurer(Action_card): + def __init__(self): + Action_card.__init__(self,"Adventurer",6,0,0,0,0) + def play(self,player,players,supply,trash): + coins_added = 0 + while (player.deck or player.discard) and coins_added <2: + player.draw() + if player.hand[-1].category == "coin": + coins_added +=1 + else: + player.aside.append(player.hand.pop()) + +class Feast(Action_card): + def __init__(self): + Action_card.__init__(self,"Feast",4,0,0,0,0) + def use(self,player,trash): + trash.append(self) + player.hand.remove(self) + def play(self,player,players,supply,trash): + player.gaincard(supply,5) + +class Mine(Action_card): + def __init__(self): + Action_card.__init__(self,"Mine",5,0,0,0,0) + def play(self,player,players,supply,trash): + while "coin" in catinlist(player.hand): + this_card = input("Choose a coin from your hand to upgrade: ") + c = getcard(this_card,supply,player.hand,"your hand",["coin"]) + if c: + trash.append(c) + player.hand.remove(c) + while c.cost>2 or len(supply["Copper"])>0 or len(supply["Silver"])>0: + pick = input("Choose a coin to gain. Any coin up to " + str(c.cost+3)+": ") + g = getcard(pick,supply,categories=["coin"],upto=c.cost+3) + if g: + player.hand.append(g) + supply[pick].remove(g) + break + break + +class Library(Action_card): + def __init__(self): + Action_card.__init__(self,"Library",5,0,0,0,0) + def play(self,player,players,supply,trash): + while (player.deck or player.discard) and len(player.hand) <7: + player.draw(player.hold) + if (player.hold[-1].category == "action" and not player.yesnoinput("You drew " + player.hold[-1].name + ". Would you like to keep it?",", add to my hand", ", set it aside")): + player.aside.append(player.hold.pop()) + else: + player.hand.append(player.hold.pop()) + +class Moat(Action_card): + def __init__(self): + Action_card.__init__(self,"Moat",2,0,2,0,0) + def react(self,player): + player.show() + return player.yesnoinput(player.name + ", you have a " + self.name + + " in your hand. Do you want to block the attack?") + +class Council_Room(Action_card): + def __init__(self): + Action_card.__init__(self,"Council Room",5,0,3,1,0) + def play(self,this_player,players,supply,trash): + for player in players: + player.draw() + +class Witch(Action_card): + def __init__(self): + Action_card.__init__(self,"Witch",5,0,2,0,0) + def play(self,this_player,players,supply,trash): + if len(supply["Curse"])>0: + for player in players: + if player==this_player: + pass + else: + for c in player.hand: + if c.react(player): + break + else: + if len(supply["Curse"])>0: + player.discard.append(supply["Curse"].pop()) + +class Bureaucrat(Action_card): + def __init__(self): + Action_card.__init__(self,"Bureaucrat",4,0,0,0,0) + def play(self,this_player,players,supply,trash): + if len(supply["Silver"])>0: + this_player.deck.insert(0,supply["Silver"].pop()) + for player in players: + if (not player==this_player) and ("victory" in catinlist(player.hand)): + for c in player.hand: + if c.react(player): + break + else: + player.show() + while True: + putback = player.choose_discard(player.name + ", which victory card" + + " do you want to put on top of your deck?\n--> ") + c = getcard(putback,supply,player.hand,"your hand",["victory"]) + if c: + player.hand.remove(c) + player.deck.insert(0,c) + break + +class Militia(Action_card): + def __init__(self): + Action_card.__init__(self,"Militia",4,0,0,0,2) + def play(self,this_player,players,supply,trash): + for player in players: + if (not player==this_player) and len(player.hand)>3: + for c in player.hand: + if c.react(player): + break + else: + player.show() + while len(player.hand)>3: + dis_card=player.choose_discard(player.name + ", choose a card from your hand to discard: ") + if dis_card: + c = getcard(dis_card,supply,player.hand,"your hand") + if c: + player.hand.remove(c) + player.discard.append(c) + +class Spy(Action_card): + def __init__(self): + Action_card.__init__(self,"Spy",4,1,1,0,0) + def play(self,this_player,players,supply,trash): + for player in players: + for c in player.hand: + if c.react(player): + break + else: + b = player.draw([]) + if not b: + continue + else: + print("The first card in the deck of " + player.name + " is " + b.name) + if this_player.yesnoinput(this_player.name + ", do you want " + player.name + " to discard this?", + ", discard",", keep"): + player.discard.append(b) + else: + player.deck.insert(0,b) + #check logic of this structure + +class Thief(Action_card): + def __init__(self): + Action_card.__init__(self,"Thief",4,0,0,0,0) + def play(self,this_player,players,supply,trash): + for player in players: + if player == this_player: + continue + for c in player.hand: + if c.react(player): + break + else: + for i in range(2): + player.draw(player.hold) + print( player.name, namesinlist(player.hold)) + if "coin" in catinlist(player.hold): + while True: + burn = input("Which card would you like " + player.name + " to trash?\n-->") + c = getcard(burn,supply,player.hold," the top 2 cards",["coin"]) + if c: + player.hold.remove(c) + break + if this_player.yesnoinput("Do you want to steal it?",", it's mine!",", leave it in the trash."): + this_player.discard.append(c) + else: + trash.append(c) + player.discard=player.discard+player.hold + player.hold = [] + +class Throne_Room(Action_card): + def __init__(self): + Action_card.__init__(self,"Throne Room",4,0,0,0,0) + def play(self,player,players,supply,trash): + if "action" in catinlist(player.hand): + while True: + double = input("What card would you like to double?\n--> ") + c = getcard(double,supply,player.hand," your hand",["action"]) + if c: + c.use(player,trash) + c.augment(player) + c.play(player,players,supply,trash) + player.show() + c.augment(player) + c.play(player,players,supply,trash) + break + + +class Player(): + def __init__(self,name): + self.name = name + deal = [Copper()]*7 + [Estate()]*3 + random.shuffle(deal) + self.hand = deal[:5] + self.deck = deal[5:] + self.played = [] + self.discard = [] + self.aside = [] + self.hold = [] + random.shuffle(self.deck) + for i in range(5): + self.draw + def other(self): + return self.played+self.discard+self.hold+self.aside + def stack(self): + return (self.deck + self.hand + self.played + self.discard + self.aside + self.hold) + def draw(self,dest=None): + #defualt destination is player's hand + if dest==None: + dest = self.hand + #Replenish deck if necessary. + if len(self.deck)==0: + self.deck = self.discard + self.discard = [] + random.shuffle(self.deck) + #If deck has cards, add card to destination list + if len(self.deck)>0: + c = self.deck.pop(0) + dest.append(c) + return c + def turn(self,players,supply,trash): + self.show() + self.actions = 1 + self.buys = 1 + self.purse = 0 + #action phase + while self.actions>0 and 'action' in catinlist(self.hand): + playthis = input("Which card would you like to play? You have " + + str(self.actions) + " action(s). \n-Hit enter for no play. --> ") + if playthis: + c = getcard(playthis,supply,self.hand,"your hand",['action']) + if c: + self.actions = self.actions - 1 + c.use(self,trash) + c.augment(self) + c.play(self,players,supply,trash) + self.show() + else: + self.actions=0 + #buy phase + for c in self.hand: + self.purse += c.buypower + while self.buys>0: + buy_string = "Buying power is " + str(self.purse) + ". You have " + str(self.buys) + " buy" + if self.buys>1: + buy_string += "s" + buy_string += "." + print( buy_string) + purchase = input("What would you like to purchase? -Hit enter for no purchase.-\n--> ") + if not purchase: + break + else: + c = getcard(purchase,supply,upto=self.purse) + if c: + self.discard.append(supply[purchase].pop()) + self.buys = self.buys -1 + self.purse = self.purse - c.cost + + #cleanup phase + self.discard = self.discard + self.played + self.hand + self.aside + self.played = [] + self.hand = [] + self.aside = [] + for i in range(5): + self.draw() + + def gaincard(self,supply,upto): + while True: + gain = input("What would you like to get? Any card up to " + str(upto) + "\n--> ") + c = getcard(gain,supply,upto=upto) + if c: + self.discard.append(c) + supply[gain].remove(c) + break + def yesnoinput(self,prompt,yesstring='',nostring=''): + print(prompt + "\n1 - Yes" + yesstring + "\n0 - No" + nostring) + while True: + r = input("--> ") + if r == "0": + return False + if r == "1": + return True + + def choose_discard(self,prompt): + return input(prompt) + + def show(self): + print (self.name) + print ("hand: ", namesinlist(self.hand)) + shuffled_deck = namesinlist(self.deck) + random.shuffle(shuffled_deck) + print ("deck (not in order): ", shuffled_deck) + print ("discard: ", namesinlist(self.discard)) + if len(self.played)>0: + print ("played: ", namesinlist(self.played)) + if len(self.aside)>0: + print ("aside: ",namesinlist(self.aside)) + print ("\r") + + def action_balance(self): + balance = 0 + for c in self.stack(): + if c.category == "action": + balance = balance - 1 + c.actions + return 70*balance / len(self.stack()) + + def cardsummary(self): + summary = {} + for c in self.stack(): + if c.name in summary: + summary[c.name] += 1 + else: + summary[c.name] = 1 + return summary + + def calcpoints(self): + tally = 0 + gardens = 0 + n = 0 + for c in self.stack(): + tally += c.vpoints + n += 1 + if c.name == "Garden": + gardens+=1 + return tally + n//10 * gardens + +class ComputerPlayer(Player): + def __init__(self,name): + Player.__init__(self,name) + self.index = 0 + self.buygaintable = [] + #beginning and middle of game + self.buygaintable1 = ["Province","Gold","Laboratory","Festival","Witch", + "Council Room","Market","Militia","Adventurer","Smithy","Bureaucrat","Silver","Moat",""] + #end of game + self.buygaintable2 = ["Province","Garden","Duchy","Estate","Gold","Silver",""] + #beginning and middle of the game, too many action cards + self.buygaintable3 = ["Province","Gold","Festival","Laboratory","Market","Village", + "Silver",""] + self.playtable1 = ["Village","Festival","Market","Laboratory","Witch", + "Council Room","Militia","Adventurer","Smithy","Bureaucrat","Moat",""] + self.discardtable1 = ["Garden","Duchy","Province","Estate","Curse","Copper", + "Village","Bureaucrat","Silver","Militia","Smithy","Council Room","Witch", + "Festival","Market","Adventurer","Laboratory","Gold","Moat"] + + def turn(self,players,supply,trash): + self.show() + self.actions = 1 + self.buys = 1 + self.purse = 0 + #action phase + self.index = 0 + while self.actions>0 and 'action' in catinlist(self.hand): + playthis = self.playtable1[self.index] + if playthis: + c = self.getcard(playthis,supply,self.hand,"your hand",['action']) + if c: + #print (self.name + " plays " + c.name) + self.actions = self.actions - 1 + c.use(self,trash) + self.index=0 + c.augment(self) + c.play(self,players,supply,trash) + self.show() + else: + self.index += 1 + else: + self.actions=0 + #buy phase + if len(supply["Province"])>len(players)+totalbuypower(self.deck)/8: + if self.action_balance()<-10: + self.buygaintable = self.buygaintable3 + else: + self.buygaintable = self.buygaintable1 + else: + self.buygaintable = self.buygaintable2 + self.index = 0 + for c in self.hand: + self.purse += c.buypower + while self.buys>0: + purchase = self.buygaintable[self.index] + if not purchase: + break + else: + c = self.getcard(purchase,supply,upto=self.purse) + if c: + self.discard.append(supply[purchase].pop()) + self.index = 0 + self.buys = self.buys -1 + self.purse = self.purse - c.cost + #print (self.name + " bought " + c.name) + else: + self.index += 1 + + #cleanup phase + self.discard = self.discard + self.played + self.hand + self.aside + self.played = [] + self.hand = [] + self.aside = [] + for i in range(5): + self.draw() + + def getcard(self,name,supply,target_list=None,target_name= "the supply anymore",categories=['action','coin','curse','victory'],upto=100): + if not name in supply: + #print name + " is not in this game." + return None + if not target_list: + target_list = supply[name] + nameslist = namesinlist(target_list) + if not name in nameslist: + #print "There is no " + name + " in " + target_name + return None + i = nameslist.index(name) + c = target_list[i] + if c.category not in categories: + catstring = categories[0] + for i in categories[1:]: + catstring = catstring + " or " + categories[i] + #print name + " is not a " + catstring + " card." + return None + if c.cost > upto: + #print name + " costs " + str(c.cost) + return None + return c + + def choose_discard(self,prompt): + index = 0 + while True: + dis_card = self.discardtable1[index] + c = self.getcard(dis_card,[dis_card],self.hand) + if c: + return c.name + else: + index+=1 + + def yesnoinput(self,prompt,yesstring='',nostring=''): + return True + + def show(self): + pass + +class TablePlayer(ComputerPlayer): + def __init__(self,name): + ComputerPlayer.__init__(self,name) + self.index=0 + self.buygaintable=[] + q=re.match(r'([a-zA-Z]+)(\d+)',name) + if q: + self.number = q.group(2) + else: + print(name) + self.playtable1 = ["Village","Festival","Market","Laboratory","Witch", + "Council Room","Militia","Adventurer","Smithy","Bureaucrat","Moat",""] + self.discardtable1 = ["Garden","Duchy","Province","Estate","Curse","Copper", + "Village","Bureaucrat","Silver","Militia","Smithy","Council Room","Witch", + "Festival","Market","Adventurer","Laboratory","Gold","Moat"] + + def turn(self,players,supply,trash): + self.show() + self.actions = 1 + self.buys = 1 + self.purse = 0 + #action phase + self.index = 0 + while self.actions>0 and 'action' in catinlist(self.hand): + playthis = self.playtable1[self.index] + if playthis: + c = self.getcard(playthis,supply,self.hand,"your hand",['action']) + if c: + #print (self.name + " plays " + c.name) + self.actions = self.actions - 1 + c.use(self,trash) + self.index=0 + c.augment(self) + c.play(self,players,supply,trash) + self.show() + else: + self.index += 1 + else: + self.actions=0 + #buy phase + v= self.number + csvstring = r"Dominionbuy" + str(v) + ".csv" + buydf=pandas.read_csv(csvstring,na_filter=False) + sortedbuydf=buydf.sort_values("Buyvalues",ascending=False) + ranktable = sortedbuydf.Cardname + self.index = 0 + for c in self.hand: + self.purse += c.buypower + while self.buys>0: + purchase = ranktable.iloc[self.index] + if not purchase: + break + else: + c = self.getcard(purchase,supply,upto=self.purse) + if c: + self.discard.append(supply[purchase].pop()) + self.index = 0 + self.buys = self.buys -1 + self.purse = self.purse - c.cost + else: + self.index += 1 + + #cleanup phase + self.discard = self.discard + self.played + self.hand + self.aside + self.played = [] + self.hand = [] + self.aside = [] + for i in range(5): + self.draw() + + +def gameover(supply): + if len(supply["Province"])==0: + return True + out = 0 + for stack in supply: + if len(supply[stack])==0: + out+=1 + if out>=3: + return True + return False + +def namesinlist(cardlist): + namelist = [] + for c in cardlist: + namelist.append(c.name) + return namelist + +def catinlist(cardlist): + catlist = [] + for c in cardlist: + catlist.append(c.category) + return catlist + +def getcard(name,supply,target_list=None,target_name= "the supply anymore",categories=['action','coin','curse','victory'],upto=100): + if not name in supply: + print( name + " is not in this game.") + return None + if not target_list: + target_list = supply[name] + nameslist = namesinlist(target_list) + if not name in nameslist: + print ("There is no " + name + " in " + target_name) + return None + i = nameslist.index(name) + c = target_list[i] + if c.category not in categories: + catstring = categories[0] + for i in categories[1:]: + catstring = catstring + " or " + categories[i] + print (name + " is not a " + catstring + " card.") + return None + if c.cost > upto: + print (name + " costs " + str(c.cost)) + return None + return c + +def totalbuypower(cardlist): + TBP = 0 + for c in cardlist: + TBP += c.buypower + if c.category == "action": + TBP += c.coins + return TBP + +def countsupply(supply,form): + return [len(supply[a]) for a in form] + +def countcards(cards,form): + dcount = Counter(namesinlist(cards)) + return [dcount[a] for a in form] + +def rankcards(form,vector): + od = OrderedDict(zip(form,vector)) + sd = OrderedDict(sorted(od.items(),key = itemgetter(1),reverse=True)) + return list(sd.keys()) + +#import Dominion +#import random +from collections import defaultdict + +#Get player names +player_names = ["Timothy","*Grover","*Elmo"] + +#number of curses and victory cards +if len(player_names)>2: + nV=12 +else: + nV=8 +nC = -10 + 10 * len(player_names) + +#Define box +box = {} +box["Woodcutter"]=[Woodcutter()]*10 +box["Smithy"]=[Smithy()]*10 +box["Laboratory"]=[Laboratory()]*10 +box["Village"]=[Village()]*10 +box["Festival"]=[Festival()]*10 +box["Market"]=[Market()]*10 +box["Chancellor"]=[Chancellor()]*10 +box["Workshop"]=[Workshop()]*10 +box["Moneylender"]=[Moneylender()]*10 +box["Chapel"]=[Chapel()]*10 +box["Cellar"]=[Cellar()]*10 +box["Remodel"]=[Remodel()]*10 +box["Adventurer"]=[Adventurer()]*10 +box["Feast"]=[Feast()]*10 +box["Mine"]=[Mine()]*10 +box["Library"]=[Library()]*10 +box["Garden"]=[Garden()]*nV +box["Moat"]=[Moat()]*10 +box["Council Room"]=[Council_Room()]*10 +box["Witch"]=[Witch()]*10 +box["Bureaucrat"]=[Bureaucrat()]*10 +box["Militia"]=[Militia()]*10 +box["Spy"]=[Spy()]*10 +box["Thief"]=[Thief()]*10 +box["Throne Room"]=[Throne_Room()]*10 + +supply_order = {0:['Curse','Copper'],2:['Estate','Cellar','Chapel','Moat'], + 3:['Silver','Chancellor','Village','Woodcutter','Workshop'], + 4:['Garden','Bureaucrat','Feast','Militia','Moneylender','Remodel','Smithy','Spy','Thief','Throne Room'], + 5:['Duchy','Market','Council Room','Festival','Laboratory','Library','Mine','Witch'], + 6:['Gold','Adventurer'],8:['Province']} + +#Pick 10 cards from box to be in the supply. +boxlist = [k for k in box] +random.shuffle(boxlist) +random10 = boxlist[:10] +supply = defaultdict(list,[(k,box[k]) for k in random10]) + + +#The supply always has these cards +supply["Copper"]=[Copper()]*(60-len(player_names)*7) +supply["Silver"]=[Silver()]*40 +supply["Gold"]=[Gold()]*30 +supply["Estate"]=[Estate()]*nV +supply["Duchy"]=[Duchy()]*nV +supply["Province"]=[Province()]*nV +supply["Curse"]=[Curse()]*nC + +#initialize the trash +trash = [] + +#Costruct the Player objects +players = [] +for name in player_names: + if name[0]=="*": + players.append(ComputerPlayer(name[1:])) + elif name[0]=="^": + players.append(TablePlayer(name[1:])) + else: + players.append(Player(name)) + +#Play the game +turn = 0 +while not gameover(supply): + turn += 1 + print("\r") + for value in supply_order: + print (value) + for stack in supply_order[value]: + if stack in supply: + print (stack, len(supply[stack])) + print("\r") + for player in players: + print (player.name,player.calcpoints()) + print ("\rStart of turn " + str(turn)) + for player in players: + if not gameover(supply): + print("\r") + player.turn(players,supply,trash) + + +#Final score +print ("\r") +for player in players: + print (player.name,player.calcpoints()) + +print ("\n") +for player in players: + print (player.name,player.cardsummary()) \ No newline at end of file diff --git a/projects/ohrlundk/dominion/playDominion.py b/projects/ohrlundk/dominion/playDominion.py new file mode 100644 index 0000000..b4d6021 --- /dev/null +++ b/projects/ohrlundk/dominion/playDominion.py @@ -0,0 +1,119 @@ +# -*- coding: utf-8 -*- +""" +Created on Tue Oct 13 15:42:42 2015 + +@author: tfleck +""" + +import Dominion +import random +from collections import defaultdict + +#Get player names +player_names = ["Annie","*Ben","*Carla"] + +#number of curses and victory cards +if len(player_names)>2: + nV=12 +else: + nV=8 +nC = -10 + 10 * len(player_names) + +#Define box +box = {} +box["Woodcutter"]=[Dominion.Woodcutter()]*10 +box["Smithy"]=[Dominion.Smithy()]*10 +box["Laboratory"]=[Dominion.Laboratory()]*10 +box["Village"]=[Dominion.Village()]*10 +box["Festival"]=[Dominion.Festival()]*10 +box["Market"]=[Dominion.Market()]*10 +box["Chancellor"]=[Dominion.Chancellor()]*10 +box["Workshop"]=[Dominion.Workshop()]*10 +box["Moneylender"]=[Dominion.Moneylender()]*10 +box["Chapel"]=[Dominion.Chapel()]*10 +box["Cellar"]=[Dominion.Cellar()]*10 +box["Remodel"]=[Dominion.Remodel()]*10 +box["Adventurer"]=[Dominion.Adventurer()]*10 +box["Feast"]=[Dominion.Feast()]*10 +box["Mine"]=[Dominion.Mine()]*10 +box["Library"]=[Dominion.Library()]*10 +box["Gardens"]=[Dominion.Gardens()]*nV +box["Moat"]=[Dominion.Moat()]*10 +box["Council Room"]=[Dominion.Council_Room()]*10 +box["Witch"]=[Dominion.Witch()]*10 +box["Bureaucrat"]=[Dominion.Bureaucrat()]*10 +box["Militia"]=[Dominion.Militia()]*10 +box["Spy"]=[Dominion.Spy()]*10 +box["Thief"]=[Dominion.Thief()]*10 +box["Throne Room"]=[Dominion.Throne_Room()]*10 + +supply_order = {0:['Curse','Copper'],2:['Estate','Cellar','Chapel','Moat'], + 3:['Silver','Chancellor','Village','Woodcutter','Workshop'], + 4:['Gardens','Bureaucrat','Feast','Militia','Moneylender','Remodel','Smithy','Spy','Thief','Throne Room'], + 5:['Duchy','Market','Council Room','Festival','Laboratory','Library','Mine','Witch'], + 6:['Gold','Adventurer'],8:['Province']} + +#Pick 10 cards from box to be in the supply. +boxlist = [k for k in box] +random.shuffle(boxlist) +random10 = boxlist[:10] +supply = defaultdict(list,[(k,box[k]) for k in random10]) + + +#The supply always has these cards +supply["Copper"]=[Dominion.Copper()]*(60-len(player_names)*7) +supply["Silver"]=[Dominion.Silver()]*40 +supply["Gold"]=[Dominion.Gold()]*30 +supply["Estate"]=[Dominion.Estate()]*nV +supply["Duchy"]=[Dominion.Duchy()]*nV +supply["Province"]=[Dominion.Province()]*nV +supply["Curse"]=[Dominion.Curse()]*nC + +#initialize the trash +trash = [] + +#Costruct the Player objects +players = [] +for name in player_names: + if name[0]=="*": + players.append(Dominion.ComputerPlayer(name[1:])) + elif name[0]=="^": + players.append(Dominion.TablePlayer(name[1:])) + else: + players.append(Dominion.Player(name)) + +#Play the game +turn = 0 +while not Dominion.gameover(supply): + turn += 1 + print("\r") + for value in supply_order: + print (value) + for stack in supply_order[value]: + if stack in supply: + print (stack, len(supply[stack])) + print("\r") + for player in players: + print (player.name,player.calcpoints()) + print ("\rStart of turn " + str(turn)) + for player in players: + if not Dominion.gameover(supply): + print("\r") + player.turn(players,supply,trash) + + +#Final score +dcs=Dominion.cardsummaries(players) +vp=dcs.loc['VICTORY POINTS'] +vpmax=vp.max() +winners=[] +for i in vp.index: + if vp.loc[i]==vpmax: + winners.append(i) +if len(winners)>1: + winstring= ' and '.join(winners) + ' win!' +else: + winstring = ' '.join([winners[0],'wins!']) + +print("\nGAME OVER!!!\n"+winstring+"\n") +print(dcs) \ No newline at end of file From f5ec2d16174e9a55369439141529fddf7988e649 Mon Sep 17 00:00:00 2001 From: kohrlund <39636053+kohrlund@users.noreply.github.com> Date: Sun, 5 Jan 2020 16:37:24 -0600 Subject: [PATCH 09/13] Create readme.md --- projects/ohrlundk/dominion/readme.md | 3 +++ 1 file changed, 3 insertions(+) create mode 100644 projects/ohrlundk/dominion/readme.md diff --git a/projects/ohrlundk/dominion/readme.md b/projects/ohrlundk/dominion/readme.md new file mode 100644 index 0000000..7486cda --- /dev/null +++ b/projects/ohrlundk/dominion/readme.md @@ -0,0 +1,3 @@ +#Your onid folder should contain a readme file that contains your name and your ONID. +Name: Kevin J. Ohrlund +ONID: Ohrlundk From 0ce85ccbc5c92bd19c100ce3aff904959d00a456 Mon Sep 17 00:00:00 2001 From: kohrlund <39636053+kohrlund@users.noreply.github.com> Date: Sun, 5 Jan 2020 16:37:59 -0600 Subject: [PATCH 10/13] Add files via upload --- projects/ohrlundk/dominion/Dominion.py | 762 ++++++++++++++++++ projects/ohrlundk/dominion/README.md | 10 + projects/ohrlundk/dominion/REPLdominion.py | 853 +++++++++++++++++++++ projects/ohrlundk/dominion/playDominion.py | 119 +++ 4 files changed, 1744 insertions(+) create mode 100644 projects/ohrlundk/dominion/Dominion.py create mode 100644 projects/ohrlundk/dominion/README.md create mode 100644 projects/ohrlundk/dominion/REPLdominion.py create mode 100644 projects/ohrlundk/dominion/playDominion.py diff --git a/projects/ohrlundk/dominion/Dominion.py b/projects/ohrlundk/dominion/Dominion.py new file mode 100644 index 0000000..6a0a534 --- /dev/null +++ b/projects/ohrlundk/dominion/Dominion.py @@ -0,0 +1,762 @@ +# -*- coding: utf-8 -*- +""" +Created on Tue Oct 13 15:26:55 2015 + +@author: tfleck +""" +import random +from collections import Counter, OrderedDict +from operator import itemgetter +import re +import pandas + +class Card(): + def __init__(self,name,category,cost,buypower,vpoints): + self.name = name + self.category = category + self.cost = cost + self.buypower = buypower + self.vpoints = vpoints + def react(self,player): + return False + +class Coin_card(Card): + def __init__(self,name,cost,buypower): + Card.__init__(self,name,"coin",cost,buypower,0) + +class Copper(Coin_card): + def __init__(self): + Coin_card.__init__(self,"Copper",0,1) + +class Silver(Coin_card): + def __init__(self): + Coin_card.__init__(self,"Silver",3,2) + +class Gold(Coin_card): + def __init__(self): + Coin_card.__init__(self,"Gold",6,3) + +class Victory_card(Card): + def __init__(self,name,cost,vpoints): + Card.__init__(self,name,"victory",cost,0,vpoints) + +class Estate(Victory_card): + def __init__(self): + Victory_card.__init__(self,"Estate",2,1) + +class Duchy(Victory_card): + def __init__(self): + Victory_card.__init__(self,"Duchy",5,3) + +class Province(Victory_card): + def __init__(self): + Victory_card.__init__(self,"Province",8,6) + +class Gardens(Victory_card): + def __init__(self): + Victory_card.__init__(self,"Gardens",4,0) + +class Curse(Card): + def __init__(self): + Card.__init__(self,"Curse","curse",0,0,-1) + +class Action_card(Card): + def __init__(self,name,cost,actions,cards,buys,coins): + Card.__init__(self,name,"action",cost,0,0) + self.actions = actions + self.cards = cards + self.buys = buys + self.coins = coins + def use(self,player,trash): + player.played.append(self) + player.hand.remove(self) + def augment(self,player): + player.actions+=self.actions + player.buys+=self.buys + player.purse+=self.coins + for i in range(self.cards): + player.draw() + def play(self,player,players,supply,trash): + pass + +class Woodcutter(Action_card): + def __init__(self): + Action_card.__init__(self,"Woodcutter",3,0,0,1,2) + +class Smithy(Action_card): + def __init__(self): + Action_card.__init__(self,"Smithy",4,0,3,0,0) + +class Laboratory(Action_card): + def __init__(self): + Action_card.__init__(self,"Laboratory",5,1,2,0,0) + +class Village(Action_card): + def __init__(self): + Action_card.__init__(self,"Village",3,2,1,0,0) + +class Festival(Action_card): + def __init__(self): + Action_card.__init__(self,"Festival",5,2,0,1,2) + +class Market(Action_card): + def __init__(self): + Action_card.__init__(self,"Market",5,1,1,1,1) + +class Chancellor(Action_card): + def __init__(self): + Action_card.__init__(self,"Chancellor",3,0,0,0,2) + def play(self,player,players,supply,trash): + if player.yesnoinput('Would you like to discard your entire deck?'): + player.discard = player.discard + player.deck + player.deck = [] + +class Workshop(Action_card): + def __init__(self): + Action_card.__init__(self,"Workshop",3,0,0,0,0) + def play(self,player,players,supply,trash): + player.gaincard(supply,4) + +class Moneylender(Action_card): + def __init__(self): + Action_card.__init__(self,"Moneylender",4,0,0,0,0) + def play(self,player,players,supply,trash): + c = getcard("Copper",supply,player.hand,"your hand") + if c: + trash.append(c) + player.hand.remove(c) + player.purse += 3 + +class Chapel(Action_card): + def __init__(self): + Action_card.__init__(self,"Chapel",2,0,0,0,0) + def play(self,player,players,supply,trash): + trashed=0 + while trashed<4 and len(player.hand)>0: + trashcard = input("Choose a card from your hand to trash: ") + if not trashcard: + break + c = getcard(trashcard,supply,player.hand,"your hand") + if c: + trash.append(c) + player.hand.remove(c) + trashed+=1 + +class Cellar(Action_card): + def __init__(self): + Action_card.__init__(self,"Cellar",2,1,0,0,0) + def play(self,player,players,supply,trash): + discarded=0 + while len(player.hand)>0: + dis_card=input("Choose a card from your hand to discard: ") + if not dis_card: + break + c = getcard(dis_card,supply,player.hand,"your hand") + if c: + player.discard.append(c) + player.hand.remove(c) + discarded+=1 + for j in range(discarded): + player.draw() + +class Remodel(Action_card): + def __init__(self): + Action_card.__init__(self,"Remodel",4,0,0,0,0) + def play(self,player,players,supply,trash): + while len(player.hand)>0: + this_card = input("Choose a card from your hand to remodel: ") + c = getcard(this_card,supply,player.hand,"your hand") + if c: + trash.append(c) + player.hand.remove(c) + player.gaincard(supply,c.cost+2) + break + +class Adventurer(Action_card): + def __init__(self): + Action_card.__init__(self,"Adventurer",6,0,0,0,0) + def play(self,player,players,supply,trash): + coins_added = 0 + while (player.deck or player.discard) and coins_added <2: + player.draw() + if player.hand[-1].category == "coin": + coins_added +=1 + else: + player.aside.append(player.hand.pop()) + +class Feast(Action_card): + def __init__(self): + Action_card.__init__(self,"Feast",4,0,0,0,0) + def use(self,player,trash): + trash.append(self) + player.hand.remove(self) + def play(self,player,players,supply,trash): + player.gaincard(supply,5) + +class Mine(Action_card): + def __init__(self): + Action_card.__init__(self,"Mine",5,0,0,0,0) + def play(self,player,players,supply,trash): + while "coin" in catinlist(player.hand): + this_card = input("Choose a coin from your hand to upgrade: ") + c = getcard(this_card,supply,player.hand,"your hand",["coin"]) + if c: + trash.append(c) + player.hand.remove(c) + while c.cost>2 or len(supply["Copper"])>0 or len(supply["Silver"])>0: + pick = input("Choose a coin to gain. Any coin up to " + str(c.cost+3)+": ") + g = getcard(pick,supply,categories=["coin"],upto=c.cost+3) + if g: + player.hand.append(g) + supply[pick].remove(g) + break + break + +class Library(Action_card): + def __init__(self): + Action_card.__init__(self,"Library",5,0,0,0,0) + def play(self,player,players,supply,trash): + while (player.deck or player.discard) and len(player.hand) <7: + player.draw(player.hold) + if (player.hold[-1].category == "action" and not player.yesnoinput("You drew " + player.hold[-1].name + ". Would you like to keep it?",", add to my hand", ", set it aside")): + player.aside.append(player.hold.pop()) + else: + player.hand.append(player.hold.pop()) + +class Moat(Action_card): + def __init__(self): + Action_card.__init__(self,"Moat",2,0,2,0,0) + def react(self,player): + player.show() + return player.yesnoinput(player.name + ", you have a " + self.name + + " in your hand. Do you want to block the attack?") + +class Council_Room(Action_card): + def __init__(self): + Action_card.__init__(self,"Council Room",5,0,3,1,0) + def play(self,this_player,players,supply,trash): + for player in players: + player.draw() + +class Witch(Action_card): + def __init__(self): + Action_card.__init__(self,"Witch",5,0,2,0,0) + def play(self,this_player,players,supply,trash): + if len(supply["Curse"])>0: + for player in players: + if player==this_player: + pass + else: + for c in player.hand: + if c.react(player): + break + else: + if len(supply["Curse"])>0: + player.discard.append(supply["Curse"].pop()) + +class Bureaucrat(Action_card): + def __init__(self): + Action_card.__init__(self,"Bureaucrat",4,0,0,0,0) + def play(self,this_player,players,supply,trash): + if len(supply["Silver"])>0: + this_player.deck.insert(0,supply["Silver"].pop()) + for player in players: + if (not player==this_player) and ("victory" in catinlist(player.hand)): + for c in player.hand: + if c.react(player): + break + else: + player.show() + while True: + putback = player.choose_discard(player.name + ", which victory card" + + " do you want to put on top of your deck?\n--> ") + c = getcard(putback,supply,player.hand,"your hand",["victory"]) + if c: + player.hand.remove(c) + player.deck.insert(0,c) + break + +class Militia(Action_card): + def __init__(self): + Action_card.__init__(self,"Militia",4,0,0,0,2) + def play(self,this_player,players,supply,trash): + for player in players: + if (not player==this_player) and len(player.hand)>3: + for c in player.hand: + if c.react(player): + break + else: + player.show() + while len(player.hand)>3: + dis_card=player.choose_discard(player.name + ", choose a card from your hand to discard: ") + if dis_card: + c = getcard(dis_card,supply,player.hand,"your hand") + if c: + player.hand.remove(c) + player.discard.append(c) + +class Spy(Action_card): + def __init__(self): + Action_card.__init__(self,"Spy",4,1,1,0,0) + def play(self,this_player,players,supply,trash): + for player in players: + for c in player.hand: + if c.react(player): + break + else: + b = player.draw([]) + if not b: + continue + else: + print("The first card in the deck of " + player.name + " is " + b.name) + if this_player.yesnoinput(this_player.name + ", do you want " + player.name + " to discard this?", + ", discard",", keep"): + player.discard.append(b) + else: + player.deck.insert(0,b) + #check logic of this structure + +class Thief(Action_card): + def __init__(self): + Action_card.__init__(self,"Thief",4,0,0,0,0) + def play(self,this_player,players,supply,trash): + for player in players: + if player == this_player: + continue + for c in player.hand: + if c.react(player): + break + else: + for i in range(2): + player.draw(player.hold) + print( player.name, namesinlist(player.hold)) + if "coin" in catinlist(player.hold): + while True: + burn = input("Which card would you like " + player.name + " to trash?\n-->") + c = getcard(burn,supply,player.hold," the top 2 cards",["coin"]) + if c: + player.hold.remove(c) + break + if this_player.yesnoinput("Do you want to steal it?",", it's mine!",", leave it in the trash."): + this_player.discard.append(c) + else: + trash.append(c) + player.discard=player.discard+player.hold + player.hold = [] + +class Throne_Room(Action_card): + def __init__(self): + Action_card.__init__(self,"Throne Room",4,0,0,0,0) + def play(self,player,players,supply,trash): + if "action" in catinlist(player.hand): + while True: + double = input("What card would you like to double?\n--> ") + c = getcard(double,supply,player.hand," your hand",["action"]) + if c: + c.use(player,trash) + c.augment(player) + c.play(player,players,supply,trash) + player.show() + c.augment(player) + c.play(player,players,supply,trash) + break + + +class Player(): + def __init__(self,name): + self.name = name + self.hand = [] + self.deck = [Copper()]*7 + [Estate()]*3 + random.shuffle(self.deck) + self.played = [] + self.discard = [] + self.aside = [] + self.hold = [] + for i in range(5): + self.draw() + + def other(self): + return self.played+self.discard+self.hold+self.aside + def stack(self): + return (self.deck + self.hand + self.played + self.discard + self.aside + self.hold) + def draw(self,dest=None): + #defualt destination is player's hand + if dest==None: + dest = self.hand + #Replenish deck if necessary. + if len(self.deck)==0: + self.deck = self.discard + self.discard = [] + random.shuffle(self.deck) + #If deck has cards, add card to destination list + if len(self.deck)>0: + c = self.deck.pop(0) + dest.append(c) + return c + def turn(self,players,supply,trash): + self.show() + self.actions = 1 + self.buys = 1 + self.purse = 0 + #action phase + while self.actions>0 and 'action' in catinlist(self.hand): + playthis = input("Which card would you like to play? You have " + + str(self.actions) + " action(s). \n-Hit enter for no play. --> ") + if playthis: + c = getcard(playthis,supply,self.hand,"your hand",['action']) + if c: + self.actions = self.actions - 1 + c.use(self,trash) + c.augment(self) + c.play(self,players,supply,trash) + self.show() + else: + self.actions=0 + #buy phase + for c in self.hand: + self.purse += c.buypower + while self.buys>0: + buy_string = "Buying power is " + str(self.purse) + ". You have " + str(self.buys) + " buy" + if self.buys>1: + buy_string += "s" + buy_string += "." + print( buy_string) + purchase = input("What would you like to purchase? -Hit enter for no purchase.-\n--> ") + if not purchase: + break + else: + c = getcard(purchase,supply,upto=self.purse) + if c: + self.discard.append(supply[purchase].pop()) + self.buys = self.buys -1 + self.purse = self.purse - c.cost + + #cleanup phase + self.discard = self.discard + self.played + self.hand + self.aside + self.played = [] + self.hand = [] + self.aside = [] + for i in range(5): + self.draw() + + def gaincard(self,supply,upto): + while True: + gain = input("What would you like to get? Any card up to " + str(upto) + "\n--> ") + c = getcard(gain,supply,upto=upto) + if c: + self.discard.append(c) + supply[gain].remove(c) + break + def yesnoinput(self,prompt,yesstring='',nostring=''): + print(prompt + "\n1 - Yes" + yesstring + "\n0 - No" + nostring) + while True: + r = input("--> ") + if r == "0": + return False + if r == "1": + return True + + def choose_discard(self,prompt): + return input(prompt) + + def show(self): + print (self.name) + print ("hand:", ", ".join(sorted(namesinlist(self.hand)))) + if len(self.deck)>0: + print ("deck (alphabetical order):", ", ".join(sorted(namesinlist(self.deck)))) + if len(self.discard)>0: + print ("discard:", ", ".join(sorted(namesinlist(self.discard)))) + if len(self.played)>0: + print ("played:", ", ".join(sorted(namesinlist(self.played)))) + if len(self.aside)>0: + print ("aside:", ", ".join(sorted(namesinlist(self.aside)))) + print ("\r") + + def action_balance(self): + balance = 0 + for c in self.stack(): + if c.category == "action": + balance = balance - 1 + c.actions + return 70*balance / len(self.stack()) + + def cardsummary(self): + summary = {} + for c in self.stack(): + if c.name in summary: + summary[c.name] += 1 + else: + summary[c.name] = 1 + summary['VICTORY POINTS']=self.calcpoints() + return summary + + def calcpoints(self): + tally = 0 + gardens = 0 + n = 0 + for c in self.stack(): + tally += c.vpoints + n += 1 + if c.name == "Gardens": + gardens+=1 + return tally + n//10 * gardens + +class ComputerPlayer(Player): + def __init__(self,name): + Player.__init__(self,name) + self.index = 0 + self.buygaintable = [] + #beginning and middle of game + self.buygaintable1 = ["Province","Gold","Laboratory","Festival","Witch", + "Council Room","Market","Militia","Adventurer","Smithy","Bureaucrat","Silver","Moat",""] + #end of game + self.buygaintable2 = ["Province","Gardens","Duchy","Estate","Gold","Silver",""] + #beginning and middle of the game, too many action cards + self.buygaintable3 = ["Province","Gold","Festival","Laboratory","Market","Village", + "Silver",""] + self.playtable1 = ["Village","Festival","Market","Laboratory","Witch", + "Council Room","Militia","Adventurer","Smithy","Bureaucrat","Moat",""] + self.discardtable1 = ["Gardens","Duchy","Province","Estate","Curse","Copper", + "Village","Bureaucrat","Silver","Militia","Smithy","Council Room","Witch", + "Festival","Market","Adventurer","Laboratory","Gold","Moat"] + + def turn(self,players,supply,trash): + self.show() + self.actions = 1 + self.buys = 1 + self.purse = 0 + #action phase + self.index = 0 + while self.actions>0 and 'action' in catinlist(self.hand): + playthis = self.playtable1[self.index] + if playthis: + c = self.getcard(playthis,supply,self.hand,"your hand",['action']) + if c: + print (self.name + " plays " + c.name) + self.actions = self.actions - 1 + c.use(self,trash) + self.index=0 + c.augment(self) + c.play(self,players,supply,trash) + self.show() + else: + self.index += 1 + else: + self.actions=0 + #buy phase + if len(supply["Province"])>len(players)+totalbuypower(self.deck)/8: + if self.action_balance()<-10: + self.buygaintable = self.buygaintable3 + else: + self.buygaintable = self.buygaintable1 + else: + self.buygaintable = self.buygaintable2 + self.index = 0 + for c in self.hand: + self.purse += c.buypower + while self.buys>0: + purchase = self.buygaintable[self.index] + if not purchase: + break + else: + c = self.getcard(purchase,supply,upto=self.purse) + if c: + self.discard.append(supply[purchase].pop()) + self.index = 0 + self.buys = self.buys -1 + self.purse = self.purse - c.cost + print (self.name + " bought " + c.name) + else: + self.index += 1 + + #cleanup phase + self.discard = self.discard + self.played + self.hand + self.aside + self.played = [] + self.hand = [] + self.aside = [] + for i in range(5): + self.draw() + + def getcard(self,name,supply,target_list=None,target_name= "the supply anymore",categories=['action','coin','curse','victory'],upto=100): + if not name in supply: + #print name + " is not in this game." + return None + if not target_list: + target_list = supply[name] + nameslist = namesinlist(target_list) + if not name in nameslist: + #print "There is no " + name + " in " + target_name + return None + i = nameslist.index(name) + c = target_list[i] + if c.category not in categories: + catstring = categories[0] + for i in categories[1:]: + catstring = catstring + " or " + categories[i] + #print name + " is not a " + catstring + " card." + return None + if c.cost > upto: + #print name + " costs " + str(c.cost) + return None + return c + + def choose_discard(self,prompt): + index = 0 + while True: + dis_card = self.discardtable1[index] + c = self.getcard(dis_card,[dis_card],self.hand) + if c: + return c.name + else: + index+=1 + + def yesnoinput(self,prompt,yesstring='',nostring=''): + return True + + def show(self): + pass + +class TablePlayer(ComputerPlayer): + def __init__(self,name): + ComputerPlayer.__init__(self,name) + self.index=0 + self.buygaintable=[] + q=re.match(r'([a-zA-Z]+)(\d+)',name) + if q: + self.number = q.group(2) + else: + print(name) + self.playtable1 = ["Village","Festival","Market","Laboratory","Witch", + "Council Room","Militia","Adventurer","Smithy","Bureaucrat","Moat",""] + self.discardtable1 = ["Gardens","Duchy","Province","Estate","Curse","Copper", + "Village","Bureaucrat","Silver","Militia","Smithy","Council Room","Witch", + "Festival","Market","Adventurer","Laboratory","Gold","Moat"] + + def turn(self,players,supply,trash): + self.show() + self.actions = 1 + self.buys = 1 + self.purse = 0 + #action phase + self.index = 0 + while self.actions>0 and 'action' in catinlist(self.hand): + playthis = self.playtable1[self.index] + if playthis: + c = self.getcard(playthis,supply,self.hand,"your hand",['action']) + if c: + #print (self.name + " plays " + c.name) + self.actions = self.actions - 1 + c.use(self,trash) + self.index=0 + c.augment(self) + c.play(self,players,supply,trash) + self.show() + else: + self.index += 1 + else: + self.actions=0 + #buy phase + v= self.number + csvstring = r"Dominionbuy" + str(v) + ".csv" + buydf=pandas.read_csv(csvstring,na_filter=False) + sortedbuydf=buydf.sort_values("Buyvalues",ascending=False) + ranktable = sortedbuydf.Cardname + self.index = 0 + for c in self.hand: + self.purse += c.buypower + while self.buys>0: + purchase = ranktable.iloc[self.index] + if not purchase: + break + else: + c = self.getcard(purchase,supply,upto=self.purse) + if c: + self.discard.append(supply[purchase].pop()) + self.index = 0 + self.buys = self.buys -1 + self.purse = self.purse - c.cost + else: + self.index += 1 + + #cleanup phase + self.discard = self.discard + self.played + self.hand + self.aside + self.played = [] + self.hand = [] + self.aside = [] + for i in range(5): + self.draw() + + +def gameover(supply): + if len(supply["Province"])==0: + return True + out = 0 + for stack in supply: + if len(supply[stack])==0: + out+=1 + if out>=3: + return True + return False + +def namesinlist(cardlist): + namelist = [] + for c in cardlist: + namelist.append(c.name) + return namelist + +def catinlist(cardlist): + catlist = [] + for c in cardlist: + catlist.append(c.category) + return catlist + +def getcard(name,supply,target_list=None,target_name= "the supply anymore",categories=['action','coin','curse','victory'],upto=100): + if not name in supply: + print( name + " is not in this game.") + return None + if not target_list: + target_list = supply[name] + nameslist = namesinlist(target_list) + if not name in nameslist: + print ("There is no " + name + " in " + target_name) + return None + i = nameslist.index(name) + c = target_list[i] + if c.category not in categories: + catstring = categories[0] + for i in categories[1:]: + catstring = catstring + " or " + categories[i] + print (name + " is not a " + catstring + " card.") + return None + if c.cost > upto: + print (name + " costs " + str(c.cost)) + return None + return c + +def totalbuypower(cardlist): + TBP = 0 + for c in cardlist: + TBP += c.buypower + if c.category == "action": + TBP += c.coins + return TBP + +def cardsummaries(players): + cardsums={} + for player in players: + cardsums[player.name]=player.cardsummary() + cardsdf = pandas.DataFrame(cardsums).fillna(0).sort_index() + vp=cardsdf.loc[['VICTORY POINTS']] + cardsdf.drop(['VICTORY POINTS'],inplace=True) + return pandas.concat([cardsdf,vp],axis=0).fillna(0).astype(int) + +def countsupply(supply,form): + return [len(supply[a]) for a in form] + +def countcards(cards,form): + dcount = Counter(namesinlist(cards)) + return [dcount[a] for a in form] + +def rankcards(form,vector): + od = OrderedDict(zip(form,vector)) + sd = OrderedDict(sorted(od.items(),key = itemgetter(1),reverse=True)) + return list(sd.keys()) \ No newline at end of file diff --git a/projects/ohrlundk/dominion/README.md b/projects/ohrlundk/dominion/README.md new file mode 100644 index 0000000..9e00834 --- /dev/null +++ b/projects/ohrlundk/dominion/README.md @@ -0,0 +1,10 @@ +# Dominion +complete Dominion game in python, text-only + +Dominion is a popular deck-building game, for 2-4 players. Each card in the deck gives a player points or money, or lets a player perform a certain action when played. Each player tries to get the most points before the end of the game. As of July 2016, I have only programmed the base version. + +There are two versions of the game--one that uses a module and a main page, and one that includes all the code in one main page, useful for sharing with a friend who doesn't have python. (It can be executed in an online REPL, hence the name.) + +The list of players is hard-coded, so edit to play. Add a * at the beginning of the name for a computer player. + +The computer (currently) plays a very simple direct strategy. Its main advantage is that is has a perfect memory of every transaction, and an accurate, dispassionate calculation of when the game is likely to end. diff --git a/projects/ohrlundk/dominion/REPLdominion.py b/projects/ohrlundk/dominion/REPLdominion.py new file mode 100644 index 0000000..5499972 --- /dev/null +++ b/projects/ohrlundk/dominion/REPLdominion.py @@ -0,0 +1,853 @@ +import random +from collections import Counter, OrderedDict +from operator import itemgetter +import re +import pandas + +class Card(): + def __init__(self,name,category,cost,buypower,vpoints): + self.name = name + self.category = category + self.cost = cost + self.buypower = buypower + self.vpoints = vpoints + def react(self,player): + return False + +class Coin_card(Card): + def __init__(self,name,cost,buypower): + Card.__init__(self,name,"coin",cost,buypower,0) + +class Copper(Coin_card): + def __init__(self): + Coin_card.__init__(self,"Copper",0,1) + +class Silver(Coin_card): + def __init__(self): + Coin_card.__init__(self,"Silver",3,2) + +class Gold(Coin_card): + def __init__(self): + Coin_card.__init__(self,"Gold",6,3) + +class Victory_card(Card): + def __init__(self,name,cost,vpoints): + Card.__init__(self,name,"victory",cost,0,vpoints) + +class Estate(Victory_card): + def __init__(self): + Victory_card.__init__(self,"Estate",2,1) + +class Duchy(Victory_card): + def __init__(self): + Victory_card.__init__(self,"Duchy",5,3) + +class Province(Victory_card): + def __init__(self): + Victory_card.__init__(self,"Province",8,6) + +class Garden(Victory_card): + def __init__(self): + Victory_card.__init__(self,"Garden",4,0) + +class Curse(Card): + def __init__(self): + Card.__init__(self,"Curse","curse",0,0,-1) + +class Action_card(Card): + def __init__(self,name,cost,actions,cards,buys,coins): + Card.__init__(self,name,"action",cost,0,0) + self.actions = actions + self.cards = cards + self.buys = buys + self.coins = coins + def use(self,player,trash): + player.played.append(self) + player.hand.remove(self) + def augment(self,player): + player.actions+=self.actions + player.buys+=self.buys + player.purse+=self.coins + for i in range(self.cards): + player.draw() + def play(self,player,players,supply,trash): + pass + +class Woodcutter(Action_card): + def __init__(self): + Action_card.__init__(self,"Woodcutter",3,0,0,1,2) + +class Smithy(Action_card): + def __init__(self): + Action_card.__init__(self,"Smithy",4,0,3,0,0) + +class Laboratory(Action_card): + def __init__(self): + Action_card.__init__(self,"Laboratory",5,1,2,0,0) + +class Village(Action_card): + def __init__(self): + Action_card.__init__(self,"Village",3,2,1,0,0) + +class Festival(Action_card): + def __init__(self): + Action_card.__init__(self,"Festival",5,2,0,1,2) + +class Market(Action_card): + def __init__(self): + Action_card.__init__(self,"Market",5,1,1,1,1) + +class Chancellor(Action_card): + def __init__(self): + Action_card.__init__(self,"Chancellor",3,0,0,0,2) + def play(self,player,players,supply,trash): + if player.yesnoinput('Would you like to discard your entire deck?'): + player.discard = player.discard + player.deck + player.deck = [] + +class Workshop(Action_card): + def __init__(self): + Action_card.__init__(self,"Workshop",3,0,0,0,0) + def play(self,player,players,supply,trash): + player.gaincard(supply,4) + +class Moneylender(Action_card): + def __init__(self): + Action_card.__init__(self,"Moneylender",4,0,0,0,0) + def play(self,player,players,supply,trash): + c = getcard("Copper",supply,player.hand,"your hand") + if c: + trash.append(c) + player.hand.remove(c) + player.purse += 3 + +class Chapel(Action_card): + def __init__(self): + Action_card.__init__(self,"Chapel",2,0,0,0,0) + def play(self,player,players,supply,trash): + trashed=0 + while trashed<4 and len(player.hand)>0: + trashcard = input("Choose a card from your hand to trash: ") + if not trashcard: + break + c = getcard(trashcard,supply,player.hand,"your hand") + if c: + trash.append(c) + player.hand.remove(c) + trashed+=1 + +class Cellar(Action_card): + def __init__(self): + Action_card.__init__(self,"Cellar",2,1,0,0,0) + def play(self,player,players,supply,trash): + discarded=0 + while len(player.hand)>0: + dis_card=input("Choose a card from your hand to discard: ") + if not dis_card: + break + c = getcard(dis_card,supply,player.hand,"your hand") + if c: + player.discard.append(c) + player.hand.remove(c) + discarded+=1 + for j in range(discarded): + player.draw() + +class Remodel(Action_card): + def __init__(self): + Action_card.__init__(self,"Remodel",4,0,0,0,0) + def play(self,player,players,supply,trash): + while len(player.hand)>0: + this_card = input("Choose a card from your hand to remodel: ") + c = getcard(this_card,supply,player.hand,"your hand") + if c: + trash.append(c) + player.hand.remove(c) + player.gaincard(supply,c.cost+2) + break + +class Adventurer(Action_card): + def __init__(self): + Action_card.__init__(self,"Adventurer",6,0,0,0,0) + def play(self,player,players,supply,trash): + coins_added = 0 + while (player.deck or player.discard) and coins_added <2: + player.draw() + if player.hand[-1].category == "coin": + coins_added +=1 + else: + player.aside.append(player.hand.pop()) + +class Feast(Action_card): + def __init__(self): + Action_card.__init__(self,"Feast",4,0,0,0,0) + def use(self,player,trash): + trash.append(self) + player.hand.remove(self) + def play(self,player,players,supply,trash): + player.gaincard(supply,5) + +class Mine(Action_card): + def __init__(self): + Action_card.__init__(self,"Mine",5,0,0,0,0) + def play(self,player,players,supply,trash): + while "coin" in catinlist(player.hand): + this_card = input("Choose a coin from your hand to upgrade: ") + c = getcard(this_card,supply,player.hand,"your hand",["coin"]) + if c: + trash.append(c) + player.hand.remove(c) + while c.cost>2 or len(supply["Copper"])>0 or len(supply["Silver"])>0: + pick = input("Choose a coin to gain. Any coin up to " + str(c.cost+3)+": ") + g = getcard(pick,supply,categories=["coin"],upto=c.cost+3) + if g: + player.hand.append(g) + supply[pick].remove(g) + break + break + +class Library(Action_card): + def __init__(self): + Action_card.__init__(self,"Library",5,0,0,0,0) + def play(self,player,players,supply,trash): + while (player.deck or player.discard) and len(player.hand) <7: + player.draw(player.hold) + if (player.hold[-1].category == "action" and not player.yesnoinput("You drew " + player.hold[-1].name + ". Would you like to keep it?",", add to my hand", ", set it aside")): + player.aside.append(player.hold.pop()) + else: + player.hand.append(player.hold.pop()) + +class Moat(Action_card): + def __init__(self): + Action_card.__init__(self,"Moat",2,0,2,0,0) + def react(self,player): + player.show() + return player.yesnoinput(player.name + ", you have a " + self.name + + " in your hand. Do you want to block the attack?") + +class Council_Room(Action_card): + def __init__(self): + Action_card.__init__(self,"Council Room",5,0,3,1,0) + def play(self,this_player,players,supply,trash): + for player in players: + player.draw() + +class Witch(Action_card): + def __init__(self): + Action_card.__init__(self,"Witch",5,0,2,0,0) + def play(self,this_player,players,supply,trash): + if len(supply["Curse"])>0: + for player in players: + if player==this_player: + pass + else: + for c in player.hand: + if c.react(player): + break + else: + if len(supply["Curse"])>0: + player.discard.append(supply["Curse"].pop()) + +class Bureaucrat(Action_card): + def __init__(self): + Action_card.__init__(self,"Bureaucrat",4,0,0,0,0) + def play(self,this_player,players,supply,trash): + if len(supply["Silver"])>0: + this_player.deck.insert(0,supply["Silver"].pop()) + for player in players: + if (not player==this_player) and ("victory" in catinlist(player.hand)): + for c in player.hand: + if c.react(player): + break + else: + player.show() + while True: + putback = player.choose_discard(player.name + ", which victory card" + + " do you want to put on top of your deck?\n--> ") + c = getcard(putback,supply,player.hand,"your hand",["victory"]) + if c: + player.hand.remove(c) + player.deck.insert(0,c) + break + +class Militia(Action_card): + def __init__(self): + Action_card.__init__(self,"Militia",4,0,0,0,2) + def play(self,this_player,players,supply,trash): + for player in players: + if (not player==this_player) and len(player.hand)>3: + for c in player.hand: + if c.react(player): + break + else: + player.show() + while len(player.hand)>3: + dis_card=player.choose_discard(player.name + ", choose a card from your hand to discard: ") + if dis_card: + c = getcard(dis_card,supply,player.hand,"your hand") + if c: + player.hand.remove(c) + player.discard.append(c) + +class Spy(Action_card): + def __init__(self): + Action_card.__init__(self,"Spy",4,1,1,0,0) + def play(self,this_player,players,supply,trash): + for player in players: + for c in player.hand: + if c.react(player): + break + else: + b = player.draw([]) + if not b: + continue + else: + print("The first card in the deck of " + player.name + " is " + b.name) + if this_player.yesnoinput(this_player.name + ", do you want " + player.name + " to discard this?", + ", discard",", keep"): + player.discard.append(b) + else: + player.deck.insert(0,b) + #check logic of this structure + +class Thief(Action_card): + def __init__(self): + Action_card.__init__(self,"Thief",4,0,0,0,0) + def play(self,this_player,players,supply,trash): + for player in players: + if player == this_player: + continue + for c in player.hand: + if c.react(player): + break + else: + for i in range(2): + player.draw(player.hold) + print( player.name, namesinlist(player.hold)) + if "coin" in catinlist(player.hold): + while True: + burn = input("Which card would you like " + player.name + " to trash?\n-->") + c = getcard(burn,supply,player.hold," the top 2 cards",["coin"]) + if c: + player.hold.remove(c) + break + if this_player.yesnoinput("Do you want to steal it?",", it's mine!",", leave it in the trash."): + this_player.discard.append(c) + else: + trash.append(c) + player.discard=player.discard+player.hold + player.hold = [] + +class Throne_Room(Action_card): + def __init__(self): + Action_card.__init__(self,"Throne Room",4,0,0,0,0) + def play(self,player,players,supply,trash): + if "action" in catinlist(player.hand): + while True: + double = input("What card would you like to double?\n--> ") + c = getcard(double,supply,player.hand," your hand",["action"]) + if c: + c.use(player,trash) + c.augment(player) + c.play(player,players,supply,trash) + player.show() + c.augment(player) + c.play(player,players,supply,trash) + break + + +class Player(): + def __init__(self,name): + self.name = name + deal = [Copper()]*7 + [Estate()]*3 + random.shuffle(deal) + self.hand = deal[:5] + self.deck = deal[5:] + self.played = [] + self.discard = [] + self.aside = [] + self.hold = [] + random.shuffle(self.deck) + for i in range(5): + self.draw + def other(self): + return self.played+self.discard+self.hold+self.aside + def stack(self): + return (self.deck + self.hand + self.played + self.discard + self.aside + self.hold) + def draw(self,dest=None): + #defualt destination is player's hand + if dest==None: + dest = self.hand + #Replenish deck if necessary. + if len(self.deck)==0: + self.deck = self.discard + self.discard = [] + random.shuffle(self.deck) + #If deck has cards, add card to destination list + if len(self.deck)>0: + c = self.deck.pop(0) + dest.append(c) + return c + def turn(self,players,supply,trash): + self.show() + self.actions = 1 + self.buys = 1 + self.purse = 0 + #action phase + while self.actions>0 and 'action' in catinlist(self.hand): + playthis = input("Which card would you like to play? You have " + + str(self.actions) + " action(s). \n-Hit enter for no play. --> ") + if playthis: + c = getcard(playthis,supply,self.hand,"your hand",['action']) + if c: + self.actions = self.actions - 1 + c.use(self,trash) + c.augment(self) + c.play(self,players,supply,trash) + self.show() + else: + self.actions=0 + #buy phase + for c in self.hand: + self.purse += c.buypower + while self.buys>0: + buy_string = "Buying power is " + str(self.purse) + ". You have " + str(self.buys) + " buy" + if self.buys>1: + buy_string += "s" + buy_string += "." + print( buy_string) + purchase = input("What would you like to purchase? -Hit enter for no purchase.-\n--> ") + if not purchase: + break + else: + c = getcard(purchase,supply,upto=self.purse) + if c: + self.discard.append(supply[purchase].pop()) + self.buys = self.buys -1 + self.purse = self.purse - c.cost + + #cleanup phase + self.discard = self.discard + self.played + self.hand + self.aside + self.played = [] + self.hand = [] + self.aside = [] + for i in range(5): + self.draw() + + def gaincard(self,supply,upto): + while True: + gain = input("What would you like to get? Any card up to " + str(upto) + "\n--> ") + c = getcard(gain,supply,upto=upto) + if c: + self.discard.append(c) + supply[gain].remove(c) + break + def yesnoinput(self,prompt,yesstring='',nostring=''): + print(prompt + "\n1 - Yes" + yesstring + "\n0 - No" + nostring) + while True: + r = input("--> ") + if r == "0": + return False + if r == "1": + return True + + def choose_discard(self,prompt): + return input(prompt) + + def show(self): + print (self.name) + print ("hand: ", namesinlist(self.hand)) + shuffled_deck = namesinlist(self.deck) + random.shuffle(shuffled_deck) + print ("deck (not in order): ", shuffled_deck) + print ("discard: ", namesinlist(self.discard)) + if len(self.played)>0: + print ("played: ", namesinlist(self.played)) + if len(self.aside)>0: + print ("aside: ",namesinlist(self.aside)) + print ("\r") + + def action_balance(self): + balance = 0 + for c in self.stack(): + if c.category == "action": + balance = balance - 1 + c.actions + return 70*balance / len(self.stack()) + + def cardsummary(self): + summary = {} + for c in self.stack(): + if c.name in summary: + summary[c.name] += 1 + else: + summary[c.name] = 1 + return summary + + def calcpoints(self): + tally = 0 + gardens = 0 + n = 0 + for c in self.stack(): + tally += c.vpoints + n += 1 + if c.name == "Garden": + gardens+=1 + return tally + n//10 * gardens + +class ComputerPlayer(Player): + def __init__(self,name): + Player.__init__(self,name) + self.index = 0 + self.buygaintable = [] + #beginning and middle of game + self.buygaintable1 = ["Province","Gold","Laboratory","Festival","Witch", + "Council Room","Market","Militia","Adventurer","Smithy","Bureaucrat","Silver","Moat",""] + #end of game + self.buygaintable2 = ["Province","Garden","Duchy","Estate","Gold","Silver",""] + #beginning and middle of the game, too many action cards + self.buygaintable3 = ["Province","Gold","Festival","Laboratory","Market","Village", + "Silver",""] + self.playtable1 = ["Village","Festival","Market","Laboratory","Witch", + "Council Room","Militia","Adventurer","Smithy","Bureaucrat","Moat",""] + self.discardtable1 = ["Garden","Duchy","Province","Estate","Curse","Copper", + "Village","Bureaucrat","Silver","Militia","Smithy","Council Room","Witch", + "Festival","Market","Adventurer","Laboratory","Gold","Moat"] + + def turn(self,players,supply,trash): + self.show() + self.actions = 1 + self.buys = 1 + self.purse = 0 + #action phase + self.index = 0 + while self.actions>0 and 'action' in catinlist(self.hand): + playthis = self.playtable1[self.index] + if playthis: + c = self.getcard(playthis,supply,self.hand,"your hand",['action']) + if c: + #print (self.name + " plays " + c.name) + self.actions = self.actions - 1 + c.use(self,trash) + self.index=0 + c.augment(self) + c.play(self,players,supply,trash) + self.show() + else: + self.index += 1 + else: + self.actions=0 + #buy phase + if len(supply["Province"])>len(players)+totalbuypower(self.deck)/8: + if self.action_balance()<-10: + self.buygaintable = self.buygaintable3 + else: + self.buygaintable = self.buygaintable1 + else: + self.buygaintable = self.buygaintable2 + self.index = 0 + for c in self.hand: + self.purse += c.buypower + while self.buys>0: + purchase = self.buygaintable[self.index] + if not purchase: + break + else: + c = self.getcard(purchase,supply,upto=self.purse) + if c: + self.discard.append(supply[purchase].pop()) + self.index = 0 + self.buys = self.buys -1 + self.purse = self.purse - c.cost + #print (self.name + " bought " + c.name) + else: + self.index += 1 + + #cleanup phase + self.discard = self.discard + self.played + self.hand + self.aside + self.played = [] + self.hand = [] + self.aside = [] + for i in range(5): + self.draw() + + def getcard(self,name,supply,target_list=None,target_name= "the supply anymore",categories=['action','coin','curse','victory'],upto=100): + if not name in supply: + #print name + " is not in this game." + return None + if not target_list: + target_list = supply[name] + nameslist = namesinlist(target_list) + if not name in nameslist: + #print "There is no " + name + " in " + target_name + return None + i = nameslist.index(name) + c = target_list[i] + if c.category not in categories: + catstring = categories[0] + for i in categories[1:]: + catstring = catstring + " or " + categories[i] + #print name + " is not a " + catstring + " card." + return None + if c.cost > upto: + #print name + " costs " + str(c.cost) + return None + return c + + def choose_discard(self,prompt): + index = 0 + while True: + dis_card = self.discardtable1[index] + c = self.getcard(dis_card,[dis_card],self.hand) + if c: + return c.name + else: + index+=1 + + def yesnoinput(self,prompt,yesstring='',nostring=''): + return True + + def show(self): + pass + +class TablePlayer(ComputerPlayer): + def __init__(self,name): + ComputerPlayer.__init__(self,name) + self.index=0 + self.buygaintable=[] + q=re.match(r'([a-zA-Z]+)(\d+)',name) + if q: + self.number = q.group(2) + else: + print(name) + self.playtable1 = ["Village","Festival","Market","Laboratory","Witch", + "Council Room","Militia","Adventurer","Smithy","Bureaucrat","Moat",""] + self.discardtable1 = ["Garden","Duchy","Province","Estate","Curse","Copper", + "Village","Bureaucrat","Silver","Militia","Smithy","Council Room","Witch", + "Festival","Market","Adventurer","Laboratory","Gold","Moat"] + + def turn(self,players,supply,trash): + self.show() + self.actions = 1 + self.buys = 1 + self.purse = 0 + #action phase + self.index = 0 + while self.actions>0 and 'action' in catinlist(self.hand): + playthis = self.playtable1[self.index] + if playthis: + c = self.getcard(playthis,supply,self.hand,"your hand",['action']) + if c: + #print (self.name + " plays " + c.name) + self.actions = self.actions - 1 + c.use(self,trash) + self.index=0 + c.augment(self) + c.play(self,players,supply,trash) + self.show() + else: + self.index += 1 + else: + self.actions=0 + #buy phase + v= self.number + csvstring = r"Dominionbuy" + str(v) + ".csv" + buydf=pandas.read_csv(csvstring,na_filter=False) + sortedbuydf=buydf.sort_values("Buyvalues",ascending=False) + ranktable = sortedbuydf.Cardname + self.index = 0 + for c in self.hand: + self.purse += c.buypower + while self.buys>0: + purchase = ranktable.iloc[self.index] + if not purchase: + break + else: + c = self.getcard(purchase,supply,upto=self.purse) + if c: + self.discard.append(supply[purchase].pop()) + self.index = 0 + self.buys = self.buys -1 + self.purse = self.purse - c.cost + else: + self.index += 1 + + #cleanup phase + self.discard = self.discard + self.played + self.hand + self.aside + self.played = [] + self.hand = [] + self.aside = [] + for i in range(5): + self.draw() + + +def gameover(supply): + if len(supply["Province"])==0: + return True + out = 0 + for stack in supply: + if len(supply[stack])==0: + out+=1 + if out>=3: + return True + return False + +def namesinlist(cardlist): + namelist = [] + for c in cardlist: + namelist.append(c.name) + return namelist + +def catinlist(cardlist): + catlist = [] + for c in cardlist: + catlist.append(c.category) + return catlist + +def getcard(name,supply,target_list=None,target_name= "the supply anymore",categories=['action','coin','curse','victory'],upto=100): + if not name in supply: + print( name + " is not in this game.") + return None + if not target_list: + target_list = supply[name] + nameslist = namesinlist(target_list) + if not name in nameslist: + print ("There is no " + name + " in " + target_name) + return None + i = nameslist.index(name) + c = target_list[i] + if c.category not in categories: + catstring = categories[0] + for i in categories[1:]: + catstring = catstring + " or " + categories[i] + print (name + " is not a " + catstring + " card.") + return None + if c.cost > upto: + print (name + " costs " + str(c.cost)) + return None + return c + +def totalbuypower(cardlist): + TBP = 0 + for c in cardlist: + TBP += c.buypower + if c.category == "action": + TBP += c.coins + return TBP + +def countsupply(supply,form): + return [len(supply[a]) for a in form] + +def countcards(cards,form): + dcount = Counter(namesinlist(cards)) + return [dcount[a] for a in form] + +def rankcards(form,vector): + od = OrderedDict(zip(form,vector)) + sd = OrderedDict(sorted(od.items(),key = itemgetter(1),reverse=True)) + return list(sd.keys()) + +#import Dominion +#import random +from collections import defaultdict + +#Get player names +player_names = ["Timothy","*Grover","*Elmo"] + +#number of curses and victory cards +if len(player_names)>2: + nV=12 +else: + nV=8 +nC = -10 + 10 * len(player_names) + +#Define box +box = {} +box["Woodcutter"]=[Woodcutter()]*10 +box["Smithy"]=[Smithy()]*10 +box["Laboratory"]=[Laboratory()]*10 +box["Village"]=[Village()]*10 +box["Festival"]=[Festival()]*10 +box["Market"]=[Market()]*10 +box["Chancellor"]=[Chancellor()]*10 +box["Workshop"]=[Workshop()]*10 +box["Moneylender"]=[Moneylender()]*10 +box["Chapel"]=[Chapel()]*10 +box["Cellar"]=[Cellar()]*10 +box["Remodel"]=[Remodel()]*10 +box["Adventurer"]=[Adventurer()]*10 +box["Feast"]=[Feast()]*10 +box["Mine"]=[Mine()]*10 +box["Library"]=[Library()]*10 +box["Garden"]=[Garden()]*nV +box["Moat"]=[Moat()]*10 +box["Council Room"]=[Council_Room()]*10 +box["Witch"]=[Witch()]*10 +box["Bureaucrat"]=[Bureaucrat()]*10 +box["Militia"]=[Militia()]*10 +box["Spy"]=[Spy()]*10 +box["Thief"]=[Thief()]*10 +box["Throne Room"]=[Throne_Room()]*10 + +supply_order = {0:['Curse','Copper'],2:['Estate','Cellar','Chapel','Moat'], + 3:['Silver','Chancellor','Village','Woodcutter','Workshop'], + 4:['Garden','Bureaucrat','Feast','Militia','Moneylender','Remodel','Smithy','Spy','Thief','Throne Room'], + 5:['Duchy','Market','Council Room','Festival','Laboratory','Library','Mine','Witch'], + 6:['Gold','Adventurer'],8:['Province']} + +#Pick 10 cards from box to be in the supply. +boxlist = [k for k in box] +random.shuffle(boxlist) +random10 = boxlist[:10] +supply = defaultdict(list,[(k,box[k]) for k in random10]) + + +#The supply always has these cards +supply["Copper"]=[Copper()]*(60-len(player_names)*7) +supply["Silver"]=[Silver()]*40 +supply["Gold"]=[Gold()]*30 +supply["Estate"]=[Estate()]*nV +supply["Duchy"]=[Duchy()]*nV +supply["Province"]=[Province()]*nV +supply["Curse"]=[Curse()]*nC + +#initialize the trash +trash = [] + +#Costruct the Player objects +players = [] +for name in player_names: + if name[0]=="*": + players.append(ComputerPlayer(name[1:])) + elif name[0]=="^": + players.append(TablePlayer(name[1:])) + else: + players.append(Player(name)) + +#Play the game +turn = 0 +while not gameover(supply): + turn += 1 + print("\r") + for value in supply_order: + print (value) + for stack in supply_order[value]: + if stack in supply: + print (stack, len(supply[stack])) + print("\r") + for player in players: + print (player.name,player.calcpoints()) + print ("\rStart of turn " + str(turn)) + for player in players: + if not gameover(supply): + print("\r") + player.turn(players,supply,trash) + + +#Final score +print ("\r") +for player in players: + print (player.name,player.calcpoints()) + +print ("\n") +for player in players: + print (player.name,player.cardsummary()) \ No newline at end of file diff --git a/projects/ohrlundk/dominion/playDominion.py b/projects/ohrlundk/dominion/playDominion.py new file mode 100644 index 0000000..b4d6021 --- /dev/null +++ b/projects/ohrlundk/dominion/playDominion.py @@ -0,0 +1,119 @@ +# -*- coding: utf-8 -*- +""" +Created on Tue Oct 13 15:42:42 2015 + +@author: tfleck +""" + +import Dominion +import random +from collections import defaultdict + +#Get player names +player_names = ["Annie","*Ben","*Carla"] + +#number of curses and victory cards +if len(player_names)>2: + nV=12 +else: + nV=8 +nC = -10 + 10 * len(player_names) + +#Define box +box = {} +box["Woodcutter"]=[Dominion.Woodcutter()]*10 +box["Smithy"]=[Dominion.Smithy()]*10 +box["Laboratory"]=[Dominion.Laboratory()]*10 +box["Village"]=[Dominion.Village()]*10 +box["Festival"]=[Dominion.Festival()]*10 +box["Market"]=[Dominion.Market()]*10 +box["Chancellor"]=[Dominion.Chancellor()]*10 +box["Workshop"]=[Dominion.Workshop()]*10 +box["Moneylender"]=[Dominion.Moneylender()]*10 +box["Chapel"]=[Dominion.Chapel()]*10 +box["Cellar"]=[Dominion.Cellar()]*10 +box["Remodel"]=[Dominion.Remodel()]*10 +box["Adventurer"]=[Dominion.Adventurer()]*10 +box["Feast"]=[Dominion.Feast()]*10 +box["Mine"]=[Dominion.Mine()]*10 +box["Library"]=[Dominion.Library()]*10 +box["Gardens"]=[Dominion.Gardens()]*nV +box["Moat"]=[Dominion.Moat()]*10 +box["Council Room"]=[Dominion.Council_Room()]*10 +box["Witch"]=[Dominion.Witch()]*10 +box["Bureaucrat"]=[Dominion.Bureaucrat()]*10 +box["Militia"]=[Dominion.Militia()]*10 +box["Spy"]=[Dominion.Spy()]*10 +box["Thief"]=[Dominion.Thief()]*10 +box["Throne Room"]=[Dominion.Throne_Room()]*10 + +supply_order = {0:['Curse','Copper'],2:['Estate','Cellar','Chapel','Moat'], + 3:['Silver','Chancellor','Village','Woodcutter','Workshop'], + 4:['Gardens','Bureaucrat','Feast','Militia','Moneylender','Remodel','Smithy','Spy','Thief','Throne Room'], + 5:['Duchy','Market','Council Room','Festival','Laboratory','Library','Mine','Witch'], + 6:['Gold','Adventurer'],8:['Province']} + +#Pick 10 cards from box to be in the supply. +boxlist = [k for k in box] +random.shuffle(boxlist) +random10 = boxlist[:10] +supply = defaultdict(list,[(k,box[k]) for k in random10]) + + +#The supply always has these cards +supply["Copper"]=[Dominion.Copper()]*(60-len(player_names)*7) +supply["Silver"]=[Dominion.Silver()]*40 +supply["Gold"]=[Dominion.Gold()]*30 +supply["Estate"]=[Dominion.Estate()]*nV +supply["Duchy"]=[Dominion.Duchy()]*nV +supply["Province"]=[Dominion.Province()]*nV +supply["Curse"]=[Dominion.Curse()]*nC + +#initialize the trash +trash = [] + +#Costruct the Player objects +players = [] +for name in player_names: + if name[0]=="*": + players.append(Dominion.ComputerPlayer(name[1:])) + elif name[0]=="^": + players.append(Dominion.TablePlayer(name[1:])) + else: + players.append(Dominion.Player(name)) + +#Play the game +turn = 0 +while not Dominion.gameover(supply): + turn += 1 + print("\r") + for value in supply_order: + print (value) + for stack in supply_order[value]: + if stack in supply: + print (stack, len(supply[stack])) + print("\r") + for player in players: + print (player.name,player.calcpoints()) + print ("\rStart of turn " + str(turn)) + for player in players: + if not Dominion.gameover(supply): + print("\r") + player.turn(players,supply,trash) + + +#Final score +dcs=Dominion.cardsummaries(players) +vp=dcs.loc['VICTORY POINTS'] +vpmax=vp.max() +winners=[] +for i in vp.index: + if vp.loc[i]==vpmax: + winners.append(i) +if len(winners)>1: + winstring= ' and '.join(winners) + ' win!' +else: + winstring = ' '.join([winners[0],'wins!']) + +print("\nGAME OVER!!!\n"+winstring+"\n") +print(dcs) \ No newline at end of file From 5d0759e44922c9c66ebebfb950091e88abeed434 Mon Sep 17 00:00:00 2001 From: kohrlund <39636053+kohrlund@users.noreply.github.com> Date: Sun, 5 Jan 2020 16:38:48 -0600 Subject: [PATCH 11/13] Create readme.md --- projects/ohrlundk/readme.md | 2 ++ 1 file changed, 2 insertions(+) create mode 100644 projects/ohrlundk/readme.md diff --git a/projects/ohrlundk/readme.md b/projects/ohrlundk/readme.md new file mode 100644 index 0000000..657b01f --- /dev/null +++ b/projects/ohrlundk/readme.md @@ -0,0 +1,2 @@ +Name: Kevin J. Ohrlund +ONID: Ohrlundk From dce433b73f1dcf0dbda71717b1213066b9e990c7 Mon Sep 17 00:00:00 2001 From: kohrlund <39636053+kohrlund@users.noreply.github.com> Date: Sun, 5 Jan 2020 16:39:25 -0600 Subject: [PATCH 12/13] Delete readme.md --- projects/ohrlundk/dominion/readme.md | 3 --- 1 file changed, 3 deletions(-) delete mode 100644 projects/ohrlundk/dominion/readme.md diff --git a/projects/ohrlundk/dominion/readme.md b/projects/ohrlundk/dominion/readme.md deleted file mode 100644 index 7486cda..0000000 --- a/projects/ohrlundk/dominion/readme.md +++ /dev/null @@ -1,3 +0,0 @@ -#Your onid folder should contain a readme file that contains your name and your ONID. -Name: Kevin J. Ohrlund -ONID: Ohrlundk From c3764878eeb331938139db5ff8abb45b46a28bf5 Mon Sep 17 00:00:00 2001 From: kohrlund <39636053+kohrlund@users.noreply.github.com> Date: Sun, 5 Jan 2020 16:42:29 -0600 Subject: [PATCH 13/13] Update readme.md --- projects/ohrlundk/readme.md | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/projects/ohrlundk/readme.md b/projects/ohrlundk/readme.md index 657b01f..8b9b43c 100644 --- a/projects/ohrlundk/readme.md +++ b/projects/ohrlundk/readme.md @@ -1,2 +1 @@ -Name: Kevin J. Ohrlund -ONID: Ohrlundk +#Kevin J. Ohrlund, ohrlundk