218 lines
5.6 KiB
Nim
218 lines
5.6 KiB
Nim
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 ""
|