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.

Advertisements

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
    ...
    

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Google photo

You are commenting using your Google account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s

%d bloggers like this: