treasure/instruction_sets/any_bit.nim

106 lines
3.7 KiB
Nim

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()