RosettaCodeData/Task/Intersecting-number-wheels/Nim/intersecting-number-wheels.nim
2023-07-01 13:44:08 -04:00

65 lines
1.6 KiB
Nim

import strutils, tables
type
ElemKind = enum eValue, eWheel
Elem = object
case kind: ElemKind
of eValue:
value: Natural
of eWheel:
name: char
Wheel = ref object
elems: seq[Elem]
index: Natural
Wheels = Table[char, Wheel]
WheelDescription = tuple[name: char; elems: string]
func initWheels(wheels: openArray[WheelDescription]): Wheels =
## Initialize a table of wheels from an array of wheel descriptions.
for (name, elems) in wheels:
let wheel = new(Wheel)
for e in elems.splitWhitespace():
if e[0].isUpperAscii():
wheel.elems.add Elem(kind: eWheel, name: e[0])
else:
wheel.elems.add Elem(kind: eValue, value: e.parseInt())
result[name] = wheel
func next(wheels: Wheels; name: char): Natural =
## Return the next element from a wheel.
let wheel = wheels[name]
let elem = wheel.elems[wheel.index]
wheel.index = (wheel.index + 1) mod wheel.elems.len
result = case elem.kind
of eValue: elem.value
of eWheel: wheels.next(elem.name)
when isMainModule:
proc generate(wheelList: openArray[WheelDescription]; count: Positive) =
## Create the wheels from their description, then display
## the first "count" values generated by wheel 'A'.
let wheels = wheelList.initWheels()
for (name, elems) in wheelList:
echo name, ": ", elems
echo "generates:"
for _ in 1..count:
stdout.write ' ', wheels.next('A')
echo '\n'
{'A': "1 2 3"}.generate(20)
{'A': "1 B 2", 'B': "3 4"}.generate(20)
{'A': "1 D D", 'D': "6 7 8"}.generate(20)
{'A': "1 B C", 'B': "3 4", 'C': "5 B"}.generate(20)