From b4155378bd7d1e4a62ffbf4b47d569d8db35f72f Mon Sep 17 00:00:00 2001 From: tabledevil Date: Fri, 27 Dec 2024 22:39:44 +0100 Subject: [PATCH] Second attempt on 17 --- 17/17.go | 145 +++++++++++++++++++++ 17/17.ipynb | 365 ++++++++++++++++++++++++++++++++++------------------ 2 files changed, 388 insertions(+), 122 deletions(-) create mode 100644 17/17.go diff --git a/17/17.go b/17/17.go new file mode 100644 index 0000000..928645b --- /dev/null +++ b/17/17.go @@ -0,0 +1,145 @@ +package main + +import ( + "fmt" + "runtime" + "sync" + "time" +) + +// QuickCheckRxa validates if a given rxa produces the program as output +func QuickCheckRxa(rxa int, prog []int) bool { + rxb := 0 + rxc := 0 + ip := 0 + output := []int{} + + for ip < len(prog) { + opcode := prog[ip] + operand := prog[ip+1] + switch opcode { + case 0: // adv: rxa / 2^operand + if operand >= 0 && operand <= 3 { + rxa = rxa / (1 << operand) + } else { + return false + } + ip += 2 + case 1: // bxl: rxb XOR operand + rxb ^= operand + ip += 2 + case 2: // bst: operand % 8 + switch operand { + case 4: + operand = rxa + case 5: + operand = rxb + case 6: + operand = rxc + } + rxb = operand % 8 + ip += 2 + case 3: // jnz: jump if rxa != 0 + if rxa != 0 { + ip = operand + } else { + ip += 2 + } + case 4: // bxc: rxb XOR rxc + rxb ^= rxc + ip += 2 + case 5: // out: operand % 8 + switch operand { + case 4: + operand = rxa + case 5: + operand = rxb + case 6: + operand = rxc + } + output = append(output, operand%8) + ip += 2 + default: + return false + } + + // Check if output mismatches the program so far + if len(output) > len(prog) { + return false + } + for i, val := range output { + if val != prog[i] { + return false + } + } + } + + return len(output) == len(prog) +} + +func workerDynamic(taskQueue <-chan int, prog []int, result chan int, done <-chan struct{}, wg *sync.WaitGroup) { + defer wg.Done() + for { + select { + case <-done: + return + case rxa, ok := <-taskQueue: + if !ok { + return + } + if QuickCheckRxa(rxa, prog) { + select { + case result <- rxa: + default: + } + return + } + } + } +} + +func main() { + prog := []int{2, 4, 1, 3, 7, 5, 4, 0, 1, 3, 0, 3, 5, 5, 3, 0} + start := time.Now() + taskQueue := make(chan int, 1000) // Buffered queue for tasks + result := make(chan int, 1) + done := make(chan struct{}) + var wg sync.WaitGroup + numWorkers := runtime.NumCPU() + + // Status updater + go func() { + for { + time.Sleep(1 * time.Second) + fmt.Printf("Queue size: %d\n", len(taskQueue)) + } + }() + + // Launch workers + for i := 0; i < numWorkers; i++ { + wg.Add(1) + go workerDynamic(taskQueue, prog, result, done, &wg) + } + + // Generate tasks dynamically + go func() { + for rxa := 0; ; rxa++ { + select { + case <-done: + close(taskQueue) + return + default: + taskQueue <- rxa + } + } + }() + + // Wait for result + foundRxa := <-result + close(done) // Signal workers to stop + wg.Wait() // Ensure all workers exit cleanly + duration := time.Since(start) + + fmt.Printf("Found rxa: %d\n", foundRxa) + fmt.Printf("Execution time: %s\n", duration) +} diff --git a/17/17.ipynb b/17/17.ipynb index 721666f..14245aa 100644 --- a/17/17.ipynb +++ b/17/17.ipynb @@ -2,101 +2,124 @@ "cells": [ { "cell_type": "code", - "execution_count": 220, + "execution_count": 1, "metadata": {}, "outputs": [], "source": [ - "def decombo(operand):\n", - " match operand:\n", - " case x if x >=0 and x<=3:\n", - " return operand\n", - " case 4:\n", - " return rxa\n", - " case 5:\n", - " return rxb\n", - " case 6:\n", - " return rxc\n", - " case _:\n", - " raise ValueError\n", + "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 operation(opcode,operand, debug=False):\n", - " global rxa,rxb,rxc,ip,output\n", - " match(opcode):\n", - " case 0:\n", - " operand = decombo(operand)\n", - " result = int(rxa/(2**operand))\n", - " if debug: print(f\"adv: {rxa} / 2^{operand} = {result}\")\n", - " rxa = result\n", - " ip += 2\n", - " case 1:\n", - " result = rxb ^ operand\n", - " if debug: print(f\"bxl: {rxb} XOR {operand} = {result}\")\n", - " rxb = result\n", - " ip += 2\n", - " case 2:\n", - " operand = decombo(operand)\n", - " result = operand % 8\n", - " if debug: print(f\"bst: {operand} % 8 = {result}\")\n", - " rxb = result\n", - " ip += 2\n", - " case 3:\n", - " result = rxa!=0\n", - " if debug: print(f\"jnz: {rxa} != 0 is {result}\")\n", - " ip = operand if result else ip+2\n", - " case 4:\n", - " result = rxb ^ rxc\n", - " if debug: print(f\"bxc: {rxb} XOR {rxc} = {result}\")\n", - " rxb=result \n", - " ip += 2\n", - " case 5:\n", - " operand = decombo(operand)\n", - " result = operand % 8\n", - " if debug: print(f\"out: {operand} % 8 = {operand % 8}\")\n", - " output.append(f\"{result}\")\n", - " ip += 2\n", - " case 6:\n", - " operand = decombo(operand)\n", - " result = int(rxa/(2**operand))\n", - " if debug: print(f\"bdv: {rxa} / 2^{operand} = {result}\")\n", - " rxb = result\n", - " ip += 2\n", - " case 7:\n", - " operand = decombo(operand)\n", - " result = int(rxa/(2**operand))\n", - " if debug: print(f\"cdv: {rxa} / 2^{operand} = {result}\")\n", - " rxc = result\n", - " ip += 2\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(index=None):\n", - " if index is None:\n", - " index = ip\n", - " if index < 0 or (index+1) > len(prog):\n", - " return None\n", - " return prog[index],prog[index+1]\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 state():\n", - " print(f\"rxa: {rxa}\")\n", - " print(f\"rxb: {rxb}\")\n", - " print(f\"rxc: {rxc}\")\n", - " print(f\"output: {','.join(output)}\")\n", - " print(f\"instruction pointer : {[ip]}\")\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": 221, + "execution_count": 2, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ - "rxa: 729\n", - "rxb: 0\n", - "rxc: 0\n", - "output: \n", - "instruction pointer : [0]\n" + "{'rxa': 729, 'rxb': 0, 'rxc': 0, 'instruction_pointer': 0}\n" ] } ], @@ -106,63 +129,159 @@ "rxc = 0\n", "ip = 0\n", "prog = [0,1,5,4,3,0]\n", - "output = []\n", - "state()" + "testcpu = ElfberryPiCPU(rxa,rxb,rxc,prog)\n", + "print(testcpu)" ] }, { "cell_type": "code", - "execution_count": 222, + "execution_count": 3, "metadata": {}, "outputs": [ { - "name": "stdout", - "output_type": "stream", - "text": [ - "rxa: 0\n", - "rxb: 0\n", - "rxc: 0\n", - "output: 4,6,3,5,6,3,5,2,1,0\n", - "instruction pointer : [6]\n" - ] + "data": { + "text/plain": [ + "'4,6,3,5,6,3,5,2,1,0'" + ] + }, + "execution_count": 3, + "metadata": {}, + "output_type": "execute_result" } ], "source": [ - "while instruction:=get_instruction():\n", - " operation(*instruction)\n", - "state()\n" + "\",\".join([str(x) for x in testcpu.outiterator()])" ] }, { "cell_type": "code", - "execution_count": 223, + "execution_count": 5, "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "rxa: 51342988\n", - "rxb: 0\n", - "rxc: 0\n", - "output: \n", - "instruction pointer : [0]\n" - ] - } - ], + "outputs": [], "source": [ - "rxa = 51342988\n", - "rxb = 0\n", - "rxc = 0\n", - "ip = 0\n", - "prog = [2,4,1,3,7,5,4,0,1,3,0,3,5,5,3,0]\n", - "output = []\n", - "state()" + "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": 224, + "execution_count": 264, "metadata": {}, "outputs": [ { @@ -185,17 +304,19 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 13, "metadata": {}, "outputs": [], "source": [ - "for x in range(51342988):\n", - " rxa = x\n", - " rxb = 0\n", - " rxc = 0\n", - " ip = 0\n", + "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", - " output = []\n", + " mycomp = ElfberryPiCPU(x,0,0,prog)\n", + " if mycomp.test_program_output():\n", + " print(f\"Solution : {x}\")\n", + " break\n", + "\n", " " ] }