X-Git-Url: https://git.njae.me.uk/?p=advent-of-code-15.git;a=blobdiff_plain;f=advent21.ipynb;fp=advent21.ipynb;h=6fbd087a1835f8bf15baf5885d851c33d933ac12;hp=0000000000000000000000000000000000000000;hb=1dbbda35a8b4d52d61bb12cafd5cbc1eb360206f;hpb=f0197028478b8fbc529908c44434c4e1cd3c7780 diff --git a/advent21.ipynb b/advent21.ipynb new file mode 100644 index 0000000..6fbd087 --- /dev/null +++ b/advent21.ipynb @@ -0,0 +1,389 @@ +{ + "cells": [ + { + "cell_type": "code", + "execution_count": 133, + "metadata": { + "collapsed": true + }, + "outputs": [], + "source": [ + "import collections\n", + "import itertools" + ] + }, + { + "cell_type": "code", + "execution_count": 134, + "metadata": { + "collapsed": true + }, + "outputs": [], + "source": [ + "def player_wins_fight(player, boss, verbose=False):\n", + " boss_hp = boss['hp']\n", + " pc_hp = player['hp']\n", + " while pc_hp > 0 and boss_hp > 0:\n", + " boss_hp -= max(player['damage'] - boss['armour'], 1)\n", + " pc_hp -= max(boss['damage'] - player['armour'], 1)\n", + " if verbose:\n", + " print('PC:', player['hp'], ' . Boss:', boss_hp)\n", + " if boss_hp <= 0:\n", + " return True\n", + " else:\n", + " return False" + ] + }, + { + "cell_type": "code", + "execution_count": 135, + "metadata": { + "collapsed": false + }, + "outputs": [ + { + "data": { + "text/plain": [ + "True" + ] + }, + "execution_count": 135, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "pc = {'hp': 8, 'damage': 5, 'armour': 5}\n", + "boss = {'hp': 12, 'damage': 7, 'armour': 2}\n", + "player_wins_fight(pc, boss)" + ] + }, + { + "cell_type": "code", + "execution_count": 136, + "metadata": { + "collapsed": false + }, + "outputs": [ + { + "data": { + "text/plain": [ + "({'armour': 5, 'damage': 5, 'hp': 8}, {'armour': 2, 'damage': 7, 'hp': 12})" + ] + }, + "execution_count": 136, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "pc, boss" + ] + }, + { + "cell_type": "code", + "execution_count": 137, + "metadata": { + "collapsed": false + }, + "outputs": [ + { + "data": { + "text/plain": [ + "{'armour': 2, 'damage': 8, 'hp': 100}" + ] + }, + "execution_count": 137, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "boss = {}\n", + "for l in open('advent21.txt').readlines():\n", + " t, v = l.strip().split(': ')\n", + " if t == 'Hit Points': \n", + " boss['hp'] = int(v)\n", + " elif t == 'Armor': \n", + " boss['armour'] = int(v)\n", + " else:\n", + " boss[t.lower()] = int(v)\n", + "boss" + ] + }, + { + "cell_type": "code", + "execution_count": 138, + "metadata": { + "collapsed": true + }, + "outputs": [], + "source": [ + "weapons_s = \"\"\"Dagger 8 4 0\n", + "Shortsword 10 5 0\n", + "Warhammer 25 6 0\n", + "Longsword 40 7 0\n", + "Greataxe 74 8 0\"\"\"\n", + "\n", + "armour_s = \"\"\"Leather 13 0 1\n", + "Chainmail 31 0 2\n", + "Splintmail 53 0 3\n", + "Bandedmail 75 0 4\n", + "Platemail 102 0 5\"\"\"\n", + "\n", + "rings_s = \"\"\"Damage+1 25 1 0\n", + "Damage+2 50 2 0\n", + "Damage+3 100 3 0\n", + "Defense+1 20 0 1\n", + "Defense+2 40 0 2\n", + "Defense+3 80 0 3\"\"\"" + ] + }, + { + "cell_type": "code", + "execution_count": 140, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "def parse_table(table):\n", + " d = []\n", + " for l in table.split('\\n'):\n", + " ls = l.split()\n", + " d += [{'name': ls[0].strip(),\n", + " 'cost': int(ls[1].strip()), \n", + " 'damage': int(ls[2].strip()), \n", + " 'armour': int(ls[3].strip()) }]\n", + " return d" + ] + }, + { + "cell_type": "code", + "execution_count": 141, + "metadata": { + "collapsed": false + }, + "outputs": [ + { + "data": { + "text/plain": [ + "([{'armour': 0, 'cost': 8, 'damage': 4, 'name': 'Dagger'},\n", + " {'armour': 0, 'cost': 10, 'damage': 5, 'name': 'Shortsword'},\n", + " {'armour': 0, 'cost': 25, 'damage': 6, 'name': 'Warhammer'},\n", + " {'armour': 0, 'cost': 40, 'damage': 7, 'name': 'Longsword'},\n", + " {'armour': 0, 'cost': 74, 'damage': 8, 'name': 'Greataxe'}],\n", + " [{'armour': 1, 'cost': 13, 'damage': 0, 'name': 'Leather'},\n", + " {'armour': 2, 'cost': 31, 'damage': 0, 'name': 'Chainmail'},\n", + " {'armour': 3, 'cost': 53, 'damage': 0, 'name': 'Splintmail'},\n", + " {'armour': 4, 'cost': 75, 'damage': 0, 'name': 'Bandedmail'},\n", + " {'armour': 5, 'cost': 102, 'damage': 0, 'name': 'Platemail'},\n", + " {}],\n", + " [{'armour': 0, 'cost': 25, 'damage': 1, 'name': 'Damage+1'},\n", + " {'armour': 0, 'cost': 50, 'damage': 2, 'name': 'Damage+2'},\n", + " {'armour': 0, 'cost': 100, 'damage': 3, 'name': 'Damage+3'},\n", + " {'armour': 1, 'cost': 20, 'damage': 0, 'name': 'Defense+1'},\n", + " {'armour': 2, 'cost': 40, 'damage': 0, 'name': 'Defense+2'},\n", + " {'armour': 3, 'cost': 80, 'damage': 0, 'name': 'Defense+3'},\n", + " {},\n", + " {}])" + ] + }, + "execution_count": 141, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "weapons = parse_table(weapons_s)\n", + "armour = parse_table(armour_s)\n", + "armour += [{}]\n", + "rings = parse_table(rings_s)\n", + "rings += [{}, {}]\n", + "weapons, armour, rings" + ] + }, + { + "cell_type": "code", + "execution_count": 142, + "metadata": { + "collapsed": true + }, + "outputs": [], + "source": [ + "def player(equipment):\n", + " player = {'hp': 100, 'damage': 0, 'armour': 0, 'cost': 0, 'name': ''}\n", + " for e in equipment:\n", + " for s in e:\n", + " player[s] += e[s]\n", + " return player" + ] + }, + { + "cell_type": "code", + "execution_count": 143, + "metadata": { + "collapsed": false + }, + "outputs": [ + { + "data": { + "text/plain": [ + "{'armour': 4, 'cost': 217, 'damage': 10, 'hp': 100, 'name': ''}" + ] + }, + "execution_count": 143, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "player([{'armour': 0, 'cost': 74, 'damage': 8}, {'armour': 1, 'cost': 13, 'damage': 0},\n", + " {'armour': 0, 'cost': 50, 'damage': 2}, {'armour': 3, 'cost': 80, 'damage': 0}])" + ] + }, + { + "cell_type": "code", + "execution_count": 144, + "metadata": { + "collapsed": false + }, + "outputs": [ + { + "data": { + "text/plain": [ + "840" + ] + }, + "execution_count": 144, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "equipment = itertools.chain(\n", + " itertools.product(\n", + " itertools.combinations(weapons, 1),\n", + " itertools.combinations(armour, 1),\n", + " itertools.combinations(rings, 2)))\n", + "\n", + "players = [player(j for i in e for j in i) for e in equipment]\n", + "len(players)" + ] + }, + { + "cell_type": "code", + "execution_count": 146, + "metadata": { + "collapsed": false + }, + "outputs": [ + { + "data": { + "text/plain": [ + "91" + ] + }, + "execution_count": 146, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "winner = [p for p in players if not player_wins_fight(p, boss)]\n", + "# sorted(winners, key=lambda w: w['cost'])\n", + "min(winners, key=lambda w: w['cost'])['cost']" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "#Part 2" + ] + }, + { + "cell_type": "code", + "execution_count": 149, + "metadata": { + "collapsed": false + }, + "outputs": [ + { + "data": { + "text/plain": [ + "840" + ] + }, + "execution_count": 149, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "equipment = itertools.chain(\n", + " itertools.product(\n", + " itertools.combinations(weapons, 1),\n", + " itertools.combinations(armour, 1),\n", + " itertools.combinations(rings, 2)))\n", + "\n", + "players = [player(j for i in e for j in i) for e in equipment]\n", + "len(players)" + ] + }, + { + "cell_type": "code", + "execution_count": 151, + "metadata": { + "collapsed": false + }, + "outputs": [ + { + "data": { + "text/plain": [ + "158" + ] + }, + "execution_count": 151, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "losers = [p for p in players if not player_wins_fight(p, boss)]\n", + "# sorted(losers, key=lambda w: w['cost'], reverse=True)\n", + "max(losers, key=lambda w: w['cost'])['cost']" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": true + }, + "outputs": [], + "source": [] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.4.3" + } + }, + "nbformat": 4, + "nbformat_minor": 0 +}