Initial commit.
fizzin' and buzzin'.
This commit is contained in:
commit
082082fcb9
4 changed files with 157 additions and 0 deletions
6
LICENCE
Normal file
6
LICENCE
Normal file
|
@ -0,0 +1,6 @@
|
|||
Copyright 2020 Linus Björnstam
|
||||
|
||||
Permission to use, copy, modify, and/or distribute this software for any
|
||||
purpose with or without fee is hereby granted, provided that the above
|
||||
copyright notice and this permission notice appear in all source copies.
|
||||
The software is provided "as is", without any express or implied warranties.
|
52
README.md
Normal file
52
README.md
Normal file
|
@ -0,0 +1,52 @@
|
|||
# wheel-utils
|
||||
|
||||
I wanted to write a fast, straight-forward, extensible fizzbuzz program. This is a small utility I wrote to do it. It can generate simple wheels that you can use if you have a recurring sequence (like fizzbuzz).
|
||||
|
||||
## documentation
|
||||
|
||||
## usage
|
||||
|
||||
Put it in your site-dir. Then you should be able to:
|
||||
|
||||
(use-modules (wheel-utils wheel))
|
||||
|
||||
### every-n in value [n]
|
||||
|
||||
(every-n-in "fizz" 3) -> '(#f #f "fizz")
|
||||
(every-n-in "bugz" 2 3) -> (#f "bugz" #f)
|
||||
|
||||
This is a procedure used to generate proto-wheels that are merged together into a larger proto-wheel using generate-wheel.
|
||||
|
||||
### generate-wheel combine proto-wheels ...
|
||||
Combines proto-wheels using the combine procedure and returns a new, larger proto-wheel:
|
||||
|
||||
(define fizz '(every-n-in "fizz" 3))
|
||||
(define buzz '(every-n-in "buzz" 5))
|
||||
(define (combine . args)
|
||||
(let ((args (filter values args)))
|
||||
(if (null? args)
|
||||
#f
|
||||
(apply string-append args))))
|
||||
(define proto-wheel (generate-wheel combine fizz buzz))
|
||||
|
||||
Proto-wheel can now be converted to a circular list or a vector depending on your needs. Most people will probably convert it to a circular-list, but wheels _can_ grow prohibitively large and using a vector might fit more into the cpu cache. The fizzbuzz wheel is just 15 elements long. A fizz-buzz-bar (where bar is instead of multiples of 7) is 105 elements long. fizz-buzz-bar-quux (quux instead of 11) means 1155 elements.
|
||||
|
||||
## How fast was your fizzbuzz
|
||||
How does our fizzbuzz fare against a naive implementation? Using the code in example.scm (both procedures generate lists of fizzy and buzzy goodness) these are my numbers:
|
||||
|
||||
scheme@(guile-user)> ,time (car (regular-fizzbuzz 10000000))
|
||||
$26 = 1
|
||||
;; 1.161756s real time, 1.242915s run time. 0.314005s spent in GC.
|
||||
scheme@(guile-user)> ,time (car (wheel-fizzbuzz 10000000))
|
||||
$27 = 1
|
||||
;; 0.528079s real time, 0.614268s run time. 0.312021s spent in GC.
|
||||
|
||||
It can of course be done faster, but not necessarily in such a simple way. The wheel version is also trivially extensible if you are unsure about your future fizzbuzzing needs.
|
||||
|
||||
## Todo
|
||||
|
||||
It would be fun to be able to generate step wheels, like for example a prime wheel where we can just skip large parts of the number line.
|
||||
|
||||
## Licence
|
||||
|
||||
a simplified ISC. Non of that big-letter stuff matters in my jurisdiction, so I removed it. You may use it under regular ISC if you please.
|
43
example.scm
Normal file
43
example.scm
Normal file
|
@ -0,0 +1,43 @@
|
|||
(use-modules (srfi srfi-1)
|
||||
(wheel-utils wheel))
|
||||
;;; Example: fizzbuzz.
|
||||
;; First we generate out sub-proto-wheels.
|
||||
(define fizz (every-n-in "fizz" 3))
|
||||
(define buzz (every-n-in "buzz" 5))
|
||||
|
||||
;; Then we merge our proto-wheels
|
||||
(define proto-wheel (generate-wheel
|
||||
(lambda x
|
||||
(let ((l (filter values x)))
|
||||
(if (null? l)
|
||||
#f
|
||||
(apply string-append l))))
|
||||
fizz
|
||||
buzz))
|
||||
|
||||
;; Then we make our wheel circular so that we don't have to check any null.
|
||||
(define actual-wheel (apply circular-list proto-wheel))
|
||||
|
||||
;; Here we loop from 1 to 99 and print every "opening" in the wheel
|
||||
;; This _should_ be quite a lot faster than a solution that uses
|
||||
;; division, and it should be quite extensible. We could easily add
|
||||
;; a baz every 7 numbers.
|
||||
|
||||
(define (wheel-fizzbuzz n)
|
||||
(let loop ((i 1) (wheel actual-wheel))
|
||||
(if (> i n)
|
||||
'()
|
||||
(cons (or (car wheel) i) (loop (+ i 1) (cdr wheel))))))
|
||||
|
||||
(define (regular-fizzbuzz n)
|
||||
(let loop ((i 1))
|
||||
(cond
|
||||
((> i n) '())
|
||||
((eq? 0 (euclidean-remainder i 15))
|
||||
(cons "fizzbuzz" (loop (+ i 1))))
|
||||
((eq? 0 (euclidean-remainder i 3))
|
||||
(cons "fizz" (loop (+ i 1))))
|
||||
((eq? 0 (euclidean-remainder i 5))
|
||||
(cons "buzz" (loop (+ i 1))))
|
||||
(else
|
||||
(cons i (loop (+ i 1)))))))
|
56
wheel-utils/wheel.scm
Normal file
56
wheel-utils/wheel.scm
Normal file
|
@ -0,0 +1,56 @@
|
|||
;; Copyright 2020 Linus Björnstam
|
||||
;;
|
||||
;; Permission to use, copy, modify, and/or distribute this software for any
|
||||
;; purpose with or without fee is hereby granted, provided that the above
|
||||
;; copyright notice and this permission notice appear in all source copies.
|
||||
;; The software is provided "as is", without any express or implied warranties.
|
||||
|
||||
;; Some code for generating simple wheels.
|
||||
;; It has had zero optimization work done, meaning that long wheels can take
|
||||
;; a long time to generate. In the far future, I hope to extend this to
|
||||
;; do prime wheel distances: I want to be able to feed it a list of primes
|
||||
;; and that it should generate "steps" to take to jump over multiples of said
|
||||
;; primes. It doesn't do that right now.
|
||||
|
||||
|
||||
(define-module (wheel-utils wheel)
|
||||
#:use-module ((srfi srfi-1) #:select (every))
|
||||
#:export (every-n-in generate-wheel))
|
||||
(define (next lsts)
|
||||
(map (lambda (x) (if (null? (cddr x))
|
||||
(cons (car x) (car x))
|
||||
(cons (car x) (cddr x))))
|
||||
lsts))
|
||||
|
||||
(define (stop? lsts)
|
||||
(every (lambda (x) (null? (cddr x))) lsts))
|
||||
|
||||
(define every-n-in
|
||||
(case-lambda
|
||||
((val n)
|
||||
(every-n-in val n n))
|
||||
((val pos out-of)
|
||||
(let loop ((i 1))
|
||||
(cond
|
||||
((= i (+ out-of 1))
|
||||
'())
|
||||
((= i pos)
|
||||
(cons val (loop (+ i 1))))
|
||||
(else
|
||||
(cons #f (loop (+ i 1)))))))
|
||||
((val n i . pos)
|
||||
(error "not implemented yet"))))
|
||||
|
||||
|
||||
(define (generate-wheel combine . lsts)
|
||||
;; We need to keep track of the starting point of the lists
|
||||
;; so we store them in a pair of (start . current-pos)
|
||||
(let loop ((lsts (map (lambda (x) (cons x x)) lsts)))
|
||||
(cons
|
||||
(apply combine (map cadr lsts))
|
||||
(if (stop? lsts)
|
||||
'()
|
||||
(loop (next lsts))))))
|
||||
|
||||
|
||||
|
Loading…
Add table
Add a link
Reference in a new issue