{ "cells": [ { "cell_type": "code", "execution_count": 1, "metadata": {}, "outputs": [], "source": [ "class ElfberryPiCPU:\n", " def __init__(self, rxa, rxb, rxc, prog):\n", " self.rxa = rxa\n", " self.rxb = rxb\n", " self.rxc = rxc\n", " self.ip = 0\n", " self.prog = prog\n", " self.output = None\n", "\n", " def decombo(self, operand):\n", " match operand:\n", " case x if 0 <= x <= 3:\n", " return operand\n", " case 4:\n", " return self.rxa\n", " case 5:\n", " return self.rxb\n", " case 6:\n", " return self.rxc\n", " case _:\n", " raise ValueError(\"Invalid operand\")\n", "\n", " def operation(self, opcode, operand, debug=False):\n", " match opcode:\n", " case 0:\n", " operand = self.decombo(operand)\n", " result = int(self.rxa / (2 ** operand))\n", " if debug:\n", " print(f\"adv: {self.rxa} / 2^{operand} = {result}\")\n", " self.rxa = result\n", " self.ip += 2\n", " case 1:\n", " result = self.rxb ^ operand\n", " if debug:\n", " print(f\"bxl: {self.rxb} XOR {operand} = {result}\")\n", " self.rxb = result\n", " self.ip += 2\n", " case 2:\n", " operand = self.decombo(operand)\n", " result = operand % 8\n", " if debug:\n", " print(f\"bst: {operand} % 8 = {result}\")\n", " self.rxb = result\n", " self.ip += 2\n", " case 3:\n", " result = self.rxa != 0\n", " if debug:\n", " print(f\"jnz: {self.rxa} != 0 is {result}\")\n", " self.ip = operand if result else self.ip + 2\n", " case 4:\n", " result = self.rxb ^ self.rxc\n", " if debug:\n", " print(f\"bxc: {self.rxb} XOR {self.rxc} = {result}\")\n", " self.rxb = result\n", " self.ip += 2\n", " case 5:\n", " operand = self.decombo(operand)\n", " result = operand % 8\n", " if debug:\n", " print(f\"out: {operand} % 8 = {result}\")\n", " self.output = result\n", " self.ip += 2\n", " case 6:\n", " operand = self.decombo(operand)\n", " result = int(self.rxa / (2 ** operand))\n", " if debug:\n", " print(f\"bdv: {self.rxa} / 2^{operand} = {result}\")\n", " self.rxb = result\n", " self.ip += 2\n", " case 7:\n", " operand = self.decombo(operand)\n", " result = int(self.rxa / (2 ** operand))\n", " if debug:\n", " print(f\"cdv: {self.rxa} / 2^{operand} = {result}\")\n", " self.rxc = result\n", " self.ip += 2\n", "\n", " def get_instruction(self, index=None):\n", " if index is None:\n", " index = self.ip\n", " if index < 0 or (index + 1) > len(self.prog):\n", " return None\n", " return self.prog[index], self.prog[index + 1]\n", "\n", " def __str__(self):\n", " return f\"{self.state()}\"\n", "\n", " def state(self):\n", " return {\n", " \"rxa\": self.rxa,\n", " \"rxb\": self.rxb,\n", " \"rxc\": self.rxc,\n", " \"instruction_pointer\": self.ip\n", " }\n", "\n", " def outiterator(self, debug=False):\n", " while instruction := self.get_instruction():\n", " opcode, operand = instruction\n", " self.operation(opcode, operand, debug)\n", " if self.output is not None:\n", " yield self.output\n", " self.output=None\n" ] }, { "cell_type": "code", "execution_count": 2, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "{'rxa': 729, 'rxb': 0, 'rxc': 0, 'instruction_pointer': 0}\n" ] } ], "source": [ "rxa = 729\n", "rxb = 0\n", "rxc = 0\n", "ip = 0\n", "prog = [0,1,5,4,3,0]\n", "testcpu = ElfberryPiCPU(rxa,rxb,rxc,prog)\n", "print(testcpu)" ] }, { "cell_type": "code", "execution_count": 3, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "'4,6,3,5,6,3,5,2,1,0'" ] }, "execution_count": 3, "metadata": {}, "output_type": "execute_result" } ], "source": [ "\",\".join([str(x) for x in testcpu.outiterator()])" ] }, { "cell_type": "code", "execution_count": 5, "metadata": {}, "outputs": [], "source": [ "class ElfberryPiCPU:\n", " def __init__(self, rxa, rxb, rxc, prog):\n", " self.rxa = rxa\n", " self.rxb = rxb\n", " self.rxc = rxc\n", " self.ip = 0\n", " self.prog = prog\n", " self.output = None\n", "\n", " def decombo(self, operand):\n", " match operand:\n", " case x if 0 <= x <= 3:\n", " return operand\n", " case 4:\n", " return self.rxa\n", " case 5:\n", " return self.rxb\n", " case 6:\n", " return self.rxc\n", " case _:\n", " raise ValueError(\"Invalid operand\")\n", "\n", " def operation(self, opcode, operand, debug=False):\n", " match opcode:\n", " case 0:\n", " operand = self.decombo(operand)\n", " result = int(self.rxa / (2 ** operand))\n", " if debug:\n", " print(f\"adv: {self.rxa} / 2^{operand} = {result}\")\n", " self.rxa = result\n", " self.ip += 2\n", " case 1:\n", " result = self.rxb ^ operand\n", " if debug:\n", " print(f\"bxl: {self.rxb} XOR {operand} = {result}\")\n", " self.rxb = result\n", " self.ip += 2\n", " case 2:\n", " operand = self.decombo(operand)\n", " result = operand % 8\n", " if debug:\n", " print(f\"bst: {operand} % 8 = {result}\")\n", " self.rxb = result\n", " self.ip += 2\n", " case 3:\n", " result = self.rxa != 0\n", " if debug:\n", " print(f\"jnz: {self.rxa} != 0 is {result}\")\n", " self.ip = operand if result else self.ip + 2\n", " case 4:\n", " result = self.rxb ^ self.rxc\n", " if debug:\n", " print(f\"bxc: {self.rxb} XOR {self.rxc} = {result}\")\n", " self.rxb = result\n", " self.ip += 2\n", " case 5:\n", " operand = self.decombo(operand)\n", " result = operand % 8\n", " if debug:\n", " print(f\"out: {operand} % 8 = {result}\")\n", " self.output = result\n", " self.ip += 2\n", " case 6:\n", " operand = self.decombo(operand)\n", " result = int(self.rxa / (2 ** operand))\n", " if debug:\n", " print(f\"bdv: {self.rxa} / 2^{operand} = {result}\")\n", " self.rxb = result\n", " self.ip += 2\n", " case 7:\n", " operand = self.decombo(operand)\n", " result = int(self.rxa / (2 ** operand))\n", " if debug:\n", " print(f\"cdv: {self.rxa} / 2^{operand} = {result}\")\n", " self.rxc = result\n", " self.ip += 2\n", "\n", " def get_instruction(self, index=None):\n", " if index is None:\n", " index = self.ip\n", " if index < 0 or (index + 1) > len(self.prog):\n", " return None\n", " return self.prog[index], self.prog[index + 1]\n", "\n", " def __str__(self):\n", " return f\"{self.state()}\"\n", "\n", " def state(self):\n", " return {\n", " \"rxa\": self.rxa,\n", " \"rxb\": self.rxb,\n", " \"rxc\": self.rxc,\n", " \"instruction_pointer\": self.ip\n", " }\n", "\n", " def outiterator(self, debug=False):\n", " while instruction := self.get_instruction():\n", " opcode, operand = instruction\n", " self.operation(opcode, operand, debug)\n", " if self.output is not None:\n", " yield self.output\n", " self.output = None\n", "\n", " def test_program_output(self):\n", " generator = self.outiterator()\n", " for expected in self.prog:\n", " try:\n", " output = next(generator)\n", " if output != expected:\n", " return False # Mismatch found, terminate early\n", " except StopIteration:\n", " return False # Generator exhausted prematurely\n", "\n", " try:\n", " next(generator) # Check if generator produces extra output\n", " return False\n", " except StopIteration:\n", " return True # Generator matches program exactly\n" ] }, { "cell_type": "code", "execution_count": 264, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "rxa: 0\n", "rxb: 0\n", "rxc: 3\n", "output: 1,5,7,4,1,6,0,3,0\n", "instruction pointer : [16]\n" ] } ], "source": [ "while instruction:=get_instruction():\n", " operation(*instruction)\n", "state()" ] }, { "cell_type": "code", "execution_count": 13, "metadata": {}, "outputs": [], "source": [ "x = 118000000\n", "while True:\n", " x+=1\n", " prog = [2,4,1,3,7,5,4,0,1,3,0,3,5,5,3,0]\n", " mycomp = ElfberryPiCPU(x,0,0,prog)\n", " if mycomp.test_program_output():\n", " print(f\"Solution : {x}\")\n", " break\n", "\n", " " ] } ], "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.11.11" } }, "nbformat": 4, "nbformat_minor": 2 }