import ../input_type import ../turtle_type import ../map_type import bitops import random const opcodeLength = 3 # 3 if there are 8 different instructions # anybit proc genAnybitTurtle*(input: Input, bits: int): Turtle = # generates a turtle of bits long memory cells let maxAddress = (1 shl (bits - opcodeLength)) - 1 let maxValue = (1 shl bits) - 1 new(result) for i in 0..maxAddress: result.memory.add(rand(0..maxValue).uint32) proc executeAnybit*(instructionIndex: uint32, turtle: Turtle, map: Map, input: Input, bits: int): int = let maxAddress = ((1 shl (bits - opcodeLength)) - 1).uint32 let maxValue = ((1 shl bits) - 1).uint32 var newInstructionIndex: uint32 let icIncrement = 0'u64 icDecrement = (0b001 shl (bits-opcodeLength)).uint32 icJump = (0b010 shl (bits-opcodeLength)).uint32 icMove = (0b011 shl (bits-opcodeLength)).uint32 icDoubleMove = (0b100 shl (bits-opcodeLength)).uint32 icCond = (0b101 shl (bits-opcodeLength)).uint32 icNand = (0b110 shl (bits-opcodeLength)).uint32 icXor = (0b111 shl (bits-opcodeLength)).uint32 let instruction = turtle.memory[instructionIndex] let instructionCode = instruction.bitand(icXor) let instructionArg = instruction.bitand(bitnot(icXor)) template addTo(target: var uint32, delta: uint32, subtract: bool = false) = if subtract: target = (target - delta).bitand(maxValue) else: target = (target + delta).bitand(maxValue) template nextBlock: uint32 = turtle.memory[(instructionIndex + 1'u32).bitand(maxAddress)] template mapBounded(i: int): int = max(min(i, input.size), 0) if instructionCode == icIncrement: turtle.memory[instructionArg].addTo(1) newInstructionIndex = instructionIndex + 1'u32 elif instructionCode == icDecrement: turtle.memory[instructionArg].addTo(1, subtract = true) newInstructionIndex = instructionIndex + 1'u32 elif instructionCode == icJump: newInstructionIndex = instructionArg elif instructionCode == icMove: let direction = instructionArg.bitand(3'u32) if direction == 0'u32: turtle.y += 1 elif direction == 1'u32: turtle.y -= 1 elif direction == 2'u32: turtle.x += 1 elif direction == 3'u32: turtle.x -= 1 if turtle.x < 0 or turtle.y < 0 or turtle.x >= input.size or turtle.y >= input.size: return -1 newInstructionIndex = instructionIndex + 1 elif instructionCode == icDoubleMove: let amount = (instructionArg.bitand(28'u32) shr 2).int() + 1 let direction = instructionArg.bitand(3'u32) if direction == 0'u32: turtle.y += amount elif direction == 1'u32: turtle.y -= amount elif direction == 2'u32: turtle.x += amount elif direction == 3'u32: turtle.x -= amount if turtle.x < 0 or turtle.y < 0 or turtle.x >= input.size or turtle.y >= input.size: return -1 newInstructionIndex = instructionIndex + 1 elif instructionCode == icCond: # jumps to address if the next block is even if nextBlock().bitand(1'u32) == 0'u32: newInstructionIndex = instructionArg else: newInstructionIndex = instructionIndex + 2 elif instructionCode == icNand: # bitwise nand of the address with the next code block turtle.memory[instructionArg] = bitnot(turtle.memory[instructionArg].bitand(nextBlock())).bitand(maxValue) newInstructionIndex = instructionIndex + 2 elif instructionCode == icXor: turtle.memory[instructionArg] = turtle.memory[instructionArg].bitxor(nextBlock()).bitand(maxValue) newInstructionIndex = instructionIndex + 2 else: raise newException(Defect, "Bad instruction code.") return newInstructionIndex.bitand(maxAddress).int()