132 lines
3.8 KiB
Nim
132 lines
3.8 KiB
Nim
import strformat, strutils
|
|
|
|
type
|
|
|
|
FCNode = ref object
|
|
name: string
|
|
weight: int
|
|
coverage: float
|
|
children: seq[FCNode]
|
|
parent: FCNode
|
|
|
|
func newFCNode(name: string; weight: int; coverage: float): FCNode =
|
|
FCNode(name: name, weight: weight, coverage: coverage)
|
|
|
|
# Forward reference.
|
|
func updateCoverage(n: FCNode)
|
|
|
|
func addChildren(n: FCNode; nodes: openArray[FCNode]) =
|
|
for node in nodes:
|
|
node.parent = n
|
|
n.children = @nodes
|
|
n.updateCoverage()
|
|
|
|
func setCoverage(n: FCNode; value: float) =
|
|
if n.coverage != value:
|
|
n.coverage = value
|
|
# Update any parent's coverage.
|
|
if not n.parent.isNil:
|
|
n.parent.updateCoverage()
|
|
|
|
func updateCoverage(n: FCNode) =
|
|
var v1 = 0.0
|
|
var v2 = 0
|
|
for node in n.children:
|
|
v1 += node.weight.toFloat * node.coverage
|
|
v2 += node.weight
|
|
n.setCoverage(v1 / v2.toFloat)
|
|
|
|
proc show(n: FCNode; level: int) =
|
|
let indent = level * 4
|
|
let nl = n.name.len + indent
|
|
const Sep = "|"
|
|
echo &"{n.name.align(nl)}{Sep.align(32-nl)} {n.weight:>3d} | {n.coverage:8.6f} |"
|
|
for child in n.children:
|
|
child.show(level + 1)
|
|
|
|
#———————————————————————————————————————————————————————————————————————————————————————————————————
|
|
|
|
let houses = [newFCNode("house1", 40, 0), newFCNode("house2", 60, 0)]
|
|
|
|
let house1 = [
|
|
newFCNode("bedrooms", 1, 0.25),
|
|
newFCNode("bathrooms", 1, 0),
|
|
newFCNode("attic", 1, 0.75),
|
|
newFCNode("kitchen", 1, 0.1),
|
|
newFCNode("living_rooms", 1, 0),
|
|
newFCNode("basement", 1, 0),
|
|
newFCNode("garage", 1, 0),
|
|
newFCNode("garden", 1, 0.8)]
|
|
|
|
let house2 = [
|
|
newFCNode("upstairs", 1, 0),
|
|
newFCNode("groundfloor", 1, 0),
|
|
newFCNode("basement", 1, 0)]
|
|
|
|
let h1Bathrooms = [
|
|
newFCNode("bathroom1", 1, 0.5),
|
|
newFCNode("bathroom2", 1, 0),
|
|
newFCNode("outside_lavatory", 1, 1)]
|
|
|
|
let h1LivingRooms = [
|
|
newFCNode("lounge", 1, 0),
|
|
newFCNode("dining_room", 1, 0),
|
|
newFCNode("conservatory", 1, 0),
|
|
newFCNode("playroom", 1, 1)]
|
|
|
|
let h2Upstairs = [
|
|
newFCNode("bedrooms", 1, 0),
|
|
newFCNode("bathroom", 1, 0),
|
|
newFCNode("toilet", 1, 0),
|
|
newFCNode("attics", 1, 0.6)]
|
|
|
|
let h2Groundfloor = [
|
|
newFCNode("kitchen", 1, 0),
|
|
newFCNode("living_rooms", 1, 0),
|
|
newFCNode("wet_room_&_toilet", 1, 0),
|
|
newFCNode("garage", 1, 0),
|
|
newFCNode("garden", 1, 0.9),
|
|
newFCNode("hot_tub_suite", 1, 1)]
|
|
|
|
let h2Basement = [
|
|
newFCNode("cellars", 1, 1),
|
|
newFCNode("wine_cellar", 1, 1),
|
|
newFCNode("cinema", 1, 0.75)]
|
|
|
|
let h2UpstairsBedrooms = [
|
|
newFCNode("suite_1", 1, 0),
|
|
newFCNode("suite_2", 1, 0),
|
|
newFCNode("bedroom_3", 1, 0),
|
|
newFCNode("bedroom_4", 1, 0)]
|
|
|
|
let h2GroundfloorLivingRooms = [
|
|
newFCNode("lounge", 1, 0),
|
|
newFCNode("dining_room", 1, 0),
|
|
newFCNode("conservatory", 1, 0),
|
|
newFCNode("playroom", 1, 0)]
|
|
|
|
let cleaning = newFCNode("cleaning", 1, 0)
|
|
|
|
house1[1].addChildren(h1Bathrooms)
|
|
house1[4].addChildren(h1LivingRooms)
|
|
houses[0].addChildren(house1)
|
|
|
|
h2Upstairs[0].addChildren(h2UpstairsBedrooms)
|
|
house2[0].addChildren(h2Upstairs)
|
|
h2Groundfloor[1].addChildren(h2GroundfloorLivingRooms)
|
|
house2[1].addChildren(h2Groundfloor)
|
|
house2[2].addChildren(h2Basement)
|
|
houses[1].addChildren(house2)
|
|
|
|
cleaning.addChildren(houses)
|
|
let topCoverage = cleaning.coverage
|
|
echo &"TOP COVERAGE = {topCoverage:8.6f}\n"
|
|
echo "NAME HIERARCHY | WEIGHT | COVERAGE |"
|
|
cleaning.show(0)
|
|
|
|
h2Basement[2].setCoverage(1) # Change Cinema node coverage to 1.
|
|
let diff = cleaning.coverage - topCoverage
|
|
echo "\nIf the coverage of the Cinema node were increased from 0.75 to 1"
|
|
echo &"the top level coverage would increase by {diff:8.6f} to {topCoverage + diff:8.6f}"
|
|
h2Basement[2].setCoverage(0.75) # Restore to original value if required.
|