From deb9cd82db7f5b6a44f613feb0959110ce70c2e6 Mon Sep 17 00:00:00 2001 From: Tomasz Kramkowski Date: Fri, 26 Nov 2021 23:51:59 +0000 Subject: solutions --- 22/solution.py | 42 +++++++++++++++++++++++++++++++++++++++++- 23/solution.py | 49 +++++++++++++++++++++++++++++++++++++++++++++++++ 24/solution.py | 43 +++++++++++++++++++++++++++++++++++++++++++ 7/solution.py | 30 +++++++++++++++++++++--------- 4 files changed, 154 insertions(+), 10 deletions(-) create mode 100644 23/solution.py create mode 100644 24/solution.py diff --git a/22/solution.py b/22/solution.py index 2859416..6df8379 100644 --- a/22/solution.py +++ b/22/solution.py @@ -1,2 +1,42 @@ +from functools import cache +from collections import namedtuple + +Opponent = namedtuple('Opponent', ['hp', 'damage']) + +def part1(opponent: Opponent) -> int: + @cache + def min_cost(php: int, pmana: int, ohp: int, sld_timer: int, psn_timer: int, rch_timer: int) -> int | float: + psld = 0 + def effects(): + nonlocal ohp, pmana, psld, psn_timer, rch_timer, sld_timer + if sld_timer > 0: + sld_timer -= 1 + psld = 7 + else: + psld = 0 + if psn_timer > 0: + psn_timer -= 1 + ohp -= 3 + if rch_timer > 0: + rch_timer -= 1 + pmana += 101 + + def opponent_turn(cost: int) -> int | float: + effects() + nonlocal php + if ohp <= 0: + return cost + php -= min(1, opponent.attack - psld) + if php <= 0: + return float('inf') + return cost + min_cost(php, pmana, ohp, sld_timer, psn_timer, rch_timer) + + effects() + if ohp <= 0: + return 0 + if __name__ == '__main__': - with open('input') as f: \ No newline at end of file + opponent = Opponent(51, 9) + + print(part1(opponent)) + #print(part2(opponent)) diff --git a/23/solution.py b/23/solution.py new file mode 100644 index 0000000..00144bf --- /dev/null +++ b/23/solution.py @@ -0,0 +1,49 @@ +def run(instructions, a=0, b=0): + ip = 0 + regs = { + 'a': a, + 'b': b, + } + + def set(r, v): + regs[r] = v + return 1 + + act = { + 'hlf': lambda r: set(r, regs[r] // 2), + 'tpl': lambda r: set(r, regs[r] * 3), + 'inc': lambda r: set(r, regs[r] + 1), + 'jmp': lambda offset: offset, + 'jie': lambda r, offset: offset if regs[r] % 2 == 0 else 1, + 'jio': lambda r, offset: offset if regs[r] == 1 else 1, + } + + while 0 <= ip < len(instructions): + ins, ops = instructions[ip] + ip += act[ins](*ops) + # print(f'ins={ins}, ops={ops}, a={regs["a"]}, b={regs["b"]}, ip={ip}') + + return regs + +def part1(instructions): + return run(instructions)['b'] + +def part2(instructons): + return run(instructions, 1)['b'] + +if __name__ == '__main__': + with open('input') as f: + instructions = list() + for line in f: + line = line.rstrip() + opcode, operands = line.split(' ', maxsplit=1) + def parse_operand(s: str) -> int | str: + if s[0] == '+': + return int(s[1:]) + elif s[0] == '-': + return -int(s[1:]) + return s + operands = tuple(parse_operand(op) for op in operands.split(', ')) + instructions.append((opcode, operands)) + print(part1(instructions)) + print(part2(instructions)) diff --git a/24/solution.py b/24/solution.py new file mode 100644 index 0000000..6aa9ebe --- /dev/null +++ b/24/solution.py @@ -0,0 +1,43 @@ +from functools import reduce + +def cansum(packages, target): + if target == 0: + return True + if len(packages) == 0: + return False + p = next(iter(packages)) + rest = packages - {p} + if p <= target: + return cansum(rest, target - p) or cansum(rest, target) + else: + return cansum(rest, target) + +def minimize(packages, pile, target, orig_target=None): + if orig_target is None: + orig_target = target + if target == 0 and cansum(packages, orig_target): + return len(pile), reduce(lambda a, b: a * b, pile, 1) + if len(packages) == 0: + return float('inf'), float('inf') + p = next(iter(packages)) + rest = packages - {p} + if p <= target: + return min( + minimize(rest, pile | {p}, target - p, orig_target), + minimize(rest, pile, target, orig_target) + ) + else: + return minimize(rest, pile, target) + +def part1(packages): + return minimize(frozenset(packages), frozenset(), sum(packages) // 3) + +def part2(packages): + return minimize(frozenset(packages), frozenset(), sum(packages) // 4) + +if __name__ == '__main__': + with open('input') as f: + packages = list(int(l.rstrip()) for l in f) + packages.reverse() + print(part1(packages)) + print(part2(packages)) diff --git a/7/solution.py b/7/solution.py index 77a1391..6eee284 100644 --- a/7/solution.py +++ b/7/solution.py @@ -15,34 +15,44 @@ class U16: return U16(self.value << other.value) def __str__(self): return str(self.value) + def __repr__(self): + return f'{self.value}' class Node: - _value: U16 = None + _value: U16 | None = None @property def value(self) -> U16: - if not self._value: + if self._value is None: self._value = self.eval() return self._value - def eval(self, net: dict[Node]) -> U16: - return self.eval() - @absrtactmethod + @abstractmethod def eval(self) -> U16: pass + @abstractmethod + def __repr__(self) -> str: + pass class Reference(Node): - def __init__(self, name: str): + def __init__(self, net: dict[Node], name: str): + self.net = net self.name = name - def eval(self, net: dict[Node]) -> U16: - return net[self.name].value + def eval(self) -> U16: + return self.net[self.name].value + def __repr__(self) -> str: + return f'Reference({self.name})' class Constant(Node): def __init__(self, value): self._value = value + def __repr__(self) -> str: + return f'Constant({self.value})' class BinaryOp(Node): def __init__(self, left, right): self.left = left self.right = right + def __repr__(self) -> str: + return f'{self.__class__.__name__}({self.left}, {self.right})' class And(BinaryOp): def eval(self) -> U16: @@ -65,6 +75,8 @@ class Not(Node): self.node = node def eval(self): return ~self.node.value + def __repr__(self) -> str: + return 'Not({self.node})' def parse_expr(net: dict[Node], expr: str) -> Node: parts = expr.split(' ') @@ -112,4 +124,4 @@ if __name__ == '__main__': with open('input') as f: inp = [line.strip() for line in f] print(part1(inp)) - print(part2(inp)) \ No newline at end of file + print(part2(inp)) -- cgit v1.2.3-54-g00ecf