## Intersecting Number Wheels

### October 1, 2019

Today’s exercise is a new task from Rosetta Code:

A number wheel has a name which is an uppercase letter and a set of ordered values which are either numbers or names. A number is generated from a named wheel by starting at the first value of the names wheel and advancing through subesquent values then wrapping around to the first value to form a “wheel”, according to the following rules: If the value is a number, yield it; if the value is a name, yield the next value from the named wheel; advance the position of the wheel. For instance, given two wheels A: 1 B 2 and B: 3 4, the sequence generated for wheel A is 1 3 2 1 4 2 1 3 2 1 4 2 ….

Your task is to write a program to calculate the sequences generated by intersecting number wheels. When you are finished, you are welcome to read or run a suggested solution, or to post your own solution or discuss the exercise in the comments below.

Pages: 1 2

### 5 Responses to “Intersecting Number Wheels”

1. chaw said

Here is a very simple solution using only R7RS Scheme plus
circular-list from SRFI 1 (and unfold for a demo). It is avoids eval
but uses destructive updates. It also requires the wheels to be
defined without forward references, which could be considered a
feature that disallows wheels like A = (B) with B = (A).

``` (import (scheme base) (scheme write) (only (srfi 1) circular-list unfold)) (define (number-wheel . vals) (let ((clst (apply circular-list vals))) (lambda () (let ((v (car clst))) (set! clst (cdr clst)) (if (procedure? v) (v) v))))) (define (demo) (define B (number-wheel 3 4)) (define A (number-wheel 1 B 2)) (display (unfold (lambda (s) (>= s 20)) (lambda (s) (A)) (lambda (s) (+ s 1)) 0)) (newline)) (demo) ```

Output:

``` (1 3 2 1 4 2 1 3 2 1 4 2 1 3 2 1 4 2 1 3) ```

2. matthew said

Here’s a C++ solution, read the wheels from the command line, 1st arg is for A, 2nd for B etc. Store in array and use second array to store current offset for each wheel:

```#include <iostream>
#include <vector>
#include <string>

int main(int argc, char *argv[]) {
std::vector<std::string> wheels(argv+1,argv+argc);
std::vector<int> state(wheels.size());
for (int i = 0; i < 20; i++) {
int n = 0;
while(true) {
char c = wheels[n][state[n]];
state[n] = (state[n]+1)%wheels[n].size();
if (isdigit(c)) {
std::cout << c;
break;
}
n = c-'A';
}
}
std::cout << "\n";
}
```
```\$ g++ -Wall wheel.cpp -o wheel
\$ ./wheel 1BC 34 5B
13514314513413514314
```
3. matthew said
```\$ ./wheel 1B2 34
13214213214213214213
```
4. matthew said

A better version:

```#include <iostream>
#include <vector>
#include <string>

class Wheels {
public:
template <typename IT>
Wheels(IT start, IT end)
: wheels(start,end), state(wheels.size()) {
}
int operator()() {
int n = 0;
while (true) {
char c = wheels[n][state[n]];
state[n] = (state[n]+1)%wheels[n].size();
if (isdigit(c)) return c-'0';
else n = c-'A';
}
}
private:
std::vector<std::string> wheels;
std::vector<int> state;
};

int main(int argc, char *argv[]) {
Wheels wheels(argv+1,argv+argc);
for (int i = 0; i < 20; i++) {
std::cout << wheels();
}
std::cout << "\n";
}
```
5. Daniel said

Here’s a solution in Python.

```from collections import deque, OrderedDict

def gen(wheels):
wheel = first = wheels[next(iter(wheels))]
while True:
value = wheel[0]
wheel.rotate(-1)
if isinstance(value, int):
wheel = first
yield value
else:
wheel = wheels[value]

wheels = OrderedDict((
('A', deque([1, 'B', 2])),
('B', deque([3, 4])),
))

for x in gen(wheels):
print(x)
```

Output:

```1
3
2
1
4
2
1
3
2
1
4
2
...
```