Intersecting Number Wheels

October 1, 2019

Our implementation follows the description exactly:

(define-generator (wheel xs)
  (let loop ((ws (cycle xs)))
    (if (integer? (car ws))
        (yield (car ws))
        (yield ((eval (car ws)))))
    (loop (cdr ws))))

Here are the examples from the Rosetta Code description:

> (define a (wheel '(1 2 3)))
> (take-gen 20 a)
(1 2 3 1 2 3 1 2 3 1 2 3 1 2 3 1 2 3 1 2)
> (define a (wheel '(1 b 2)))
> (define b (wheel '(3 4)))
> (take-gen 20 a)
(1 3 2 1 4 2 1 3 2 1 4 2 1 3 2 1 4 2 1 3)
> (define a (wheel '(1 d d)))
> (define d (wheel '(6 7 8)))
> (take-gen 20 a)
(1 6 7 1 8 6 1 7 8 1 6 7 1 8 6 1 7 8 1 6)
> (define a (wheel '(1 b c)))
> (define b (wheel '(3 4)))
> (define c (wheel '(5 b)))
> (take-gen 20 a)
(1 3 5 1 4 3 1 4 5 1 3 4 1 3 5 1 4 3 1 4)

You can see the assembled program at https://ideone.com/lpMU0a, but it doesn’t run, I don’t know why, something to do with the define-generator macro. I can assure you it runs fine in Chez Scheme on my systems at home and work.

Advertisement

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 )

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: