name = '2018-02-05-oop-vs-procedural'
title = 'Advent of Code Battle'
tags = 'oop'
author = 'Mark Prosser'
from nb_tools import connect_notebook_to_post
from IPython.core.display import HTML
html = connect_notebook_to_post(name, title, tags, author)
Instructions for the example in the code can be found here: https://adventofcode.com/2015/day/21 And other approaches to this problem (including other languages) can be found on Reddit: https://www.reddit.com/r/adventofcode/comments/3xspyl/day_21_solutions/
First, we import Packages
import numpy as np
import itertools
import warnings
warnings.simplefilter(action='ignore')
startbosshp = 104
bossdamage = 8
bossarmor = 1
startplayerhp = 100
playerdamage = 0
playerarmor = 0
from collections import namedtuple
Item = namedtuple('item', ['name', 'cost', 'damage', 'armor'])
weaponsnt = [
Item('Dagger', 8, 4, 0),
Item('Shortsword', 10, 5, 0),
Item('Warhammer', 25, 6, 0),
Item('Longsword', 40, 7, 0),
Item('Greataxe', 74, 8, 0),
]
armornt = [
Item('Leather', 13, 0, 1),
Item('Chainmail', 31, 0, 2),
Item('Splintmail', 53, 0, 3),
Item('Bandedmail', 75, 0, 4),
Item('Platemail', 102, 0, 5),
Item('Naked', 0, 0, 0),
]
ringsnt = [
Item('Damage +1', 25, 1, 0),
Item('Damage +2', 50, 2, 0),
Item('Damage +3', 100, 3, 0),
Item('Defense +1', 20, 0, 1),
Item('Defense +2', 40, 0, 2),
Item('Defense +3', 80, 0, 3),
]
wn = 5 #weapons
an = 6 #armor
rn = 22 #rings
comb = wn * an * rn #total number of possibilities
#setup arrays
player_spent = np.full((wn, an, rn), np.nan)
player_damage = np.full((wn, an, rn), np.nan) #damage
player_armor = np.full((wn, an, rn), np.nan) #cost
#setup arrays
#weapons = np.full((wn, 3), 0)
armor = np.full((an, 3), 0)
rings0 = np.full((6, 3), 0)
rings = np.full((rn, 3), 0)
weapons = np.array([[8, 4, 0], [10, 5, 0], [25, 6, 0], [40, 7, 0], [74, 8, 0]])
armor[:,:] = [[13, 0, 1], [31, 0, 2], [53, 0, 3], [75, 0, 4], [102, 0, 5], [0, 0, 0]]
rings0[:,:] = [[25, 1, 0], [50, 2, 0], [100, 3, 0], [20, 0, 1], [40, 0, 2], [80, 0, 3]]
ring_combs = (list(itertools.combinations(range(6), 2)))
print(ring_combs)
[(0, 1), (0, 2), (0, 3), (0, 4), (0, 5), (1, 2), (1, 3), (1, 4), (1, 5), (2, 3), (2, 4), (2, 5), (3, 4), (3, 5), (4, 5)]
for i in range(0, len(ring_combs)):
rings[i, 0] = int(rings0[ring_combs[i][0]][0] + rings0[ring_combs[i][1]][0]) #spent
rings[i, 1] = int(rings0[ring_combs[i][0]][1] + rings0[ring_combs[i][1]][1]) #damage
rings[i, 2] = int(rings0[ring_combs[i][0]][2] + rings0[ring_combs[i][1]][2]) #armor
rings[15:-1, :] = rings0[:,:]
print(rings)
[[ 75 3 0] [125 4 0] [ 45 1 1] [ 65 1 2] [105 1 3] [150 5 0] [ 70 2 1] [ 90 2 2] [130 2 3] [120 3 1] [140 3 2] [180 3 3] [ 60 0 3] [100 0 4] [120 0 5] [ 25 1 0] [ 50 2 0] [100 3 0] [ 20 0 1] [ 40 0 2] [ 80 0 3] [ 0 0 0]]
for w in range(0, wn):
for a in range(0, an):
for r in range(0, rn):
player_spent[w, a, r] = weapons[w, 0] + armor[a, 0] + rings[r, 0]
player_damage[w, a, r] = weapons[w, 1] + armor[a, 1] + rings[r, 1]
player_armor[w, a, r] = weapons[w, 2] + armor[a, 2] + rings[r, 2]
playerspent = player_spent[0,0,0]
print('playerspent=',playerspent)
playerdamage = player_damage[0,0,0]
print('playerdamage=',playerdamage)
playerarmor = player_armor[0,0,0]
print('playerarmor=',playerarmor)
playerspent= 96.0 playerdamage= 7.0 playerarmor= 1.0
bestspend = 999
wi = 0
ai = 0
ri = 0
worstspend = 0
wi2 = 0
ai2 = 0
ri2 = 0
win_no = 0
lose_no = 0
for w in range(0, wn): #length=5
for a in range(0, an): #length=6
for r in range(0, rn): #length=22
#get 1 of 660
playerspent = player_spent[w, a, r]
playerdamage = player_damage[w, a, r]
playerarmor = player_armor[w, a, r]
bosshp = startbosshp
playerhp = startplayerhp
playeractdam = playerdamage - bossarmor
if (playeractdam < 1):
playeractdam = 1
# playactdam = max(playeractdam, 1)
bossactdam = bossdamage - playerarmor
if (bossactdam < 1):
bossactdam = 1
while (bosshp > 0) and (playerhp > 0):
#bosshp = bosshp - playeractdam
bosshp -= playeractdam
#playerhp = playerhp - bossactdam
playerhp -= bossactdam
if playerhp > bosshp: #if I win
#win_no = win_no += 1
win_no += 1
if playerspent < bestspend:
bestspend = playerspent
wi = w
ai = a
ri = r
if playerhp < bosshp: #if I lose
#lose_no = lose_no + 1
lose_no += 1
if playerspent > worstspend:
worstspend = playerspent
wi2 = w
ai2 = a
ri2 = r
print('lowest cost while still winning =',bestspend)
print(weaponsnt[wi])
print(armornt[ai])
print('ringscombi',rings[ri])
print(wi)
print(ai)
print(ri)
print('-')
print('highest cost while still losing =',worstspend)
print(weaponsnt[wi2])
print(armornt[ai2])
print('ringscombi',rings[ri2])
print(wi2)
print(ai2)
print(ri2)
print('-')
print('win_no=',win_no)
print('lose_no=',lose_no)
lowest cost while still winning = 91.0 item(name='Longsword', cost=40, damage=7, armor=0) item(name='Chainmail', cost=31, damage=0, armor=2) ringscombi [20 0 1] 3 1 18 - highest cost while still losing = 158.0 item(name='Dagger', cost=8, damage=4, armor=0) item(name='Naked', cost=0, damage=0, armor=0) ringscombi [150 5 0] 0 5 5 - win_no= 525 lose_no= 135
ww = 0
aa = 5
rr = 5
playerspend = player_spent[ww, aa, rr]
playerdamage = player_damage[ww, aa, rr]
playerarmor = player_armor[ww, aa, rr]
bosshp = startbosshp
playerhp = startplayerhp
playeractdam = playerdamage - bossarmor
if (playeractdam < 1):
playeractdam = 1
bossactdam = bossdamage - playerarmor
if (bossactdam < 1):
bossactdam = 1
while (bosshp > 0) & (playerhp > 0):
bosshp = bosshp - playeractdam
playerhp = playerhp - bossactdam
print('bosshp=',bosshp)
print('playerhp=',playerhp)
print('-')
bosshp= 96.0 playerhp= 92.0 - bosshp= 88.0 playerhp= 84.0 - bosshp= 80.0 playerhp= 76.0 - bosshp= 72.0 playerhp= 68.0 - bosshp= 64.0 playerhp= 60.0 - bosshp= 56.0 playerhp= 52.0 - bosshp= 48.0 playerhp= 44.0 - bosshp= 40.0 playerhp= 36.0 - bosshp= 32.0 playerhp= 28.0 - bosshp= 24.0 playerhp= 20.0 - bosshp= 16.0 playerhp= 12.0 - bosshp= 8.0 playerhp= 4.0 - bosshp= 0.0 playerhp= -4.0 -
# class Boss:
# def __init__(self, hp, damage, armor):
# self.hp = hp
# self.damage = damage
# self.armor = armor
# def calc_actdamage(self, playerarmor):
# self.actdamage = self.damage - playerarmor
# if (self.actdamage < 1):
# self.actdamage = 1
# class Player:
# def __init__(self, spent, hp, damage, armor):
# self.spent = spent
# self.hp = hp
# self.damage = damage
# self.armor = armor
# def calc_actdamage(self, bossarmor):
# self.actdamage = self.damage - bossarmor
# if (self.actdamage < 1):
# self.actdamage = 1
class RpgChara:
def __init__(self, hp, damage, armor):
self.hp = hp
self.damage = damage
self.armor = armor
def calc_actdamage(self, enemyarmor):
self.actdamage = self.damage - enemyarmor
if (self.actdamage < 1):
self.actdamage = 1
class Boss(RpgChara):
pass
class Player(RpgChara):
def __init__(self, spent, hp, damage, armor):
super().__init__(hp, damage, armor)
self.spent = spent
bestspend = 999 #too high in order to come down
wi = 0
ai = 0
ri = 0
worstspend = 0 #too low in order to go up
wi2 = 0
ai2 = 0
ri2 = 0
win_no = 0
lose_no = 0
for w in range(0, wn): #length5
for a in range(0, an): #length6
for r in range(0, rn): #length22
#get 1 of 660 instances per loop
boss_i = Boss(startbosshp, bossdamage, bossarmor)
player_i = Player(player_spent[w, a, r], startplayerhp, player_damage[w, a, r], \
player_armor[w, a, r])
#but what is their actual damage
boss_i.calc_actdamage(player_i.armor)
player_i.calc_actdamage(boss_i.armor)
while (boss_i.hp > 0) & (player_i.hp > 0):
boss_i.hp -= player_i.actdamage
player_i.hp -= boss_i.actdamage
if player_i.hp > boss_i.hp: #if I win
win_no += 1
if player_i.spent < bestspend:
bestspend = player_i.spent
wi = w
ai = a
ri = r
if player_i.hp < boss_i.hp: #if I lose
lose_no += 1
if player_i.spent > worstspend:
worstspend = player_i.spent
wi2 = w
ai2 = a
ri2 = r
print('lowest spend while still winning =',bestspend)
print(weaponsnt[wi])
print(armornt[ai])
print('ringscombi',rings[ri])
print(ri)
print('-')
print('highest spend while still losing =',worstspend)
print(weaponsnt[wi2])
print(armornt[ai2])
print('ringscombi',rings[ri2])
print(ri2)
print('-')
print('win_no=',win_no)
print('lose_no=',lose_no)
lowest spend while still winning = 91.0 item(name='Longsword', cost=40, damage=7, armor=0) item(name='Chainmail', cost=31, damage=0, armor=2) ringscombi [20 0 1] 18 - highest spend while still losing = 158.0 item(name='Dagger', cost=8, damage=4, armor=0) item(name='Naked', cost=0, damage=0, armor=0) ringscombi [150 5 0] 5 - win_no= 525 lose_no= 135
HTML(html)
This post was written as an IPython (Jupyter) notebook. You can view or download it using nbviewer.