#!/usr/bin/Python
import random

#problems with the model include:
# no mulligans
# assume all lands are equal
# ad nauseam will spend up to about 10 life
# logic for playing cards is pretty simple
# assumes taht once you get swans and seismic out, you win
debug=True

class Card:
    def __init__(self, name, cost=-1, cascade=False):
        self.name = name
        self.cascade = cascade
        self.cost = cost
    
    def __str__(self):
        if self.cost == -1:
            return "Land"
        if self.cascade:
            return self.name
        return self.name

def buildModiSwans():
    deck=[]
    for i in range(0,42):
        deck.append(Card("Land", -1, False))

    for i in range(0,4):
        deck.append(Card("BloodbraidElf", 4, True))
        deck.append(Card("BituminousBlast", 5, True))
        deck.append(Card("SwansofBrynArgoll", 4, False))
        deck.append(Card("SeismicAssault", 3, False))

    for i in range (0,2):
        deck.append(Card("AdNauseam", 5, False))
    return deck

def draw(meta):
    if len(meta["deck"]) <= 0:
        dprint("How the fuck did you deck yourself?")
        return False
    meta["hand"].append(meta["deck"].pop(0))
    return meta["hand"][-1]

def printList(list):
    for i in list:
        dprint(i)
    dprintln()

def dprint(s=""):
    if debug:
        print s,

def dprintln(s=""):
    if debug:
        print s

def playGame():
    deck = buildModiSwans()
    random.shuffle(deck)

    meta={"lands":0, "assault":False, "swans":False, "deck":deck, "hand":[], "life":20}
    for i in range(0,7):
        draw(meta)

    dprintln("DECK")
    printList(deck)
    dprintln("HAND")
    printList(meta["hand"])

    for i in range(1,100):
        dprintln("Turn " + str(i))
        result = playTurn(i,meta)
        if result == -1:
            dprintln("You lost; how could you lose in this simulation?")
            return -i;
        if result == 1:
            dprint("You won on turn "+str(i)+"!")
            return i;
    
def handContains(hand,cardName):
    for i in hand:
        if i.name == cardName:
            return i
    return False

def playLand(meta):
    land = handContains(meta["hand"], "Land")
    if land:
        meta["hand"].remove(land)
        meta["lands"] += 1
        return True
    return False

def canPlay(card, mana):
    return card.cost != -1 and card.cost <= mana

def playCard(card, meta):
    dprintln("You play " + card.name)

    if card.name == "AdNauseam":
        next=draw(meta)
        if next.cost != -1:
            meta["life"] -= next.cost
        dprintln("Off of Ad Nauseam, you drew a " + next.name)

        while meta["life"] > 14 and len(meta["deck"]) > 1:
            next=draw(meta)
            if next.cost != -1:
                meta["life"] -= next.cost
            dprintln("Off of Ad Nauseam, you drew a " + next.name)
        dprintln("Your life is now " + str(meta["life"]) + " because of Ad Nauseam")

    if card.name == "SeismicAssault":
        meta["assault"] = True

    if card.name == "SwansofBrynArgoll":
        meta["swans"] = True

    if card.cascade:
        cascade(card, meta)


def castCard(card, meta):
    meta["hand"].remove(card)
    meta["mana"] -= card.cost
    playCard(card, meta)

def cascade(card, meta):
    junk = []
    
    next = meta["deck"].pop(0)
    while len(meta["deck"]) > 0 and (next.cost == -1 or next.cost >= card.cost):
        junk.append(next)
        next = meta["deck"].pop(0)
    
    if next.cost < card.cost and next.cost != -1:
        dprint("Cascade, so")
        playCard(next, meta)
    else:
        junk.append(next)
    
    if len(junk) != 0:
        random.shuffle(junk)
        while len(junk) > 0:
            meta["deck"].append(junk.pop(0))

def playStrategy(meta):

    if not meta["swans"]:
        swans=handContains(meta["hand"],"SwansofBrynArgoll")
        if swans and canPlay(swans,meta["mana"]):
            castCard(swans, meta)

    if not meta["assault"]:
        assault=handContains(meta["hand"],"SeismicAssault")
        if assault and canPlay(assault,meta["mana"]):
            castCard(assault, meta)

    if not meta["swans"]:
        blast = handContains(meta["hand"],"BituminousBlast")
        if blast and canPlay(blast, meta["mana"]):
            castCard(blast, meta)

    if not meta["assault"]:
        elf = handContains(meta["hand"],"BloodbraidElf")
        if elf and canPlay(elf, meta["mana"]):
            castCard(elf, meta)
    
    if not meta["assault"] or not meta["swans"]:
        ad = handContains(meta["hand"],"AdNauseam")
        if ad and canPlay(ad, meta["mana"]) and meta["life"] >= 14:
            castCard(ad, meta)
            playStrategy(meta)


def playTurn(turn,meta):
    if not turn==1 and not draw(meta):
        dprintln("You lost")
        return -1

    if not turn==1:
        dprintln("You drew a " + str(meta["hand"][-1]))

    playLand(meta)
    
    meta["mana"] = meta["lands"]
    
    playStrategy(meta)

    if meta["assault"] and meta["swans"]:
        return 1

    return 0

def simulateDeck():
    global debug
    debug = False

    epochs = 100000

    turns=[]
    for i in range(0,61):
        turns.append(0)

    for i in range(0,epochs):
        outcome=playGame()        
        if outcome > 0:
            turns[outcome] += 1

    cumul = 0
    print "Turn Wins  %age   %cumulative"
    for i in range(len(turns)):
        cumul += turns[i] / float(epochs)
        print "%4d %5d %.4f %.4f" %(i,turns[i],turns[i]/float(epochs),cumul)
