initial commit
This commit is contained in:
parent
f4755be327
commit
b8ecf7c744
|
@ -0,0 +1,217 @@
|
|||
import input_type
|
||||
import map_type
|
||||
import turtle
|
||||
import turtle_type
|
||||
|
||||
import math
|
||||
import sequtils
|
||||
import strutils
|
||||
import strformat
|
||||
import terminal
|
||||
import algorithm
|
||||
|
||||
const blueCutoff = 0.05
|
||||
const cyanCutoff = 0.1
|
||||
const greenCutoff = 0.205
|
||||
const yellowCutoff = 0.335
|
||||
const redCutoff = 0.505
|
||||
const magentaCutoff = 1.0
|
||||
|
||||
proc setHotnessBackground(hotness: float, maxHotness: float) =
|
||||
if hotness == 0:
|
||||
stdout.setBackgroundColor(bgDefault)
|
||||
else:
|
||||
let hotnessFrac = hotness / maxHotness
|
||||
if hotnessFrac < blueCutoff:
|
||||
stdout.setBackgroundColor(bgBlue)
|
||||
elif hotnessFrac < cyanCutoff:
|
||||
stdout.setBackgroundColor(bgCyan)
|
||||
elif hotnessFrac < greenCutoff:
|
||||
stdout.setBackgroundColor(bgGreen)
|
||||
elif hotnessFrac < yellowCutoff:
|
||||
stdout.setBackgroundColor(bgYellow)
|
||||
elif hotnessFrac < redCutoff:
|
||||
stdout.setBackgroundColor(bgRed)
|
||||
else:
|
||||
stdout.setBackgroundColor(bgMagenta)
|
||||
|
||||
proc printHotmapLegend(maxHotness: float, x,y: int) =
|
||||
template line(num: int) =
|
||||
setCursorPos(x, y + num - 1)
|
||||
template showColor(col: BackgroundColor) =
|
||||
stdout.setBackgroundColor(col)
|
||||
stdout.write(" ")
|
||||
stdout.setBackgroundColor(bgBlack)
|
||||
stdout.write(" ")
|
||||
|
||||
proc writeNumber(num: float) =
|
||||
stdout.write(fmt"{num.int()}")
|
||||
|
||||
line(1)
|
||||
showColor(bgDefault)
|
||||
writeNumber(0.0)
|
||||
|
||||
line(2)
|
||||
showColor(bgBlue)
|
||||
writeNumber(blueCutoff * maxHotness)
|
||||
|
||||
line(3)
|
||||
showColor(bgCyan)
|
||||
writeNumber(cyanCutoff * maxHotness)
|
||||
|
||||
line(4)
|
||||
showColor(bgGreen)
|
||||
writeNumber(greenCutoff * maxHotness)
|
||||
|
||||
line(5)
|
||||
showColor(bgYellow)
|
||||
writeNumber(yellowCutoff * maxHotness)
|
||||
|
||||
line(6)
|
||||
showColor(bgRed)
|
||||
writeNumber(redCutoff * maxHotness)
|
||||
|
||||
line(7)
|
||||
showColor(bgMagenta)
|
||||
writeNumber(magentaCutoff * maxHotness)
|
||||
|
||||
|
||||
|
||||
proc displayGeneration*(generationNumber: int, timeSeconds: float, seed: int, input: Input, map: Map, turtles: var seq[Turtle]) =
|
||||
|
||||
# SCREEN INIT
|
||||
stdout.setBackgroundColor(bgBlack)
|
||||
stdout.setForegroundColor(fgWhite)
|
||||
eraseScreen()
|
||||
setCursorPos(0, 0)
|
||||
|
||||
# STATISTICS
|
||||
let scoreCount = turtles.len()
|
||||
var scoreSum = 0
|
||||
var stepsSum = 0
|
||||
for turtle in turtles:
|
||||
scoreSum += turtle.score
|
||||
stepsSum += turtle.steps
|
||||
|
||||
let scoreAvg = scoreSum.float() / scoreCount.float()
|
||||
let stepsAvg = stepsSum.float() / scoreCount.float()
|
||||
|
||||
let variance = turtles.mapIt((it.score.float() - scoreAvg)^2).sum() / scoreCount.float()
|
||||
let stddev = variance.sqrt()
|
||||
|
||||
# PRINT BASIC INFO
|
||||
echo &"Generation number: {generationNumber}"
|
||||
echo &"Computation time since last stop: {timeSeconds} s"
|
||||
echo &"Seed: {seed}"
|
||||
echo &"Population: {turtles.len()} turtles"
|
||||
echo &"Mean score: {scoreAvg} (in {stepsAvg} steps)"
|
||||
echo &"Standard deviation: {stddev}"
|
||||
echo &"Top score: {turtles[0].score} (in {turtles[0].steps} steps)"
|
||||
|
||||
# PERCENTILS
|
||||
turtles.sort(compareTurtles)
|
||||
var percentils: seq[int] = @[]
|
||||
for i in 1..9:
|
||||
let index = (input.population div 10) * i
|
||||
percentils.add(turtles[index].score)
|
||||
let percentilsString = percentils.join(", ")
|
||||
echo &"Score of every 10%th percentil: {percentilsString}"
|
||||
|
||||
# CHOOSE NOTABLE
|
||||
var top10Paths: seq[Turtle] = @[]
|
||||
var notables: seq[int] = @[]
|
||||
var i = 0
|
||||
while true:
|
||||
if i > turtles.high():
|
||||
break
|
||||
|
||||
if top10Paths.len() == 0 or top10Paths[top10Paths.high()].score != turtles[i].score:
|
||||
top10Paths.add(turtles[i])
|
||||
notables.add(i)
|
||||
|
||||
if top10Paths.len() >= 10:
|
||||
break
|
||||
|
||||
inc i
|
||||
|
||||
let notableString = notables.join(", ")
|
||||
echo &"Notable turtles: {notableString}"
|
||||
|
||||
# HOTNESS MAP
|
||||
var hotness: seq[seq[int]] = @[]
|
||||
var top10Hot: seq[seq[int]] = @[]
|
||||
var topHot: seq[seq[int]] = @[]
|
||||
for i in 0..input.size-1:
|
||||
hotness.add(@[])
|
||||
top10Hot.add(@[])
|
||||
topHot.add(@[])
|
||||
for j in 0..input.size-1:
|
||||
hotness[i].add(0)
|
||||
top10Hot[i].add(0)
|
||||
topHot[i].add(0)
|
||||
|
||||
template populateHotness(turtles: seq[Turtle], hotSeq: var seq[seq[int]], maxHot: var int) =
|
||||
for turtle in turtles:
|
||||
let path = turtle.path
|
||||
for i in 0..path.xs.high():
|
||||
let x = path.xs[i]
|
||||
let y = path.ys[i]
|
||||
hotSeq[y][x].inc()
|
||||
if hotSeq[y][x] > maxHot:
|
||||
maxHot = hotSeq[y][x]
|
||||
|
||||
var maxHotness = 0
|
||||
populateHotness(turtles, hotness, maxHotness)
|
||||
var maxTop10Hotness = 0
|
||||
populateHotness(top10Paths, top10Hot, maxTop10Hotness)
|
||||
var maxTopHotness = 0
|
||||
populateHotness(@[turtles[0]], topHot, maxTopHotness)
|
||||
|
||||
# DISPLAY HOTNESS MAP
|
||||
echo "Hotmap of All/Notable/Best Turtles"
|
||||
|
||||
const yOffset = 10
|
||||
let xOffset = input.size + 2
|
||||
|
||||
for y in 0..input.size-1:
|
||||
for x in 0..input.size-1:
|
||||
let hotness = hotness[y][x]
|
||||
let top10hotness = top10Hot[y][x]
|
||||
let topHotness = topHot[y][x]
|
||||
let symbol = map[y][x].tileToString()
|
||||
|
||||
# hotmap
|
||||
setHotnessBackground(hotness.float(), maxHotness.float())
|
||||
setCursorPos(x, y+yOffset)
|
||||
stdout.write(symbol)
|
||||
|
||||
# top10 map
|
||||
setHotnessBackground(top10hotness.float(), maxTop10Hotness.float())
|
||||
setCursorPos(x+xOffset, y+yOffset)
|
||||
stdout.write(symbol)
|
||||
|
||||
# top map
|
||||
setHotnessBackground(topHotness.float(), maxTopHotness.float())
|
||||
setCursorPos(x+2*xOffset, y+yOffset)
|
||||
stdout.write(symbol)
|
||||
|
||||
|
||||
stdout.setBackgroundColor(bgBlack)
|
||||
stdout.write("\n")
|
||||
|
||||
echo ""
|
||||
|
||||
# display legend
|
||||
let legendYOffset = yOffset + 1 + input.size
|
||||
printHotmapLegend(maxHotness.float(), 0, legendYOffset)
|
||||
printHotmapLegend(maxTop10Hotness.float(), xOffset, legendYOffset)
|
||||
printHotmapLegend(maxTopHotness.float(), 2*xOffset, legendYOffset)
|
||||
echo ""
|
||||
echo ""
|
||||
# FINISH
|
||||
echo "Press enter to continue."
|
||||
discard stdin.readLine()
|
||||
stdout.setBackgroundColor(bgDefault)
|
||||
eraseScreen()
|
||||
setCursorPos(1,1)
|
||||
echo ""
|
|
@ -0,0 +1,8 @@
|
|||
{
|
||||
"size": 19,
|
||||
"treasure_count": 7,
|
||||
"lifetime": 500,
|
||||
"population": 500,
|
||||
"instruction_set": "anybit",
|
||||
"bits": 12
|
||||
}
|
|
@ -0,0 +1,11 @@
|
|||
|
||||
type
|
||||
Input* = object
|
||||
size*: int
|
||||
treasure_count*: int
|
||||
lifetime*: int
|
||||
population*: int
|
||||
instruction_set*: string
|
||||
bits*: int
|
||||
|
||||
|
|
@ -0,0 +1,105 @@
|
|||
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()
|
|
@ -0,0 +1,67 @@
|
|||
import strutils
|
||||
import json
|
||||
import random
|
||||
import times
|
||||
import os
|
||||
|
||||
import input_type
|
||||
import map_type
|
||||
import turtle
|
||||
import turtle_type
|
||||
import score
|
||||
import select
|
||||
import mutate
|
||||
import display
|
||||
|
||||
let now = getTime()
|
||||
var seed = now.toUnix * 1_000_000_000 + now.nanosecond
|
||||
if paramCount() > 0:
|
||||
seed = parseInt(paramStr(1))
|
||||
|
||||
randomize(seed)
|
||||
|
||||
# first, get the inputs
|
||||
let input = readFile("input.json").parseJson().to(Input)
|
||||
|
||||
if input.bits < 4 or input.bits > 32:
|
||||
raise newException(Defect, "bits in input json must be between 4 and 32 (inclusive).")
|
||||
|
||||
# get a map
|
||||
let map = input.generateMap()
|
||||
|
||||
# get population turtles
|
||||
var turtles: seq[Turtle]
|
||||
for i in 0..input.population-1:
|
||||
turtles.add(input.genTurtle())
|
||||
|
||||
var lastTime = cpuTime()
|
||||
|
||||
proc generation(generationNumber: int) =
|
||||
# does a whole generation
|
||||
|
||||
# gets the path of the turtles
|
||||
for turtle in turtles:
|
||||
turtle.execute(map, input)
|
||||
score(turtle, map, input)
|
||||
|
||||
# display generation
|
||||
|
||||
if generationNumber mod 500 == 0:
|
||||
let newTime = cpuTime()
|
||||
let timeSeconds = newTime - lastTime
|
||||
lastTime = newTime
|
||||
displayGeneration(generationNumber, timeSeconds, seed.int(), input, map, turtles)
|
||||
|
||||
turtles.select(input)
|
||||
|
||||
# add mutated turtles from previous generation
|
||||
let prevGenCount = turtles.high()
|
||||
while turtles.len() < input.population:
|
||||
let basis = turtles[rand(prevGenCount)]
|
||||
turtles.add(mutate(basis, input))
|
||||
|
||||
|
||||
var i = 0
|
||||
while true:
|
||||
generation(i)
|
||||
inc i
|
|
@ -0,0 +1,54 @@
|
|||
import strutils
|
||||
import sequtils
|
||||
import random
|
||||
|
||||
import input_type
|
||||
|
||||
type
|
||||
Tile* = enum
|
||||
tileEmpty, tileTreasure
|
||||
Map* = seq[seq[Tile]]
|
||||
|
||||
proc generateMap*(input: Input): Map =
|
||||
let treasureCount = input.treasure_count
|
||||
|
||||
# create empty map
|
||||
for i in 0..input.size:
|
||||
result.add(@[])
|
||||
for j in 0..input.size:
|
||||
result[i].add(tileEmpty)
|
||||
|
||||
# populate treasures
|
||||
var addedTreasures = 0
|
||||
while addedTreasures < treasureCount:
|
||||
let randX = rand(input.size - 1)
|
||||
let randY = rand(input.size - 1)
|
||||
if result[randX][randY] == tileEmpty:
|
||||
result[randX][randY] = tileTreasure
|
||||
inc addedTreasures
|
||||
|
||||
func tileToString*(tile: Tile): string =
|
||||
case tile:
|
||||
of tileEmpty:
|
||||
" "
|
||||
of tileTreasure:
|
||||
"T"
|
||||
|
||||
func lineToString*(line: seq[Tile]): string =
|
||||
line.map(tileToString).join()
|
||||
|
||||
proc mapToString*(map: Map): string =
|
||||
map.map(lineToString).join("\n")
|
||||
|
||||
proc printMap*(map: Map) =
|
||||
map.mapToString().echo()
|
||||
|
||||
func getTreasures*(map: Map): seq[(int, int)] =
|
||||
var treasures: seq[(int, int)]
|
||||
|
||||
for y in 0..map.high():
|
||||
for x in 0..map[0].high():
|
||||
if map[y][x] == tileTreasure:
|
||||
treasures.add((x, y))
|
||||
|
||||
return treasures
|
|
@ -0,0 +1,14 @@
|
|||
import turtle
|
||||
import turtle_type
|
||||
import input_type
|
||||
import random
|
||||
|
||||
proc mutate*(turtle: Turtle, input: Input): Turtle =
|
||||
# returns a mutated turtle
|
||||
let newTurtle = genTurtle(input)
|
||||
|
||||
for i in 0..newTurtle.memory.high():
|
||||
if rand(100) > 2:
|
||||
newTurtle.memory[i] = turtle.memory[i]
|
||||
|
||||
return newTurtle
|
|
@ -0,0 +1,38 @@
|
|||
import map_type
|
||||
import input_type
|
||||
import turtle_type
|
||||
import math
|
||||
|
||||
proc score*(turtle: Turtle, map: Map, input: Input) =
|
||||
let path = turtle.path
|
||||
# create a list of treasures
|
||||
let treasures = map.getTreasures()
|
||||
|
||||
# create a list of distances from each treasure
|
||||
var distances: seq[float] = @[]
|
||||
|
||||
for i in 0..treasures.high():
|
||||
distances.add(-1.0)
|
||||
|
||||
# iterate through the path, and change the distance if it decreases
|
||||
for i in 0..path.ys.high():
|
||||
let x = path.xs[i]
|
||||
let y = path.ys[i]
|
||||
for j in 0..treasures.high():
|
||||
let (tx, ty) = treasures[j]
|
||||
let deltaX = abs(tx - x)
|
||||
let deltaY = abs(ty - y)
|
||||
# taxicab distance
|
||||
let distance = (deltaX + deltaY).float()
|
||||
if distances[j] < 0 or distance < distances[j]:
|
||||
distances[j] = distance
|
||||
|
||||
# every distance contributes to score, exponentially dropping off
|
||||
# by the formula Ae^(-k * dist)
|
||||
var treasureScore = 0.0
|
||||
for distance in distances:
|
||||
const A = 100.0
|
||||
const k = 0.2
|
||||
treasureScore += A * exp(- k * distance)
|
||||
|
||||
turtle.score = treasureScore.int() - (turtle.steps div 5)
|
|
@ -0,0 +1,36 @@
|
|||
import random
|
||||
import math
|
||||
import algorithm
|
||||
|
||||
import turtle
|
||||
import turtle_type
|
||||
import input_type
|
||||
|
||||
proc select*(turtles: var seq[Turtle], input: Input) =
|
||||
# sort turtles according to score
|
||||
turtles.sort(compareTurtles)
|
||||
|
||||
var scoreSum = 0
|
||||
for turtle in turtles:
|
||||
scoreSum += turtle.score
|
||||
let avgScore = scoreSum div turtles.len()
|
||||
|
||||
var survivors: seq[Turtle] = @[]
|
||||
|
||||
for i in 0..turtles.high():
|
||||
let turtle = turtles[i]
|
||||
const smoothness = 0.08
|
||||
const chanceRandomLive = 0.02
|
||||
const chanceRandomDie = 0.0
|
||||
let chanceExp = exp(smoothness * float(turtles[i].score - avgScore))
|
||||
let chance = chanceRandomLive + (1-chanceRandomDie-chanceRandomLive) * chanceExp / (chanceExp + 1)
|
||||
if rand(1.0) < chance:
|
||||
survivors.add(turtle)
|
||||
|
||||
var i = 0
|
||||
while i < turtles.len():
|
||||
if turtles[i] notin survivors:
|
||||
turtles.del(i)
|
||||
else:
|
||||
inc i
|
||||
|
|
@ -0,0 +1,75 @@
|
|||
import input_type
|
||||
import map_type
|
||||
import sequtils
|
||||
|
||||
import turtle_type
|
||||
#import instruction_sets/eight_bit
|
||||
#import instruction_sets/ten_bit
|
||||
import instruction_sets/any_bit
|
||||
|
||||
proc compareTurtles*(left, right: Turtle): int =
|
||||
-cmp(left.score, right.score)
|
||||
|
||||
# general:
|
||||
|
||||
proc genTurtle*(input: Input): Turtle =
|
||||
if input.instruction_set == "anybit":
|
||||
return genAnybitTurtle(input, input.bits)
|
||||
else:
|
||||
raise newException(Defect, "Unknown instruction set.")
|
||||
|
||||
proc executeInstruction(instructionIndex: int, turtle: Turtle, map: Map, input: Input): int =
|
||||
if input.instruction_set == "anybit":
|
||||
return executeAnybit(instructionIndex.uint32, turtle, map, input, input.bits)
|
||||
else:
|
||||
raise newException(Defect, "Unknown instruction set.")
|
||||
|
||||
|
||||
proc execute*(turtle: Turtle, map: Map, input: Input) =
|
||||
|
||||
let treasures = map.getTreasures()
|
||||
|
||||
# back to start
|
||||
turtle.y = input.size div 2
|
||||
turtle.x = input.size div 2
|
||||
turtle.path.xs = @[]
|
||||
turtle.path.ys = @[]
|
||||
turtle.score = 0
|
||||
turtle.found = repeat(false, treasures.len())
|
||||
# save turtle original code
|
||||
let turtleOriginalCode = turtle.memory
|
||||
|
||||
template tpath: Path =
|
||||
turtle.path
|
||||
|
||||
proc markLocation: bool =
|
||||
tpath.xs.add(turtle.x)
|
||||
tpath.ys.add(turtle.y)
|
||||
if map[turtle.y][turtle.x] == tileTreasure:
|
||||
for i in 0..treasures.high():
|
||||
let treasure = treasures[i]
|
||||
if treasure[0] == turtle.x and treasure[1] == turtle.y:
|
||||
turtle.found[i] = true
|
||||
if turtle.found.allIt(it):
|
||||
return true
|
||||
return false
|
||||
|
||||
|
||||
discard markLocation()
|
||||
|
||||
var instructionNumber = 0
|
||||
var instructionIndex = 0
|
||||
while instructionNumber < input.lifetime:
|
||||
instructionIndex = executeInstruction(instructionIndex, turtle, map, input)
|
||||
if instructionIndex == -1:
|
||||
# out of bounds of map
|
||||
break
|
||||
|
||||
if turtle.y != tpath.ys[tpath.ys.high()] or turtle.x != tpath.xs[tpath.xs.high()]:
|
||||
if markLocation():
|
||||
break
|
||||
inc instructionNumber
|
||||
|
||||
turtle.steps = instructionNumber
|
||||
# restore original code
|
||||
turtle.memory = turtleOriginalCode
|
|
@ -0,0 +1,13 @@
|
|||
type
|
||||
Turtle* = ref object
|
||||
memory*: seq[uint32]
|
||||
x*: int
|
||||
y*: int
|
||||
score*: int
|
||||
path*: Path
|
||||
steps*: int
|
||||
found*: seq[bool]
|
||||
|
||||
Path* = object
|
||||
xs*: seq[int]
|
||||
ys*: seq[int]
|
Loading…
Reference in New Issue