Advent of code

 21 décembre 2015 

  RPG Simulator 20XX :
  1. code.py
from pprint import pprint
import itertools, math

def toDict(t):
    return [dict(zip(['name', 'cost', 'damage', 'armor'], item)) for item in t]

WEAPONS = toDict([ ['Dagger', 8, 4, 0], ['Shortsword', 10, 5, 0], ['Warhammer', 25, 6, 0], ['Longsword', 40, 7, 0], ['Greataxe', 74, 8, 0] ])
ARMORS  = toDict([ ['Leather', 13, 0, 1], ['Chainmail', 31, 0, 2], ['Splintmail', 53, 0, 3], ['Bandedmail', 75, 0, 4], ['Platemail', 102, 0, 5] ])
RINGS   = toDict([ ['Damage +1', 25, 1, 0], ['Damage +2', 50, 2, 0], ['Damage +3', 100, 3, 0], ['Defense +1', 20, 0, 1], ['Defense +2', 40, 0, 2], ['Defense +3', 80, 0, 3] ])    

ITEMS_CATEGORIES = [
    {'list':WEAPONS, 'nbs':[1]},
    {'list':ARMORS,  'nbs':[0,1]},
    {'list':RINGS,   'nbs':[0,1,2]}
]

BOSS_POINTS = 109
BOSS_DAMAGE = 8
BOSS_ARMOR = 2
MY_POINTS = 100


def choices(category):
    ### oneliner :
    # return itertools.chain(*[itertools.combinations(category['list'], nb) for nb in category['nbs']])
    r = []
    for nb in category['nbs']:
        r.extend(itertools.combinations(category['list'], nb))
    return r
        
def nbAttacksTillDeath(hitpoints, damage, armor):
    return math.ceil(hitpoints / max(damage - armor, 1))

def isWinningItems(items):
    my_damage = sum([item['damage'] for item in items])
    my_armor  = sum([item['armor'] for item in items])
    return nbAttacksTillDeath(BOSS_POINTS, my_damage, BOSS_ARMOR) <= nbAttacksTillDeath(MY_POINTS, BOSS_DAMAGE, my_armor)

def goldCost(items):
    return sum([item['cost'] for item in items])

minGold = None
minItems = None
maxGold = None
maxItems = None
for items in itertools.product(*[choices(cat) for cat in ITEMS_CATEGORIES]):
    items = list(itertools.chain(*items))
    cost = goldCost(items)
    if isWinningItems(items):
        if minGold == None or cost < minGold:
            minGold = cost
            minItems = items
    else:
        if maxGold == None or cost > maxGold:
            maxGold = cost
            maxItems = items
print(minGold, minItems)
print(maxGold, maxItems)