Intersecting number wheels: Difference between revisions

(→‎Python: Functional composition: Allowed for ill-formed wheel-sets - unrecognised wheel labels)
 
(48 intermediate revisions by 17 users not shown)
Line 61:
 
<br>
 
=={{header|11l}}==
{{trans|Python}}
 
<syntaxhighlight lang="11l">F nextfrom(&w, =name)
L
V nxt = w[name][0]
w[name] = w[name][1..] + w[name][0.<1]
I nxt[0] C ‘0’..‘9’
R nxt
name = nxt
 
L(group) |‘A: 1 2 3
A: 1 B 2; B: 3 4
A: 1 D D; D: 6 7 8
A: 1 B C; B: 3 4; C: 5 B’.split("\n")
print("Intersecting Number Wheel group:\n "group)
[String = [String]] wheel
V first = ‘’
L(w) group.split(‘;’)
V s = w.trim(‘ ’).split(‘ ’)
V name = s[0]
wheel[name[0 .< (len)-1]] = s[1..]
first = I first == ‘’ {name[0 .< (len)-1]} E first
V gen = (0.<20).map(i -> nextfrom(&@wheel, @first)).join(‘ ’)
print(" Generates:\n "gen" ...\n")</syntaxhighlight>
 
{{out}}
<pre>
Intersecting Number Wheel group:
A: 1 2 3
Generates:
1 2 3 1 2 3 1 2 3 1 2 3 1 2 3 1 2 3 1 2 ...
 
Intersecting Number Wheel group:
A: 1 B 2; B: 3 4
Generates:
1 3 2 1 4 2 1 3 2 1 4 2 1 3 2 1 4 2 1 3 ...
 
Intersecting Number Wheel group:
A: 1 D D; D: 6 7 8
Generates:
1 6 7 1 8 6 1 7 8 1 6 7 1 8 6 1 7 8 1 6 ...
 
Intersecting Number Wheel group:
A: 1 B C; B: 3 4; C: 5 B
Generates:
1 3 5 1 4 3 1 4 5 1 3 4 1 3 5 1 4 3 1 4 ...
</pre>
 
=={{header|ALGOL 68}}==
<langsyntaxhighlight lang="algol68">BEGIN
# a number wheel element #
MODE NWELEMENT = UNION( CHAR # wheel name #, INT # wheel value # );
Line 117 ⟶ 167:
, NW( "B", LOC INT := 1, ( 3, 4 ) )
, NW( "C", LOC INT := 1, ( 5, "B" ) ) ) )
END</langsyntaxhighlight>
{{out}}
<pre>
Line 141 ⟶ 191:
 
</pre>
 
=={{header|AutoHotkey}}==
<syntaxhighlight lang="autohotkey">obj1 := {"A":[1, 2, 3]}
obj2 := {"A":[1, "B", 2] , "B":[3, 4]}
obj3 := {"A":[1, "D", "D"] , "D":[6, 7, 8]}
obj4 := {"A":[1, "B", "C"] , "B":[3, 4] , "C":[5, "B"]}
 
loop 4
{
str := ""
for k, v in obj%A_Index% {
str .= "{" k " : "
for i, t in v
str .= t ","
str := Trim(str, ",") "}, "
}
str := Trim(str, ", ")
x := INW(obj%A_Index%)
result .= str "`n" x.1 "`n" x.2 "`n------`n"
}
MsgBox % result
return
 
INW(obj, num:=20){
sets := [], ptr := []
for k, v in obj {
if A_Index=1
s := k, s1 := k
%k% := v, sets.Push(k), ptr[k] := 0
}
loop % num {
ptr[s]++
while !((v := %s%[ptr[s]]) ~= "\d") {
s := %s%[ptr[s]]
ptr[s]++
}
key .= s "." ptr[s] ", "
result .= %s%[ptr[s]] " "
s := s1
for i, set in sets
ptr[set] := ptr[set] = %set%.count() ? 0 : ptr[set]
}
return [key, result]
}</syntaxhighlight>
{{out}}
<pre>{A : 1,2,3}
A.1, A.2, A.3, A.1, A.2, A.3, A.1, A.2, A.3, A.1, A.2, A.3, A.1, A.2, A.3, A.1, A.2, A.3, A.1, A.2,
1 2 3 1 2 3 1 2 3 1 2 3 1 2 3 1 2 3 1 2
------
{A : 1,B,2}, {B : 3,4}
A.1, B.1, A.3, A.1, B.2, A.3, A.1, B.1, A.3, A.1, B.2, A.3, A.1, B.1, A.3, A.1, B.2, A.3, A.1, B.1,
1 3 2 1 4 2 1 3 2 1 4 2 1 3 2 1 4 2 1 3
------
{A : 1,D,D}, {D : 6,7,8}
A.1, D.1, D.2, A.1, D.3, D.1, A.1, D.2, D.3, A.1, D.1, D.2, A.1, D.3, D.1, A.1, D.2, D.3, A.1, D.1,
1 6 7 1 8 6 1 7 8 1 6 7 1 8 6 1 7 8 1 6
------
{A : 1,B,C}, {B : 3,4}, {C : 5,B}
A.1, B.1, C.1, A.1, B.2, B.1, A.1, B.2, C.1, A.1, B.1, B.2, A.1, B.1, C.1, A.1, B.2, B.1, A.1, B.2,
1 3 5 1 4 3 1 4 5 1 3 4 1 3 5 1 4 3 1 4
------</pre>
 
=={{header|C}}==
<syntaxhighlight lang="c">#include <stdio.h>
#include <stdlib.h>
#include <string.h>
 
struct Wheel {
char *seq;
int len;
int pos;
};
 
struct Wheel *create(char *seq) {
struct Wheel *w = malloc(sizeof(struct Wheel));
if (w == NULL) {
return NULL;
}
 
w->seq = seq;
w->len = strlen(seq);
w->pos = 0;
 
return w;
}
 
char cycle(struct Wheel *w) {
char c = w->seq[w->pos];
w->pos = (w->pos + 1) % w->len;
return c;
}
 
struct Map {
struct Wheel *v;
struct Map *next;
char k;
};
 
struct Map *insert(char k, struct Wheel *v, struct Map *head) {
struct Map *m = malloc(sizeof(struct Map));
if (m == NULL) {
return NULL;
}
 
m->k = k;
m->v = v;
m->next = head;
 
return m;
}
 
struct Wheel *find(char k, struct Map *m) {
struct Map *ptr = m;
 
while (ptr != NULL) {
if (ptr->k == k) {
return ptr->v;
}
ptr = ptr->next;
}
 
return NULL;
}
 
void printOne(char k, struct Map *m) {
struct Wheel *w = find(k, m);
char c;
 
if (w == NULL) {
printf("Missing the wheel for: %c\n", k);
exit(1);
}
 
c = cycle(w);
if ('0' <= c && c <= '9') {
printf(" %c", c);
} else {
printOne(c, m);
}
}
 
void exec(char start, struct Map *m) {
struct Wheel *w;
int i;
 
if (m == NULL) {
printf("Unable to proceed.");
return;
}
 
for (i = 0; i < 20; i++) {
printOne(start, m);
}
printf("\n");
}
 
void group1() {
struct Wheel *a = create("123");
 
struct Map *m = insert('A', a, NULL);
 
exec('A', m);
}
 
void group2() {
struct Wheel *a = create("1B2");
struct Wheel *b = create("34");
 
struct Map *m = insert('A', a, NULL);
m = insert('B', b, m);
 
exec('A', m);
}
 
void group3() {
struct Wheel *a = create("1DD");
struct Wheel *d = create("678");
 
struct Map *m = insert('A', a, NULL);
m = insert('D', d, m);
 
exec('A', m);
}
 
void group4() {
struct Wheel *a = create("1BC");
struct Wheel *b = create("34");
struct Wheel *c = create("5B");
 
struct Map *m = insert('A', a, NULL);
m = insert('B', b, m);
m = insert('C', c, m);
 
exec('A', m);
}
 
int main() {
group1();
group2();
group3();
group4();
 
return 0;
}</syntaxhighlight>
{{out}}
<pre> 1 2 3 1 2 3 1 2 3 1 2 3 1 2 3 1 2 3 1 2
1 3 2 1 4 2 1 3 2 1 4 2 1 3 2 1 4 2 1 3
1 6 7 1 8 6 1 7 8 1 6 7 1 8 6 1 7 8 1 6
1 3 5 1 4 3 1 4 5 1 3 4 1 3 5 1 4 3 1 4</pre>
 
=={{header|C sharp}}==
<langsyntaxhighlight lang="csharp">using System;
using System.Collections.Generic;
using System.Linq;
Line 177 ⟶ 436:
 
static void Print(this IEnumerable<char> sequence) => Console.WriteLine(string.Join(" ", sequence));
}</langsyntaxhighlight>
{{out}}
<pre>
Line 184 ⟶ 443:
1 6 7 1 8 6 1 7 8 1 6 7 1 8 6 1 7 8 1 6
1 3 5 1 4 3 1 4 5 1 3 4 1 3 5 1 4 3 1 4</pre>
 
=={{header|C++}}==
{{trans|D}}
<syntaxhighlight lang="cpp">#include <initializer_list>
#include <iostream>
#include <map>
#include <vector>
 
struct Wheel {
private:
std::vector<char> values;
size_t index;
 
public:
Wheel() : index(0) {
// empty
}
 
Wheel(std::initializer_list<char> data) : values(data), index(0) {
//values.assign(data);
if (values.size() < 1) {
throw new std::runtime_error("Not enough elements");
}
}
 
char front() {
return values[index];
}
 
void popFront() {
index = (index + 1) % values.size();
}
};
 
struct NamedWheel {
private:
std::map<char, Wheel> wheels;
 
public:
void put(char c, Wheel w) {
wheels[c] = w;
}
 
char front(char c) {
char v = wheels[c].front();
while ('A' <= v && v <= 'Z') {
v = wheels[v].front();
}
return v;
}
 
void popFront(char c) {
auto v = wheels[c].front();
wheels[c].popFront();
 
while ('A' <= v && v <= 'Z') {
auto d = wheels[v].front();
wheels[v].popFront();
v = d;
}
}
};
 
void group1() {
Wheel w({ '1', '2', '3' });
for (size_t i = 0; i < 20; i++) {
std::cout << ' ' << w.front();
w.popFront();
}
std::cout << '\n';
}
 
void group2() {
Wheel a({ '1', 'B', '2' });
Wheel b({ '3', '4' });
 
NamedWheel n;
n.put('A', a);
n.put('B', b);
 
for (size_t i = 0; i < 20; i++) {
std::cout << ' ' << n.front('A');
n.popFront('A');
}
std::cout << '\n';
}
 
void group3() {
Wheel a({ '1', 'D', 'D' });
Wheel d({ '6', '7', '8' });
 
NamedWheel n;
n.put('A', a);
n.put('D', d);
 
for (size_t i = 0; i < 20; i++) {
std::cout << ' ' << n.front('A');
n.popFront('A');
}
std::cout << '\n';
}
 
void group4() {
Wheel a({ '1', 'B', 'C' });
Wheel b({ '3', '4' });
Wheel c({ '5', 'B' });
 
NamedWheel n;
n.put('A', a);
n.put('B', b);
n.put('C', c);
 
for (size_t i = 0; i < 20; i++) {
std::cout << ' ' << n.front('A');
n.popFront('A');
}
std::cout << '\n';
}
 
int main() {
group1();
group2();
group3();
group4();
 
return 0;
}</syntaxhighlight>
{{out}}
<pre> 1 2 3 1 2 3 1 2 3 1 2 3 1 2 3 1 2 3 1 2
1 3 2 1 4 2 1 3 2 1 4 2 1 3 2 1 4 2 1 3
1 6 7 1 8 6 1 7 8 1 6 7 1 8 6 1 7 8 1 6
1 3 5 1 4 3 1 4 5 1 3 4 1 3 5 1 4 3 1 4</pre>
 
=={{header|D}}==
<syntaxhighlight lang="d">import std.exception;
import std.range;
import std.stdio;
 
struct Wheel {
private string[] values;
private uint index;
 
invariant {
enforce(index < values.length, "index out of range");
}
 
this(string[] value...) in {
enforce(value.length > 0, "Cannot create a wheel with no elements");
} body {
values = value;
}
 
enum empty = false;
 
auto front() {
return values[index];
}
 
void popFront() {
index = (index + 1) % values.length;
}
}
 
struct NamedWheel {
private Wheel[char] wheels;
char m;
 
this(char c, Wheel w) {
add(c, w);
m = c;
}
 
void add(char c, Wheel w) {
wheels[c] = w;
}
 
enum empty = false;
 
auto front() {
auto v = wheels[m].front;
char c = v[0];
while ('A' <= c && c <= 'Z') {
v = wheels[c].front;
c = v[0];
}
return v;
}
 
void popFront() {
auto v = wheels[m].front;
wheels[m].popFront;
 
char c = v[0];
while ('A' <= c && c <= 'Z') {
auto d = wheels[c].front;
wheels[c].popFront;
c = d[0];
}
}
}
 
void group1() {
auto a = Wheel("1", "2", "3");
a.take(20).writeln;
}
 
void group2() {
auto a = Wheel("1", "B", "2");
auto b = Wheel("3", "4");
 
auto n = NamedWheel('A', a);
n.add('B', b);
 
n.take(20).writeln;
}
 
void group3() {
auto a = Wheel("1", "D", "D");
auto d = Wheel("6", "7", "8");
 
auto n = NamedWheel('A', a);
n.add('D', d);
 
n.take(20).writeln;
}
 
void group4() {
auto a = Wheel("1", "B", "C");
auto b = Wheel("3", "4");
auto c = Wheel("5", "B");
 
auto n = NamedWheel('A', a);
n.add('B', b);
n.add('C', c);
 
n.take(20).writeln;
}
 
void main() {
group1();
group2();
group3();
group4();
}</syntaxhighlight>
{{out}}
<pre>["1", "2", "3", "1", "2", "3", "1", "2", "3", "1", "2", "3", "1", "2", "3", "1", "2", "3", "1", "2"]
["1", "3", "2", "1", "4", "2", "1", "3", "2", "1", "4", "2", "1", "3", "2", "1", "4", "2", "1", "3"]
["1", "6", "7", "1", "8", "6", "1", "7", "8", "1", "6", "7", "1", "8", "6", "1", "7", "8", "1", "6"]
["1", "3", "5", "1", "4", "3", "1", "4", "5", "1", "3", "4", "1", "3", "5", "1", "4", "3", "1", "4"]</pre>
 
=={{header|F_Sharp|F#}}==
<langsyntaxhighlight lang="fsharp">
// Wheels within wheels. Nigel Galloway: September 30th., 2019.
let N(n)=fun()->n
Line 206 ⟶ 714:
for n in 0..20 do printf "%d " (A4())
printfn ""
</syntaxhighlight>
</lang>
{{out}}
<pre>
Line 231 ⟶ 739:
⁠— a dictionary-like structure that is transformed into a lazy list which yields the expected sequence elements.
{{works with|Factor|0.99 2019-07-10}}
<langsyntaxhighlight lang="factor">USING: accessors assocs circular io kernel lists lists.lazy math
math.parser multiline peg.ebnf prettyprint prettyprint.custom
sequences strings ;
Line 266 ⟶ 774:
 
: .take ( n group -- )
list>> ltake list>array [ pprint bl ] each "..." print ;</langsyntaxhighlight>
Now the interface defined above may be used:
<langsyntaxhighlight lang="factor">USING: generalizations io kernel prettyprint
rosetta-code.number-wheels ;
 
Line 294 ⟶ 802:
"Intersecting number wheel group:" print
[ . ] [ "Generates:" print 20 swap .take nl ] bi
] 4 napply</langsyntaxhighlight>
{{out}}
<pre>
Line 323 ⟶ 831:
 
=={{header|Go}}==
<langsyntaxhighlight lang="go">package main
 
import (
Line 411 ⟶ 919:
generate(wheels, "A", 20)
}
}</langsyntaxhighlight>
 
{{out}}
Line 445 ⟶ 953:
terminating at the first digit found, and printing a map-accumulation of that recursion over a list of given length but arbitrary content.
 
<syntaxhighlight lang ="haskell">import qualified Data.Map.Strict asChar M(isDigit)
import Data.Maybe (fromMaybe)
import Data.List (mapAccumL)
import qualified Data.CharMap.Strict as (isDigit)M
import Data.BoolMaybe (boolfromMaybe)
 
---------------- INTERSECTING NUMBER WHEELS --------------
clockWorkTick :: M.Map Char String -> (M.Map Char String, Char)
clockWorkTick wheelMap =
let leftRotate = take . length <*> (tail . cycle)
click wheels name =
let wheel = fromMaybe ['?'] (M.lookup name wheels)
v = head wheel
in bool
click
(,)
(isDigit v || '?' == v)
(M.insert name (leftRotate wheel) wheels)
v
in click wheelMap 'A'
 
clockWorkTick ::
M.Map Char String ->
(M.Map Char String, Char)
clockWorkTick = flip click 'A'
where
click wheels name
| isDigit name = (wheels, name)
| otherwise =
( click
. flip
(M.insert name . leftRotate)
wheels
<*> head
)
$ fromMaybe ['?'] $ M.lookup name wheels
 
leftRotate :: [a] -> [a]
leftRotate = take . length <*> (tail . cycle)
 
--------------------------- TEST -------------------------
main :: IO ()
main = do
let wheelSets =
[ [('A', "123")],
[('A', "1B2"), ('B', "34")],
[('A', "1DD"), ('D', "678")],
[('A', "1BC"), ('B', "34"), ('C', "5B")]
]
putStrLn "State of each wheel-set after 20 clicks:\n"
mapM_ print $
fmap
(flip (mapAccumL (const . clockWorkTick)) [1 .. 20] . M.fromList) <$>
[ [ ('A', "123")]flip
(mapAccumL (const . clockWorkTick))
, [('A', "1B2"), ('B', "34")]
(replicate 20 undefined)
, [('A', "1DD"), ('D', "678")]
. M.fromList
, [('A', "1BC"), ('B', "34"), ('C', "5B")]
)
]</lang>
wheelSets
putStrLn "\nInitial state of the wheel-sets:\n"
mapM_ print wheelSets</syntaxhighlight>
{{Out}}
<pre>State of each wheel-set after 20 clicks:
<pre>(fromList [('A',"312")],"12312312312312312312")
 
(fromList [('A',"312")],"12312312312312312312")
(fromList [('A',"21B"),('B',"43")],"13214213214213214213")
(fromList [('A',"D1D"),('D',"786")],"16718617816718617816")
(fromList [('A',"C1B"),('B',"34"),('C',"5B")],"13514314513413514314")</pre>
 
Initial state of the wheel-sets:
 
[('A',"123")]
[('A',"1B2"),('B',"34")]
[('A',"1DD"),('D',"678")]
[('A',"1BC"),('B',"34"),('C',"5B")]</pre>
 
=={{header|J}}==
Implementation:
<syntaxhighlight lang="j">
wheelgroup=:{{
yield_wheelgroup_=: {{
i=. wheels i.<;y
j=. i{inds
k=. ".;y
l=. j{k
inds=: ((#k)|1+j) i} inds
if. l e. wheels
do.yield l
else.{.".;l
end.
}}
gen_wheelgroup_=: {{
yield wheel
}}
grp=. cocreate ''
coinsert__grp 'wheelgroup'
specs__grp=: cut each boxopen m
wheel__grp=: ;{.wheels__grp=: {.every specs__grp
init__grp=: {{('inds';wheels)=:(0#~#specs);}.each specs}}
init__grp''
('gen_',(;grp),'_')~
}}
</syntaxhighlight>
 
Task examples:
 
<syntaxhighlight lang="j">
task=: {{y wheelgroup^:(1+i.20)_}}
task 'A 1 2 3'
1 2 3 1 2 3 1 2 3 1 2 3 1 2 3 1 2 3 1 2
task 'A 1 B 2';'B 3 4'
1 3 2 1 4 2 1 3 2 1 4 2 1 3 2 1 4 2 1 3
task 'A 1 D D';'D 6 7 8'
1 6 7 1 8 6 1 7 8 1 6 7 1 8 6 1 7 8 1 6
task 'A 1 B C';'B 3 4';'C 5 B'
1 3 5 1 4 3 1 4 5 1 3 4 1 3 5 1 4 3 1 4
</syntaxhighlight>
 
=={{header|Java}}==
<syntaxhighlight lang="java">
package intersectingNumberWheels;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.IntStream;
 
public class WheelController {
private static final String IS_NUMBER = "[0-9]";
private static final int TWENTY = 20;
private static Map<String, WheelModel> wheelMap;
 
public static void advance(String wheel) {
WheelModel w = wheelMap.get(wheel);
if (w.list.get(w.position).matches(IS_NUMBER)) {
w.printThePosition();
w.advanceThePosition();
} else {
String wheelName = w.list.get(w.position);
advance(wheelName);
w.advanceThePosition();
}
}
 
public static void run() {
System.out.println(wheelMap);
IntStream.rangeClosed(1, TWENTY).forEach(i -> advance("A"));
System.out.println();
wheelMap.clear();
}
 
public static void main(String[] args) {
wheelMap = new HashMap<>();
wheelMap.put("A", new WheelModel("A", "1", "2", "3"));
run();
wheelMap.put("A", new WheelModel("A", "1", "B", "2"));
wheelMap.put("B", new WheelModel("B", "3", "4"));
run();
wheelMap.put("A", new WheelModel("A", "1", "D", "D"));
wheelMap.put("D", new WheelModel("D", "6", "7", "8"));
run();
wheelMap.put("A", new WheelModel("A", "1", "B", "C"));
wheelMap.put("B", new WheelModel("B", "3", "4"));
wheelMap.put("C", new WheelModel("C", "5", "B"));
run();
}
 
}
 
class WheelModel {
String name;
List<String> list;
int position;
int endPosition;
private static final int INITIAL = 0;
 
public WheelModel(String name, String... values) {
super();
 
this.name = name.toUpperCase();
this.list = new ArrayList<>();
for (String value : values) {
list.add(value);
}
this.position = INITIAL;
this.endPosition = this.list.size() - 1;
}
 
@Override
public String toString() {
return list.toString();
}
 
public void advanceThePosition() {
if (this.position == this.endPosition) {
this.position = INITIAL;// new beginning
} else {
this.position++;// advance position
}
}
 
public void printThePosition() {
System.out.print(" " + this.list.get(position));
}
}
</syntaxhighlight>
Output:
{A=[1, 2, 3]}
1 2 3 1 2 3 1 2 3 1 2 3 1 2 3 1 2 3 1 2
{A=[1, B, 2], B=[3, 4]}
1 3 2 1 4 2 1 3 2 1 4 2 1 3 2 1 4 2 1 3
{A=[1, D, D], D=[6, 7, 8]}
1 6 7 1 8 6 1 7 8 1 6 7 1 8 6 1 7 8 1 6
{A=[1, B, C], B=[3, 4], C=[5, B]}
1 3 5 1 4 3 1 4 5 1 3 4 1 3 5 1 4 3 1 4
 
=={{header|JavaScript}}==
Map-accumulation of a recursive digit-search,
over an array of given length and arbitrary contents.
{{Trans|Haskell}}
{{Trans|Python}}
<syntaxhighlight lang="javascript">(() => {
'use strict';
 
// main :: IO ()
const main = () => {
 
// clockWorkTick :: Dict -> (Dict, Char)
const clockWorkTick = wheelMap => {
// The new configuration of the wheels, tupled with
// a digit found by recursive descent from a single
// click of the first wheel.
const click = wheels => wheelName => {
const
wheel = wheels[wheelName] || ['?'],
v = wheel[0];
return bool(click)(Tuple)(isDigit(v) || '?' === v)(
insertDict(wheelName)(
leftRotate(wheel)
)(wheels)
)(v);
};
return click(wheelMap)('A');
};
 
// leftRotate ::[a] -> [a]
const leftRotate = xs =>
// The head of the list appended
// to the tail of of the list.
0 < xs.length ? (
xs.slice(1).concat(xs[0])
) : [];
 
 
// TEST -------------------------------------------
// State of each wheel-set after 20 clicks,
// paired with the resulting series of characters.
 
const tuple = uncurry(Tuple);
const wheelLists = [
[tuple('A', '123')],
[tuple('A', '1B2'), tuple('B', '34')],
[tuple('A', '1DD'), tuple('D', '678')],
[tuple('A', '1BC'), tuple('B', '34'), tuple('C', '5B')]
];
 
console.log([
'Series and state of each wheel-set after 20 clicks:\n',
unlines(
map(tuples => showWheels(
mapAccumL(
compose(constant, clockWorkTick)
)(dictFromList(tuples))(replicate(20)(''))
))(wheelLists)
),
'\nInitial state of each wheel-set:\n',
map(map(compose(
JSON.stringify,
dictFromList,
x => [Array.from(x)]
)))(wheelLists).join('\n')
].join('\n'));
};
 
// DISPLAY FORMATTING ---------------------------------
 
// showWheels :: (Dict, [Char]) -> String
const showWheels = tpl =>
JSON.stringify(
Array.from(secondArrow(concat)(tpl))
);
 
// GENERIC FUNCTIONS ----------------------------------
 
// Tuple (,) :: a -> b -> (a, b)
const Tuple = a => b => ({
type: 'Tuple',
'0': a,
'1': b,
length: 2
});
 
// bool :: a -> a -> Bool -> a
const bool = f => t => p =>
p ? t : f;
 
// compose (<<<) :: (b -> c) -> (a -> b) -> a -> c
const compose = (...fs) =>
x => fs.reduceRight((a, f) => f(a), x);
 
// concat :: [[a]] -> [a]
// concat :: [String] -> String
const concat = xs =>
0 < xs.length ? (() => {
const unit = 'string' !== typeof xs[0] ? (
[]
) : '';
return unit.concat.apply(unit, xs);
})() : [];
 
// constant :: a -> b -> a
const constant = k => _ => k;
 
// dictFromList :: [(k, v)] -> Dict
const dictFromList = kvs =>
Object.fromEntries(kvs);
 
// secondArrow :: (a -> b) -> ((c, a) -> (c, b))
const secondArrow = f => xy =>
// A function over a simple value lifted
// to a function over a tuple.
// f (a, b) -> (a, f(b))
Tuple(xy[0])(
f(xy[1])
);
 
// insertDict :: String -> a -> Dict -> Dict
const insertDict = k => v => dct =>
Object.assign({}, dct, {
[k]: v
});
 
// isDigit :: Char -> Bool
const isDigit = c => {
const n = c.codePointAt(0);
return 48 <= n && 57 >= n;
};
 
// map :: (a -> b) -> [a] -> [b]
const map = f => xs =>
(Array.isArray(xs) ? (
xs
) : xs.split('')).map(f);
 
// Map-accumulation is a combination of map and a catamorphism;
// it applies a function to each element of a list, passing an
// accumulating parameter from left to right, and returning a final
// value of this accumulator together with the new list.
 
// mapAccumL :: (acc -> x -> (acc, y)) -> acc -> [x] -> (acc, [y])
const mapAccumL = f => acc => xs =>
xs.reduce((a, x) => {
const pair = f(a[0])(x);
return Tuple(pair[0])(a[1].concat(pair[1]));
}, Tuple(acc)([]));
 
// replicate :: Int -> a -> [a]
const replicate = n => x =>
Array.from({
length: n
}, () => x);
 
// uncurry :: (a -> b -> c) -> ((a, b) -> c)
const uncurry = f =>
(x, y) => f(x)(y);
 
// unlines :: [String] -> String
const unlines = xs => xs.join('\n');
 
// MAIN ---
return main();
})();</syntaxhighlight>
{{Out}}
<pre>Series and state of each wheel-set after 20 clicks:
 
[{"A":"312"},"12312312312312312312"]
[{"A":"21B","B":"43"},"13214213214213214213"]
[{"A":"D1D","D":"786"},"16718617816718617816"]
[{"A":"C1B","B":"34","C":"5B"},"13514314513413514314"]
 
Initial state of each wheel-set:
 
{"A":"123"}
{"A":"1B2"},{"B":"34"}
{"A":"1DD"},{"D":"678"}
{"A":"1BC"},{"B":"34"},{"C":"5B"}</pre>
 
=={{header|jq}}==
{{works with|jq}}
'''Also works with gojq, the Go implementation of jq'''
 
In this entry, a single wheel is simply represented by
a JSON object of the form { name: array }
 
where `name` is its name, and `array` is an array of the values on the wheel in the order
in which they would be read.
 
A set of of number of wheels can thus be represented simply as the sum of the objects corresponding to each wheel.
Thus the collection of illustrative number wheel groups can be defined as follows:
<syntaxhighlight lang="jq">
def wheels: [
{
"A": [1, 2, 3]
},
{
"A": [1, "B", 2],
"B": [3, 4]
},
{
"A": [1, "D", "D"],
"D": [6, 7, 8]
},
{
"A": [1, "B", "C"],
"B": [3, 4],
"C": [5, "B"]
}
];
</syntaxhighlight>
<syntaxhighlight lang="jq">
# read($wheel)
# where $wheel is the wheel to be read (a string)
# Input: a set of wheels
# Output: an object such that .value is the next value,
# and .state is the updated state of the set of wheels
def read($wheel):
 
# Input: an array
# Output: the rotated array
def rotate: .[1:] + [.[0]];
 
.[$wheel][0] as $value
| (.[$wheel] |= rotate) as $state
| if ($value | type) == "number"
then {$value, $state}
else $state | read($value)
end;
 
# Read wheel $wheel $n times
def multiread($wheel; $n):
if $n <= 0 then empty
else read($wheel)
| .value, (.state | multiread($wheel; $n - 1))
end;
 
def printWheels:
keys[] as $k
| "\($k): \(.[$k])";
 
# Spin each group $n times
def spin($n):
wheels[]
| "The number wheel group:",
printWheels,
"generates",
([ multiread("A"; $n) ] | join(" ") + " ..."),
"";
 
spin(20)
</syntaxhighlight>
'''Invocation'''
<pre>
jq -nr -f intersecting-number-wheels.jq
</pre>
 
{{output}}
<pre>
The number wheel group:
A: [1,2,3]
generates
1 2 3 1 2 3 1 2 3 1 2 3 1 2 3 1 2 3 1 2 ...
 
The number wheel group:
A: [1,"B",2]
B: [3,4]
generates
1 3 2 1 4 2 1 3 2 1 4 2 1 3 2 1 4 2 1 3 ...
 
The number wheel group:
A: [1,"D","D"]
D: [6,7,8]
generates
1 6 7 1 8 6 1 7 8 1 6 7 1 8 6 1 7 8 1 6 ...
 
The number wheel group:
A: [1,"B","C"]
B: [3,4]
C: [5,"B"]
generates
1 3 5 1 4 3 1 4 5 1 3 4 1 3 5 1 4 3 1 4 ...
</pre>
 
=={{header|Julia}}==
<langsyntaxhighlight lang="julia">const d1 = Dict("A" => [["1", "2", "3"], 1])
const d2 = Dict("A" => [["1", "B", "2"], 1], "B" => [["3", "4"], 1])
const d3 = Dict("A" => [["1", "D", "D"], 1], "D" => [["6", "7", "8"], 1])
Line 511 ⟶ 1,471:
 
foreach(testwheels, [d1, d2, d3, d4])
</langsyntaxhighlight>{{out}}
<pre>
Number Wheels:
Line 534 ⟶ 1,494:
</pre>
 
=={{header|Perl 6Kotlin}}==
{{trans|Java}}
A succinct Perl 6 example using a few additional language features. Wheels are implemented as infinite repeating sequences, allowing a single iterator to keep track of the current position. This means the code contains no position tracking whatsoever.
<syntaxhighlight lang="scala">import java.util.Collections
<lang perl6>
import java.util.stream.IntStream
#| advance rotates a named wheel $n by consuming an item from an infinite sequence. It is called
 
#| from within a gather block and so can use take in order to construct an infinite, lazy sequence
object WheelController {
#| of result values
private val IS_NUMBER = "[0-9]".toRegex()
sub advance($g, $n) {
private const val TWENTY = 20
given $g{$n}.pull-one {
private var wheelMap = mutableMapOf<String, WheelModel>()
when /\d/ { take $_ }
 
default { samewith $g, $_ } # samewith re-calls this function with new parameters
private fun advance(wheel: String) {
}
val w = wheelMap[wheel]
if (w!!.list[w.position].matches(IS_NUMBER)) {
w.printThePosition()
} else {
val wheelName = w.list[w.position]
advance(wheelName)
}
w.advanceThePosition()
}
 
private fun run() {
println(wheelMap)
IntStream.rangeClosed(1, TWENTY)
.forEach { advance("A") }
println()
wheelMap.clear()
}
 
@JvmStatic
fun main(args: Array<String>) {
wheelMap["A"] = WheelModel("1", "2", "3")
run()
wheelMap["A"] = WheelModel("1", "B", "2")
wheelMap["B"] = WheelModel("3", "4")
run()
wheelMap["A"] = WheelModel("1", "D", "D")
wheelMap["D"] = WheelModel("6", "7", "8")
run()
wheelMap["A"] = WheelModel("1", "B", "C")
wheelMap["B"] = WheelModel("3", "4")
wheelMap["C"] = WheelModel("5", "B")
run()
}
}
 
internal class WheelModel(vararg values: String?) {
#| Input groups are a hash containing each wheel name as the key, and a list of values constructed
var list = mutableListOf<String>()
#| using <> to split on whitespace. They are transformed using xx * to repeat the list infinitely.
var position: Int
#| We then retrieve the underlying iterator in order for wheel position to be persistent. Each group
private var endPosition: Int
#| is then aggregated into a lazy output sequence using an infinite loop inside a gather block.
 
[
override fun toString(): String {
{A => <1 2 3>},
return list.toString()
{A => <1 B 2>, B => <3 4>},
}
{A => <1 D D>, D => <6 7 8>},
 
{A => <1 B C>, B => <3 4>, C => <5 B>},
fun advanceThePosition() {
]
if (position == endPosition) {
#| %() converts a list of pairs produced by map into a hash. $^k and $^v are implicit variables.
position = INITIAL // new beginning
#| They are processed in alphabetical order and make the block arity 2, called with two vars.
} else {
#| .kv gets the list of wheel names and wheel values from the input entry
position++ // advance position
==> map({ %(.kv.map: { $^k => (|$^v xx *).iterator }) })
}
#| gather constructs a lazy sequence, in which we infinitely loop advancing wheel A
}
==> map({ gather { loop { advance $_, 'A' }} })
 
#| state variables are only initialised once, and are kept between invocations.
fun printThePosition() {
==> map({ state $i = 1; say "Group {$i++}, First 20 values: $_[^20]" })
print(" ${list[position]}")
</lang>{{Output}}
}
 
companion object {
private const val INITIAL = 0
}
 
init {
Collections.addAll<String>(list, *values)
position = INITIAL
endPosition = list.size - 1
}
}</syntaxhighlight>
{{out}}
<pre>{A=[1, 2, 3]}
1 2 3 1 2 3 1 2 3 1 2 3 1 2 3 1 2 3 1 2
{A=[1, B, 2], B=[3, 4]}
1 3 2 1 4 2 1 3 2 1 4 2 1 3 2 1 4 2 1 3
{A=[1, D, D], D=[6, 7, 8]}
1 6 7 1 8 6 1 7 8 1 6 7 1 8 6 1 7 8 1 6
{A=[1, B, C], B=[3, 4], C=[5, B]}
1 3 5 1 4 3 1 4 5 1 3 4 1 3 5 1 4 3 1 4</pre>
 
=={{header|Maple}}==
 
<syntaxhighlight lang="maple">
with(ArrayTools):
 
module Wheel()
option object;
local spokes := Array([1,2,3]);
local currentSpoke := 1;
 
export currentValue::static := proc(self::Wheel)
local valueOut;
if type(self:-spokes[self:-currentSpoke], integer) then
valueOut := self:-spokes[self:-currentSpoke]:
else
valueOut := currentValue(self:-spokes[self:-currentSpoke]):
end if:
rotate(self):
return valueOut;
end proc:
 
export rotate::static := proc(self::Wheel)
if self:-currentSpoke = ArrayNumElems(self:-spokes) then self:-currentSpoke := 1:
else self:-currentSpoke += 1: end if:
end proc:
 
export ModuleApply::static := proc()
Object(Wheel, _passed);
end proc:
 
export ModuleCopy::static := proc(new::Wheel, proto::Wheel, spo::Array, curr::integer, $)
new:-spokes := spo:
new:-currentSpoke := curr:
end proc:
end module:
 
A := Wheel(Array([1,2,3]), 1):
 
seq(currentValue(A), 1..20);
 
A := Wheel(Array([1,B,2]), 1):
B := Wheel(Array([3,4]), 1):
 
seq(currentValue(A), 1..20);
 
A := Wheel(Array([1,d,d]), 1):
d := Wheel(Array([6,7,8]), 1):
 
seq(currentValue(A), 1..20);
 
A := Wheel(Array([1,b,C]), 1):
b := Wheel(Array([3,4]), 1):
C := Wheel(Array([5,b]), 1):
 
seq(currentValue(A), 1..20);
</syntaxhighlight>
 
{{out}}<pre>
1, 2, 3, 1, 2, 3, 1, 2, 3, 1, 2, 3, 1, 2, 3, 1, 2, 3, 1, 2
 
1, 3, 2, 1, 4, 2, 1, 3, 2, 1, 4, 2, 1, 3, 2, 1, 4, 2, 1, 3
 
1, 6, 7, 1, 8, 6, 1, 7, 8, 1, 6, 7, 1, 8, 6, 1, 7, 8, 1, 6
 
1, 3, 5, 1, 4, 3, 1, 4, 5, 1, 3, 4, 1, 3, 5, 1, 4, 3, 1, 4
 
</pre>
 
=={{header|Nim}}==
<syntaxhighlight lang="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)</syntaxhighlight>
 
{{out}}
<pre>A: 1 2 3
generates:
1 2 3 1 2 3 1 2 3 1 2 3 1 2 3 1 2 3 1 2
 
A: 1 B 2
B: 3 4
generates:
1 3 2 1 4 2 1 3 2 1 4 2 1 3 2 1 4 2 1 3
 
A: 1 D D
D: 6 7 8
generates:
1 6 7 1 8 6 1 7 8 1 6 7 1 8 6 1 7 8 1 6
 
A: 1 B C
B: 3 4
C: 5 B
generates:
1 3 5 1 4 3 1 4 5 1 3 4 1 3 5 1 4 3 1 4</pre>
 
=={{header|Perl}}==
{{trans|Julia}}
<syntaxhighlight lang="perl">use strict;
use warnings;
use feature 'say';
 
sub get_next {
my($w,%wheels) = @_;
my $wh = \@{$wheels{$w}}; # reference, not a copy
my $value = $$wh[0][$$wh[1]];
$$wh[1] = ($$wh[1]+1) % @{$$wh[0]};
defined $wheels{$value} ? get_next($value,%wheels) : $value;
}
 
sub spin_wheels {
my(%wheels) = @_;
say "$_: " . join ', ', @{${$wheels{$_}}[0]} for sort keys %wheels;
print get_next('A', %wheels) . ' ' for 1..20; print "\n\n";
}
 
spin_wheels(%$_) for
(
{'A' => [['1', '2', '3'], 0]},
{'A' => [['1', 'B', '2'], 0], 'B' => [['3', '4'], 0]},
{'A' => [['1', 'D', 'D'], 0], 'D' => [['6', '7', '8'], 0]},
{'A' => [['1', 'B', 'C'], 0], 'B' => [['3', '4'], 0], 'C' => [['5', 'B'], 0]},
);</syntaxhighlight>
{{out}}
<pre>A: 1, 2, 3
1 2 3 1 2 3 1 2 3 1 2 3 1 2 3 1 2 3 1 2
 
A: 1, B, 2
B: 3, 4
1 3 2 1 4 2 1 3 2 1 4 2 1 3 2 1 4 2 1 3
 
A: 1, D, D
D: 6, 7, 8
1 6 7 1 8 6 1 7 8 1 6 7 1 8 6 1 7 8 1 6
 
A: 1, B, C
B: 3, 4
C: 5, B
1 3 5 1 4 3 1 4 5 1 3 4 1 3 5 1 4 3 1 4</pre>
 
=={{header|Phix}}==
<!--<syntaxhighlight lang="phix">(phixonline)-->
<span style="color: #008080;">with</span> <span style="color: #008080;">javascript_semantics</span>
<span style="color: #008080;">function</span> <span style="color: #000000;">terms</span><span style="color: #0000FF;">(</span><span style="color: #004080;">sequence</span> <span style="color: #000000;">wheels</span><span style="color: #0000FF;">,</span> <span style="color: #004080;">integer</span> <span style="color: #000000;">n</span><span style="color: #0000FF;">)</span>
<span style="color: #004080;">sequence</span> <span style="color: #000000;">res</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">repeat</span><span style="color: #0000FF;">(</span><span style="color: #008000;">' '</span><span style="color: #0000FF;">,</span><span style="color: #000000;">n</span><span style="color: #0000FF;">),</span>
<span style="color: #000000;">pos</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">repeat</span><span style="color: #0000FF;">(</span><span style="color: #000000;">2</span><span style="color: #0000FF;">,</span><span style="color: #7060A8;">length</span><span style="color: #0000FF;">(</span><span style="color: #000000;">wheels</span><span style="color: #0000FF;">)),</span>
<span style="color: #000000;">wvs</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">vslice</span><span style="color: #0000FF;">(</span><span style="color: #000000;">wheels</span><span style="color: #0000FF;">,</span><span style="color: #000000;">1</span><span style="color: #0000FF;">)</span>
<span style="color: #004080;">integer</span> <span style="color: #000000;">wheel</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">1</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">rdx</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">1</span>
<span style="color: #008080;">while</span> <span style="color: #000000;">rdx</span><span style="color: #0000FF;"><=</span><span style="color: #000000;">n</span> <span style="color: #008080;">do</span>
<span style="color: #004080;">integer</span> <span style="color: #000000;">p</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">pos</span><span style="color: #0000FF;">[</span><span style="color: #000000;">wheel</span><span style="color: #0000FF;">],</span>
<span style="color: #000000;">c</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">wheels</span><span style="color: #0000FF;">[</span><span style="color: #000000;">wheel</span><span style="color: #0000FF;">][</span><span style="color: #000000;">p</span><span style="color: #0000FF;">]</span>
<span style="color: #000000;">p</span> <span style="color: #0000FF;">=</span> <span style="color: #008080;">iff</span><span style="color: #0000FF;">(</span><span style="color: #000000;">p</span><span style="color: #0000FF;">=</span><span style="color: #7060A8;">length</span><span style="color: #0000FF;">(</span><span style="color: #000000;">wheels</span><span style="color: #0000FF;">[</span><span style="color: #000000;">wheel</span><span style="color: #0000FF;">])?</span><span style="color: #000000;">2</span><span style="color: #0000FF;">:</span><span style="color: #000000;">p</span><span style="color: #0000FF;">+</span><span style="color: #000000;">1</span><span style="color: #0000FF;">)</span>
<span style="color: #000000;">pos</span><span style="color: #0000FF;">[</span><span style="color: #000000;">wheel</span><span style="color: #0000FF;">]</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">p</span>
<span style="color: #008080;">if</span> <span style="color: #000000;">c</span><span style="color: #0000FF;">></span><span style="color: #008000;">'9'</span> <span style="color: #008080;">then</span>
<span style="color: #000000;">wheel</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">find</span><span style="color: #0000FF;">(</span><span style="color: #000000;">c</span><span style="color: #0000FF;">,</span><span style="color: #000000;">wvs</span><span style="color: #0000FF;">)</span>
<span style="color: #008080;">else</span>
<span style="color: #000000;">res</span><span style="color: #0000FF;">[</span><span style="color: #000000;">rdx</span><span style="color: #0000FF;">]</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">c</span>
<span style="color: #000000;">rdx</span> <span style="color: #0000FF;">+=</span> <span style="color: #000000;">1</span>
<span style="color: #000000;">wheel</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">1</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">if</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">while</span>
<span style="color: #008080;">return</span> <span style="color: #000000;">res</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">function</span>
<span style="color: #008080;">constant</span> <span style="color: #000000;">wheels</span> <span style="color: #0000FF;">=</span> <span style="color: #0000FF;">{{</span><span style="color: #008000;">"A123"</span><span style="color: #0000FF;">},</span>
<span style="color: #0000FF;">{</span><span style="color: #008000;">"A1B2"</span><span style="color: #0000FF;">,</span><span style="color: #008000;">"B34"</span><span style="color: #0000FF;">},</span>
<span style="color: #0000FF;">{</span><span style="color: #008000;">"A1DD"</span><span style="color: #0000FF;">,</span><span style="color: #008000;">"D678"</span><span style="color: #0000FF;">},</span>
<span style="color: #0000FF;">{</span><span style="color: #008000;">"A1BC"</span><span style="color: #0000FF;">,</span><span style="color: #008000;">"B34"</span><span style="color: #0000FF;">,</span><span style="color: #008000;">"C5B"</span><span style="color: #0000FF;">}}</span>
<span style="color: #008080;">for</span> <span style="color: #000000;">i</span><span style="color: #0000FF;">=</span><span style="color: #000000;">1</span> <span style="color: #008080;">to</span> <span style="color: #7060A8;">length</span><span style="color: #0000FF;">(</span><span style="color: #000000;">wheels</span><span style="color: #0000FF;">)</span> <span style="color: #008080;">do</span>
<span style="color: #0000FF;">?</span><span style="color: #000000;">terms</span><span style="color: #0000FF;">(</span><span style="color: #000000;">wheels</span><span style="color: #0000FF;">[</span><span style="color: #000000;">i</span><span style="color: #0000FF;">],</span><span style="color: #000000;">20</span><span style="color: #0000FF;">)</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">for</span>
<!--</syntaxhighlight>-->
{{out}}
<pre>
"12312312312312312312"
Group 1, First 20 values: 1 2 3 1 2 3 1 2 3 1 2 3 1 2 3 1 2 3 1 2
"13214213214213214213"
Group 2, First 20 values: 1 3 2 1 4 2 1 3 2 1 4 2 1 3 2 1 4 2 1 3
"16718617816718617816"
Group 3, First 20 values: 1 6 7 1 8 6 1 7 8 1 6 7 1 8 6 1 7 8 1 6
"13514314513413514314"
Group 4, First 20 values: 1 3 5 1 4 3 1 4 5 1 3 4 1 3 5 1 4 3 1 4
</pre>
 
=={{header|Python}}==
===Python: Original class and generator based===
<langsyntaxhighlight lang="python">from itertools import islice
 
class INW():
Line 628 ⟶ 1,877:
]:
w = INW(**group)
print(f"{w}\n Generates:\n {first(w, 20)} ...\n")</langsyntaxhighlight>
 
{{out}}
Line 656 ⟶ 1,905:
 
===Python: Simplified procedural===
<langsyntaxhighlight lang="python">def nextfrom(w, name):
while True:
nxt, w[name] = w[name][0], w[name][1:] + w[name][:1]
Line 676 ⟶ 1,925:
first = name[:-1] if first is None else first
gen = ' '.join(nextfrom(wheel, first) for i in range(20))
print(f" Generates:\n {gen} ...\n")</langsyntaxhighlight>
 
{{out}}
Line 704 ⟶ 1,953:
Input is just a list of Python dicts, and depends on c-python dicts being odered by key insertion order.
 
<langsyntaxhighlight lang="python">def nextfromr(w, name):
nxt, w[name] = w[name][0], w[name][1:] + w[name][:1]
return nxt if '0' <= nxt[0] <= '9' else nextfromr(w, nxt)
Line 716 ⟶ 1,965:
first = next(group.__iter__())
gen = ' '.join(nextfromr(group, first) for i in range(20))
print(f" Generates:\n {gen} ...\n")</langsyntaxhighlight>
 
{{out}}
Line 740 ⟶ 1,989:
 
===Python: Functional composition===
Defining a unit rotation of the wheel -set as a recursive descent, and taking
a map-accumulation of this recursion
over a list of specific length and arbitrary content.
{{Trans|Haskell}}
{{Works with|Python|3.7}}
<langsyntaxhighlight lang="python">'''Intersecting number wheels'''
 
from functools import reduce
from itertools import cycle, islice
from functools import reduce
 
 
# clockWorkTick :: Dict -> (Dict, Char)
def clockWorkTick(wheelMap):
'''The new state of the wheels, tupled with thea
digit found, bothby resultingrecursive descent from a recursivesingle
descent from a single click of the first wheel.'''
def click(wheels):
wheel, terminating at the first digit found.'''
def clickgo(wheels, namewheelName):
wheel = wheels.get(namewheelName, ['?'])
v = wheel[0]
return (Tuple if isDigit(v.isdigit() or '?' == v else curry(click))(
insertDict(namewheelName)(leftRotate(wheel))(wheels)
)(v)
return go
return click(wheelMap, 'A')
return click(wheelMap)('A')
 
 
Line 774 ⟶ 2,024:
 
 
# TEST --------------------------- TEST -------------------------
# main :: IO ()
def main():
'''First twenty values from each set of test wheels.'''
 
print('New state of wheel sets, after 20 clicks of each:\n')
wheelMaps = [dict(kvs) for kvs in [
[('A', "123")],
Line 786 ⟶ 2,035:
[('A', "1BC"), ('B', "34"), ('C', "5B")]
]]
print('New state of wheel sets, after 20 clicks of each:\n')
for wheels, series in [
mapAccumL(compose(const)(clockWorkTick))(
Line 798 ⟶ 2,048:
 
 
# GENERIC ------------------------- GENERIC ------------------------
 
# Tuple (,) :: a -> b -> (a, b)
Line 822 ⟶ 2,072:
'''
return lambda _: k
 
 
# curry :: ((a, b) -> c) -> a -> b -> c
def curry(f):
'''A curried function derived
from an uncurried function.
'''
return lambda x: lambda y: f(x, y)
 
 
# insertDict :: String -> a -> Dict -> Dict
def insertDict(k):
'''A new dictionary updated with a (k, v) pair.'''
def go(v, dct):
dup =return dict(dct, **{k: v})
dup.update({k: v})
return dup
return lambda v: lambda dct: go(v, dct)
 
 
# isDigit :: Char -> Bool
def isDigit(c):
'''True if the character c is a digit.'''
return c.isdigit() and (1 == len(c))
 
 
# mapAccumL :: (acc -> x -> (acc, y)) -> acc -> [x] -> (acc, [y])
def mapAccumL(f):
'''A tuple of an accumulation and a list derived by amap
combined map and fold,
with accumulation from left to right.
'''
def gonxt(a, x):
tpl = f(a[0])(x)
return (tpl[0], a[1] + [tpl[1]])
 
return lambda acc: lambda xs: (
def reduce(go, xs, (acc, [])):
def g(xs):
return reduce(nxt, xs, (acc, []))
return g
return go
 
 
# MAIN ---
if __name__ == '__main__':
main()</langsyntaxhighlight>
{{Out}}
<pre>New state of wheel sets, after 20 clicks of each:
Line 878 ⟶ 2,114:
{'A': '1DD', 'D': '678'}
{'A': '1BC', 'B': '34', 'C': '5B'}</pre>
 
=={{header|Quackery}}==
 
As the contents of a wheel (e.g. <code>[ 1 B 2 ]</code>) is just Quackery code, wheels can be extended in interesting ways.
 
They could, for example, contain a nest that randomly selects a wheel to advance; <code>[ 1 [ 2 random table [ B C ] ] 2 ]</code> would do the same as <code>[ 1 B 2 ]</code>, except that on the second click of the wheel, instead of always advancing wheel <code>B</code>, <code>[ 2 random table [ B C ] ]</code> would be evaluated, causing either wheel <code>B</code> or wheel <code>C</code> to advance arbitrarily.
 
<syntaxhighlight lang="quackery"> [ ]this[ ]done[
dup take behead
dup dip
[ nested join
swap put ]
do ] is wheel ( --> n )
 
[ ]'[
]'[ nested
' [ wheel ]
swap join
swap replace ] is newwheel ( --> )
forward is A forward is B forward is C
forward is D ( and so on, as required )
[ wheel [ 1 2 3 ] ] resolves A ( --> n )
 
[ wheel [ 3 4 ] ] resolves B ( --> n )
 
[ wheel [ 5 B ] ] resolves C ( --> n )
 
[ wheel [ 6 7 8 ] ] resolves D ( --> n )
 
 
20 times [ A echo sp ] cr
newwheel A [ 1 B 2 ]
20 times [ A echo sp ] cr
newwheel A [ 1 D D ]
20 times [ A echo sp ] cr
newwheel A [ 1 B C ]
newwheel B [ 3 4 ] ( As B has been used already )
( it's state may be [ 4 3 ]. )
( So we reset it to [ 3 4 ]. )
 
20 times [ A echo sp ] cr</syntaxhighlight>
 
{{out}}
 
<pre>1 2 3 1 2 3 1 2 3 1 2 3 1 2 3 1 2 3 1 2
1 3 2 1 4 2 1 3 2 1 4 2 1 3 2 1 4 2 1 3
1 6 7 1 8 6 1 7 8 1 6 7 1 8 6 1 7 8 1 6
1 3 5 1 4 3 1 4 5 1 3 4 1 3 5 1 4 3 1 4 </pre>
 
=={{header|Raku}}==
(formerly Perl 6)
A succinct Raku example using a few additional language features. Wheels are implemented as infinite repeating sequences, allowing a single iterator to keep track of the current position. This means the code contains no position tracking whatsoever.
<syntaxhighlight lang="raku" line>
#| advance rotates a named wheel $n by consuming an item from an infinite sequence. It is called
#| from within a gather block and so can use take in order to construct an infinite, lazy sequence
#| of result values
sub advance($g, $n) {
given $g{$n}.pull-one {
when /\d/ { take $_ }
default { samewith $g, $_ } # samewith re-calls this function with new parameters
}
}
 
#| Input groups are a hash containing each wheel name as the key, and a list of values constructed
#| using <> to split on whitespace. They are transformed using xx * to repeat the list infinitely.
#| We then retrieve the underlying iterator in order for wheel position to be persistent. Each group
#| is then aggregated into a lazy output sequence using an infinite loop inside a gather block.
[
{A => <1 2 3>},
{A => <1 B 2>, B => <3 4>},
{A => <1 D D>, D => <6 7 8>},
{A => <1 B C>, B => <3 4>, C => <5 B>},
]
#| %() converts a list of pairs produced by map into a hash. $^k and $^v are implicit variables.
#| They are processed in alphabetical order and make the block arity 2, called with two vars.
#| .kv gets the list of wheel names and wheel values from the input entry
==> map({ %(.kv.map: { $^k => (|$^v xx *).iterator }) })
#| gather constructs a lazy sequence, in which we infinitely loop advancing wheel A
==> map({ gather { loop { advance $_, 'A' }} })
#| state variables are only initialised once, and are kept between invocations.
==> map({ state $i = 1; say "Group {$i++}, First 20 values: $_[^20]" })
</syntaxhighlight>{{Output}}
<pre>
Group 1, First 20 values: 1 2 3 1 2 3 1 2 3 1 2 3 1 2 3 1 2 3 1 2
Group 2, First 20 values: 1 3 2 1 4 2 1 3 2 1 4 2 1 3 2 1 4 2 1 3
Group 3, First 20 values: 1 6 7 1 8 6 1 7 8 1 6 7 1 8 6 1 7 8 1 6
Group 4, First 20 values: 1 3 5 1 4 3 1 4 5 1 3 4 1 3 5 1 4 3 1 4
</pre>
 
=={{header|REXX}}==
Line 884 ⟶ 2,213:
 
This REXX program uses &nbsp; ''numbers'' &nbsp; (any form), &nbsp; not &nbsp; ''digits'' &nbsp; (for the values on the wheels).
<langsyntaxhighlight lang="rexx">/*REXX program expresses numbers from intersecting number wheels (or wheel sets). */
@.= /*initialize array to hold the wheels. */
parse arg lim @.1 /*obtain optional arguments from the CL*/
Line 893 ⟶ 2,222:
@.4= ' A: 1 B C, B: 3 4, C: 5 B '
end
do i=1 while @.i\=''; call buildrun /*construct the wheel set and (gear"execute" sets)it.*/
call run /*execute " " " " " */
end /*i*/
exit 0 /*stick a fork in it, we're all done. */
/*──────────────────────────────────────────────────────────────────────────────────────*/
error: procedure; say; say; say '***error***' arg(1); say; say; exit 12
isLet: procedure; parse arg y; return datatype( arg(1)y, 'M') & length( arg(1) y)==1 /*is a letter? */
isNum: procedure; parse arg y; return datatype( arg(1)y, 'N') /*is a number? */
/*──────────────────────────────────────────────────────────────────────────────────────*/
buildrun: @wn= 'wheel name'; first=; @wnnfbacnoColon= '"wheel name not followed by a colon:'"
@gn= 'gear name' ; gear.=; say copies('"'", 79)
say 'building wheel group for: ' @.i; wheels= space(@.i); upper wheels
do y#=1 while wheels\=''; parse var wheels w gears '",'" wheels; L= length(w)
if L==2 then do; !.y#= left(w, 1) /*obtain the 1-charone─character gear name. */
if right(w, 1)\==':' then call error @wnnfbacnoColon w
if \isLet(!.y#) then call error @wn "not a letter:" w
end
else call error "first token isn't a" @wn':' w
if y#==1 then first= !.1 /*Is this is the 1st wheel set? Use it*/
if first=='' then call error "no wheel name was specified."
n= !.y# /*obtain the name of the 1st wheel set.*/
gear.n.0= 1 /*initialize default 1st gear position.*/
say ' setting gear.name:' n ' " gears='" gears
do g=1 for words(gears); _= word(gears, g)
if isNum(_) | isLet(_) then do; gear.n.g= _; iterate; end
call error @gn "isn't a number or a gear name:" _
end /*g*/
end /*y#*/; return
say; say center(' running the wheel named ' first" ", 79, '─'); $=
/*──────────────────────────────────────────────────────────────────────────────────────*/
run: say; saydo center('dummy=0 running theby wheel0 named 'until first" ", 79, "─"words($)==lim; $n= first
do #z= gear.n.0; by 0 until words($) x==lim gear.n.z; nz= firstz + 1
z= gear.n.0; x= gear.n.z; z= z + 1
gear.n.0= z; if gear.n.z=='' then gear.n.0= 1
if isNum(x) then do; $= $ x; iterate; end /*found a number, use it.*/
xx= x /*different gear, keep switching until'til #.X*/
do forever; nn= xx
if gear.nn.0=='' then call error "a gear is using an unknown gear name:" x
zz= gear.nn.0; xx= gear.nn.zz
zz= zz + 1; gear.nn.0= zz; if gear.nn.zz=='' then gear.nn.0= 1
if isNum(xx) then do; $= $ xx; iterate #dummy; end
end /*forever*/ /* [↑] found a number, now use FIRST. */
end /*dummy*/ /*"DUMMY" is needed for the ITERATE. */
end /*until*/
say '('lim "results): " strip($); say; say; return</langsyntaxhighlight>
{{out|output|text=&nbsp; when using the default inputs:}}
<pre>
Line 972 ⟶ 2,299:
───────────────────────── running the wheel named A ──────────────────────────
(20 results): 1 3 5 1 4 3 1 4 5 1 3 4 1 3 5 1 4 3 1 4
</pre>
 
=={{header|Ruby}}==
<syntaxhighlight lang="ruby">groups = [{A: [1, 2, 3]},
{A: [1, :B, 2], B: [3, 4]},
{A: [1, :D, :D], D: [6, 7, 8]},
{A: [1, :B, :C], B: [3, 4], C: [5, :B]} ]
 
groups.each do |group|
p group
wheels = group.transform_values(&:cycle)
res = 20.times.map do
el = wheels[:A].next
el = wheels[el].next until el.is_a?(Integer)
el
end
puts res.join(" "),""
end
</syntaxhighlight>
{{out}}
<pre>{:A=>[1, 2, 3]}
1 2 3 1 2 3 1 2 3 1 2 3 1 2 3 1 2 3 1 2
 
{:A=>[1, :B, 2], :B=>[3, 4]}
1 3 2 1 4 2 1 3 2 1 4 2 1 3 2 1 4 2 1 3
 
{:A=>[1, :D, :D], :D=>[6, 7, 8]}
1 6 7 1 8 6 1 7 8 1 6 7 1 8 6 1 7 8 1 6
 
{:A=>[1, :B, :C], :B=>[3, 4], :C=>[5, :B]}
1 3 5 1 4 3 1 4 5 1 3 4 1 3 5 1 4 3 1 4
</pre>
=={{header|Visual Basic .NET}}==
{{trans|C#}}
<syntaxhighlight lang="vbnet">Imports System.Runtime.CompilerServices
 
Module Module1
 
<Extension()>
Iterator Function Loopy(Of T)(seq As IEnumerable(Of T)) As IEnumerable(Of T)
While True
For Each element In seq
Yield element
Next
End While
End Function
 
Iterator Function TurnWheels(ParamArray wheels As (name As Char, values As String)()) As IEnumerable(Of Char)
Dim data = wheels.ToDictionary(Function(wheel) wheel.name, Function(wheel) wheel.values.Loopy.GetEnumerator)
Dim primary = data(wheels(0).name)
 
Dim Turn As Func(Of IEnumerator(Of Char), Char) = Function(sequence As IEnumerator(Of Char))
sequence.MoveNext()
Dim c = sequence.Current
Return If(Char.IsDigit(c), c, Turn(data(c)))
End Function
 
While True
Yield Turn(primary)
End While
End Function
 
<Extension()>
Sub Print(sequence As IEnumerable(Of Char))
Console.WriteLine(String.Join(" ", sequence))
End Sub
 
Sub Main()
TurnWheels(("A", "123")).Take(20).Print()
TurnWheels(("A", "1B2"), ("B", "34")).Take(20).Print()
TurnWheels(("A", "1DD"), ("D", "678")).Take(20).Print()
TurnWheels(("A", "1BC"), ("B", "34"), ("C", "5B")).Take(20).Print()
End Sub
 
End Module</syntaxhighlight>
{{out}}
<pre>1 2 3 1 2 3 1 2 3 1 2 3 1 2 3 1 2 3 1 2
1 3 2 1 4 2 1 3 2 1 4 2 1 3 2 1 4 2 1 3
1 6 7 1 8 6 1 7 8 1 6 7 1 8 6 1 7 8 1 6
1 3 5 1 4 3 1 4 5 1 3 4 1 3 5 1 4 3 1 4</pre>
 
=={{header|Wren}}==
{{trans|Go}}
{{libheader|Wren-dynamic}}
{{libheader|Wren-sort}}
{{libheader|Wren-fmt}}
<syntaxhighlight lang="wren">import "./dynamic" for Struct
import "./sort" for Sort
import "./fmt" for Fmt
 
var Wheel = Struct.create("Wheel", ["next", "values"])
 
var generate = Fn.new { |wheels, start, maxCount|
var count = 0
var w = wheels[start]
while (true) {
var s = w.values[w.next]
var v = Num.fromString(s)
w.next = (w.next + 1) % w.values.count
wheels[start] = w
if (v) {
System.write("%(v) ")
count = count + 1
if (count == maxCount) {
System.print("...\n")
return
}
} else {
while (true) {
var w2 = wheels[s]
var ss = s
s = w2.values[w2.next]
w2.next = (w2.next + 1) % w2.values.count
wheels[ss] = w2
v = Num.fromString(s)
if (v) {
System.write("%(v) ")
count = count + 1
if (count == maxCount) {
System.print("...\n")
return
}
break
}
}
}
}
}
 
var printWheels = Fn.new { |wheels|
var names = []
for (name in wheels.keys) names.add(name)
Sort.quick(names)
System.print("Intersecting Number Wheel group:")
for (name in names) {
Fmt.print(" $s: $n", name, wheels[name].values)
}
System.write(" Generates:\n ")
}
 
var wheelMaps = [
{
"A": Wheel.new(0, ["1", "2", "3"])
},
{
"A": Wheel.new(0, ["1", "B", "2"]),
"B": Wheel.new(0, ["3", "4"])
},
{
"A": Wheel.new(0, ["1", "D", "D"]),
"D": Wheel.new(0, ["6", "7", "8"])
},
{
"A": Wheel.new(0, ["1", "B", "C"]),
"B": Wheel.new(0, ["3", "4"]),
"C": Wheel.new(0, ["5", "B"])
}
]
for (wheels in wheelMaps) {
printWheels.call(wheels)
generate.call(wheels, "A", 20)
}</syntaxhighlight>
 
{{out}}
<pre>
Intersecting Number Wheel group:
A: [1, 2, 3]
Generates:
1 2 3 1 2 3 1 2 3 1 2 3 1 2 3 1 2 3 1 2 ...
 
Intersecting Number Wheel group:
A: [1, B, 2]
B: [3, 4]
Generates:
1 3 2 1 4 2 1 3 2 1 4 2 1 3 2 1 4 2 1 3 ...
 
Intersecting Number Wheel group:
A: [1, D, D]
D: [6, 7, 8]
Generates:
1 6 7 1 8 6 1 7 8 1 6 7 1 8 6 1 7 8 1 6 ...
 
Intersecting Number Wheel group:
A: [1, B, C]
B: [3, 4]
C: [5, B]
Generates:
1 3 5 1 4 3 1 4 5 1 3 4 1 3 5 1 4 3 1 4 ...
</pre>
 
=={{header|zkl}}==
<langsyntaxhighlight lang="zkl">fcn intersectingNumberWheelsW(wheels){ // ("A":(a,b,"C"), "C":(d,e) ...)
ws:=wheels.pump(Dictionary(),fcn([(k,v)]){ return(k,Walker.cycle(v)) }); // new Dictionary
Walker.zero().tweak(fcn(w,wheels){
Line 983 ⟶ 2,498:
}
}.fp("A",ws)) // assume wheel A exists and is always first
}</langsyntaxhighlight>
<langsyntaxhighlight lang="zkl">wheelSets:=T( Dictionary("A",T(1,2,3)),
Dictionary("A",T(1,"B",2), "B",T(3,4)),
Dictionary("A",T(1,"D","D"), "D",T(6,7,8)),
Line 992 ⟶ 2,507:
ws.pump(String,fcn([(k,v)]){ " %s: %s\n".fmt(k,v.concat(" ")) }).print();
println("-->",intersectingNumberWheelsW(ws).walk(20).concat(" "));
}</langsyntaxhighlight>
{{out}}
<pre>
2,442

edits