106 lines
3.7 KiB
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()
|