ruby-fizzbuzz 0.0.2

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,233 @@
1
+ /* :enddoc: */
2
+
3
+ /*
4
+ * fizzbuzz.h
5
+ *
6
+ * Copyright 2012-2013 Krzysztof Wilczynski
7
+ *
8
+ * Licensed under the Apache License, Version 2.0 (the "License");
9
+ * you may not use this file except in compliance with the License.
10
+ * You may obtain a copy of the License at
11
+ *
12
+ * http://www.apache.org/licenses/LICENSE-2.0
13
+ *
14
+ * Unless required by applicable law or agreed to in writing, software
15
+ * distributed under the License is distributed on an "AS IS" BASIS,
16
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17
+ * See the License for the specific language governing permissions and
18
+ * limitations under the License.
19
+ */
20
+
21
+ #if !defined(_FIZZBUZZ_H)
22
+ #define _FIZZBUZZ_H 1
23
+
24
+ #include "common.h"
25
+
26
+ #if defined(__cplusplus)
27
+ extern "C" {
28
+ #endif
29
+
30
+ #define ZERO INT2FIX(0)
31
+ #define ONE INT2FIX(1)
32
+ #define THREE INT2FIX(3)
33
+ #define FIVE INT2FIX(5)
34
+
35
+ #define PLUS(a, b) fizzbuzz_plus((a), (b))
36
+ #define MINUS(a, b) fizzbuzz_minus((a), (b))
37
+ #define MOD(a, b) fizzbuzz_modulo((a), (b))
38
+
39
+ #define GREATER(a, b) fizzbuzz_greater((a), (b))
40
+ #define GREATER_EQUAL(a, b) fizzbuzz_greater_equal((a), (b))
41
+ #define LESS_EQUAL(a, b) fizzbuzz_less_equal((a), (b))
42
+
43
+ #define INTEGER_P(x) (TYPE(x) == T_FIXNUM || TYPE(x) == T_BIGNUM)
44
+
45
+ #define ZERO_P(x) \
46
+ (FIXNUM_P(x) ? (NUM2TYPE(x) == 0) : fizzbuzz_equal((x), ZERO))
47
+
48
+ #define INCREASE(x) PLUS((x), ONE)
49
+ #define DECREASE(x) MINUS((x), ONE)
50
+
51
+ #define COMPUTE_MOD_3(x) ZERO_P(MOD((x), THREE))
52
+ #define COMPUTE_MOD_5(x) ZERO_P(MOD((x), FIVE))
53
+
54
+ #define SCORE_FIXNUM(x) (uint8_t)(!((x) % 3) + 2 * !((x) % 5))
55
+ #define SCORE_BIGNUM(x) (uint8_t)(COMPUTE_MOD_3(x) + 2 * COMPUTE_MOD_5(x))
56
+
57
+ #define SCORE_VALUE(x) \
58
+ (FIXNUM_P(x) ? SCORE_FIXNUM(NUM2TYPE(x)) : SCORE_BIGNUM(x))
59
+
60
+ #define IS_FIZZ(x) (!ZERO_P(x) && (SCORE_VALUE(x) == 1))
61
+ #define IS_BUZZ(x) (!ZERO_P(x) && (SCORE_VALUE(x) == 2))
62
+ #define IS_FIZZBUZZ(x) (!ZERO_P(x) && (SCORE_VALUE(x) == 3))
63
+
64
+ #define WANT_ARRAY(x) ((x) == R_TYPE_ARRAY)
65
+
66
+ #define LOOP_FORWARD(x) ((x) == D_LOOP_FORWARD)
67
+ #define LOOP_REVERSE(x) ((x) == D_LOOP_REVERSE)
68
+
69
+ #define CHECK_TYPE(x, m) \
70
+ do { \
71
+ if (!INTEGER_P(x)) \
72
+ rb_raise(rb_eTypeError, "%s", (m)); \
73
+ } while (0)
74
+
75
+ #define CHECK_BOUNDARY(a, b, m) \
76
+ do { \
77
+ if (GREATER((a), (b))) \
78
+ rb_raise(rb_eArgError, "%s", (m)); \
79
+ } while (0)
80
+
81
+ enum error {
82
+ E_INVALID_TYPE = 0,
83
+ E_INVALID_START_TYPE,
84
+ E_INVALID_STOP_TYPE,
85
+ E_BAD_VALUE_START,
86
+ E_BAD_VALUE_STOP
87
+ };
88
+
89
+ enum return_type {
90
+ R_TYPE_ARRAY = 0,
91
+ R_TYPE_ENUMERATOR
92
+ };
93
+
94
+ enum direction {
95
+ D_LOOP_FORWARD = 0,
96
+ D_LOOP_REVERSE
97
+ };
98
+
99
+ typedef enum error error_t;
100
+ typedef enum return_type return_type_t;
101
+ typedef enum direction direction_t;
102
+
103
+ static const char *errors[] = {
104
+ "must be an integer value",
105
+ "must be an integer value for start",
106
+ "must be an integer value for stop",
107
+ "start value is higher than stop value",
108
+ "stop value is lower than start value",
109
+ NULL
110
+ };
111
+
112
+ static const char *words[] = {
113
+ "Fizz", "Buzz",
114
+ "FizzBuzz", NULL
115
+ };
116
+
117
+ inline static VALUE
118
+ fizzbuzz_plus(VALUE a, VALUE b)
119
+ {
120
+ if (FIXNUM_P(a) && FIXNUM_P(b)) {
121
+ return TYPE2NUM(NUM2TYPE(a) + NUM2TYPE(b));
122
+ }
123
+
124
+ return rb_funcall(a, rb_intern("+"), 1, b);
125
+ }
126
+
127
+ inline static VALUE
128
+ fizzbuzz_minus(VALUE a, VALUE b)
129
+ {
130
+ if (FIXNUM_P(a) && FIXNUM_P(b)) {
131
+ return TYPE2NUM(NUM2TYPE(a) - NUM2TYPE(b));
132
+ }
133
+
134
+ return rb_funcall(a, rb_intern("-"), 1, b);
135
+ }
136
+
137
+ inline static VALUE
138
+ fizzbuzz_modulo(VALUE a, VALUE b)
139
+ {
140
+ if (FIXNUM_P(a) && FIXNUM_P(b)) {
141
+ return TYPE2NUM(NUM2TYPE(a) % NUM2TYPE(b));
142
+ }
143
+
144
+ return rb_funcall(a, rb_intern("%"), 1, b);
145
+ }
146
+
147
+ inline static VALUE
148
+ fizzbuzz_equal(VALUE a, VALUE b)
149
+ {
150
+ VALUE result;
151
+
152
+ if (FIXNUM_P(a) && FIXNUM_P(b)) {
153
+ result = (NUM2TYPE(a) == NUM2TYPE(b));
154
+ }
155
+ else {
156
+ result = rb_funcall(a, rb_intern("=="), 1, b);
157
+ }
158
+
159
+ return RVAL2CBOOL(result);
160
+ }
161
+
162
+ inline static VALUE
163
+ fizzbuzz_greater(VALUE a, VALUE b)
164
+ {
165
+ VALUE result;
166
+
167
+ if (FIXNUM_P(a) && FIXNUM_P(b)) {
168
+ result = (NUM2TYPE(a) > NUM2TYPE(b));
169
+ }
170
+ else {
171
+ result = rb_funcall(a, rb_intern(">"), 1, b);
172
+ }
173
+
174
+ return RVAL2CBOOL(result);
175
+ }
176
+
177
+ inline static VALUE
178
+ fizzbuzz_greater_equal(VALUE a, VALUE b)
179
+ {
180
+ VALUE result;
181
+
182
+ if (FIXNUM_P(a) && FIXNUM_P(b)) {
183
+ result = (NUM2TYPE(a) >= NUM2TYPE(b));
184
+ }
185
+ else {
186
+ result = rb_funcall(a, rb_intern(">="), 1, b);
187
+ }
188
+
189
+ return RVAL2CBOOL(result);
190
+ }
191
+
192
+ inline static VALUE
193
+ fizzbuzz_less_equal(VALUE a, VALUE b)
194
+ {
195
+ VALUE result;
196
+
197
+ if (FIXNUM_P(a) && FIXNUM_P(b)) {
198
+ result = (NUM2TYPE(a) <= NUM2TYPE(b));
199
+ }
200
+ else {
201
+ result = rb_funcall(a, rb_intern("<="), 1, b);
202
+ }
203
+
204
+ return RVAL2CBOOL(result);
205
+ }
206
+
207
+ RUBY_EXTERN ID id_at_start, id_at_stop;
208
+ RUBY_EXTERN VALUE rb_cFizzBuzz;
209
+
210
+ RUBY_EXTERN VALUE rb_fb_initialize(int argc, VALUE *argv, VALUE object);
211
+
212
+ RUBY_EXTERN VALUE rb_fb_get_start(VALUE object);
213
+ RUBY_EXTERN VALUE rb_fb_set_start(VALUE object, VALUE value);
214
+ RUBY_EXTERN VALUE rb_fb_get_stop(VALUE object);
215
+ RUBY_EXTERN VALUE rb_fb_set_stop(VALUE object, VALUE value);
216
+
217
+ RUBY_EXTERN VALUE rb_fb_array(VALUE object);
218
+ RUBY_EXTERN VALUE rb_fb_enumerator(VALUE object);
219
+ RUBY_EXTERN VALUE rb_fb_reverse_enumerator(VALUE object);
220
+
221
+ RUBY_EXTERN VALUE rb_fb_is_fizz(VALUE object, VALUE value);
222
+ RUBY_EXTERN VALUE rb_fb_is_buzz(VALUE object, VALUE value);
223
+ RUBY_EXTERN VALUE rb_fb_is_fizzbuzz(VALUE object, VALUE value);
224
+
225
+ RUBY_EXTERN VALUE rb_fb_square(VALUE object, VALUE value);
226
+
227
+ #if defined(__cplusplus)
228
+ }
229
+ #endif
230
+
231
+ #endif /* _FIZZBUZZ_H */
232
+
233
+ /* vim: set ts=8 sw=4 sts=2 et : */
data/lib/fizzbuzz.rb ADDED
@@ -0,0 +1,94 @@
1
+ # -*- encoding: utf-8 -*-
2
+
3
+ # :stopdoc:
4
+
5
+ #
6
+ # fizzbuzz.rb
7
+ #
8
+ # Copyright 2012-2013 Krzysztof Wilczynski
9
+ #
10
+ # Licensed under the Apache License, Version 2.0 (the "License");
11
+ # you may not use this file except in compliance with the License.
12
+ # You may obtain a copy of the License at
13
+ #
14
+ # http://www.apache.org/licenses/LICENSE-2.0
15
+ #
16
+ # Unless required by applicable law or agreed to in writing, software
17
+ # distributed under the License is distributed on an "AS IS" BASIS,
18
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
19
+ # See the License for the specific language governing permissions and
20
+ # limitations under the License.
21
+ #
22
+
23
+ # :startdoc:
24
+
25
+ require 'fizzbuzz/fizzbuzz'
26
+ require 'fizzbuzz/version'
27
+ require 'fizzbuzz/integer'
28
+ require 'fizzbuzz/bignum'
29
+
30
+ #
31
+ # Yet another _FizzBuzz_ in Ruby.
32
+ #
33
+ # Provides simple and fast solution to a popular _FizzBuzz_ problem for Ruby.
34
+ #
35
+ class FizzBuzz
36
+ #
37
+ # call-seq:
38
+ # FizzBuzz.fizzbuzz( start, stop, reverse ) -> array
39
+ # FizzBuzz.fizzbuzz( start, stop, reverse ) {|value| block } -> self
40
+ #
41
+ # Returns either an array or accepts a block if such is given. When a block is given
42
+ # then it will call the block once for each subsequent value for a given range from
43
+ # +start+ to +stop+, passing the value as a parameter to the block.
44
+ #
45
+ # Additionally, if the value of +reverse+ is set to be +true+ then the results will
46
+ # be given in an <em>reverse order</em> whether in a resulting array or when passing
47
+ # values to a block given.
48
+ #
49
+ # Example:
50
+ #
51
+ # FizzBuzz.fizzbuzz(1, 15) #=> [1, 2, "Fizz", 4, "Buzz", "Fizz", 7, 8, "Fizz", "Buzz", 11, "Fizz", 13, 14, "FizzBuzz"]
52
+ # FizzBuzz.fizzbuzz(1, 15, true) #=> ["FizzBuzz", 14, 13, "Fizz", 11, "Buzz", "Fizz", 8, 7, "Fizz", "Buzz", 4, "Fizz", 2, 1]
53
+ #
54
+ # Example:
55
+ #
56
+ # FizzBuzz.fizzbuzz(1, 15) {|value| puts "Got #{value}" }
57
+ #
58
+ # Produces:
59
+ #
60
+ # Got 1
61
+ # Got 2
62
+ # Got Fizz
63
+ # Got 4
64
+ # Got Buzz
65
+ # Got Fizz
66
+ # Got 7
67
+ # Got 8
68
+ # Got Fizz
69
+ # Got Buzz
70
+ # Got 11
71
+ # Got Fizz
72
+ # Got 13
73
+ # Got 14
74
+ # Got FizzBuzz
75
+ #
76
+ # See also: FizzBuzz::[], FizzBuzz::new, FizzBuzz#to_a, FizzBuzz#each and FizzBuzz#reverse_each
77
+ #
78
+ def self.fizzbuzz(start, stop, reverse = false)
79
+ fb = FizzBuzz.new(start, stop)
80
+
81
+ if block_given?
82
+ fb.send(reverse ? :reverse_each : :each) {|i| yield i }
83
+ else
84
+ reverse ? fb.to_a.reverse : fb.to_a
85
+ end
86
+ end
87
+ end
88
+
89
+ # :enddoc:
90
+
91
+ FB = FizzBuzz
92
+
93
+ # vim: set ts=2 sw=2 sts=2 et :
94
+ # encoding: utf-8
@@ -0,0 +1,90 @@
1
+ # -*- encoding: utf-8 -*-
2
+
3
+ # :stopdoc:
4
+
5
+ #
6
+ # bignum.rb
7
+ #
8
+ # Copyright 2012-2013 Krzysztof Wilczynski
9
+ #
10
+ # Licensed under the Apache License, Version 2.0 (the "License");
11
+ # you may not use this file except in compliance with the License.
12
+ # You may obtain a copy of the License at
13
+ #
14
+ # http://www.apache.org/licenses/LICENSE-2.0
15
+ #
16
+ # Unless required by applicable law or agreed to in writing, software
17
+ # distributed under the License is distributed on an "AS IS" BASIS,
18
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
19
+ # See the License for the specific language governing permissions and
20
+ # limitations under the License.
21
+ #
22
+
23
+ # :startdoc:
24
+
25
+ #
26
+ # Provides a convenient integration of _FizzBuzz_ with _Bignum_ class.
27
+ #
28
+ class Bignum
29
+ #
30
+ # call-seq:
31
+ # Bignum.fizz? -> true or false
32
+ #
33
+ # Returns +true+ if a given integer value is divisible by *three* (given
34
+ # value is a _Fizz_), or +false+ otherwise.
35
+ #
36
+ # Example:
37
+ #
38
+ # 1000000000000.fizz? #=> false
39
+ # 1000000000002.fizz? #=> true
40
+ # 1000000000005.fizz? #=> false
41
+ #
42
+ # See also: FizzBuzz::[] and FizzBuzz::is_fizz?
43
+ #
44
+ def fizz?
45
+ FizzBuzz.is_fizz?(self)
46
+ end
47
+
48
+ #
49
+ # call-seq:
50
+ # Bignum.buzz? -> true or false
51
+ #
52
+ # Returns +true+ if a given integer value is divisible by *five* (given
53
+ # value is a _Buzz_), or +false+ otherwise.
54
+ #
55
+ # Example:
56
+ #
57
+ # 1000000000000.buzz? #=> true
58
+ # 1000000000002.buzz? #=> false
59
+ # 1000000000005.buzz? #=> false
60
+ #
61
+ # See also: FizzBuzz::[] and FizzBuzz::is_buzz?
62
+ #
63
+ def buzz?
64
+ FizzBuzz.is_buzz?(self)
65
+ end
66
+
67
+ #
68
+ # call-seq:
69
+ # Bignum.fizzbuzz? -> true or false
70
+ #
71
+ # Returns +true+ if a given integer value is divisible by both *three*
72
+ # and *five* (given value is a _FizzBuzz_), or +false+ otherwise.
73
+ #
74
+ # Example:
75
+ #
76
+ # 1000000000000.fizzbuzz? #=> false
77
+ # 1000000000002.fizzbuzz? #=> false
78
+ # 1000000000005.fizzbuzz? #=> true
79
+ #
80
+ # See also: FizzBuzz::[] and FizzBuzz::is_fizzbuzz?
81
+ #
82
+ def fizzbuzz?
83
+ FizzBuzz.is_fizzbuzz?(self)
84
+ end
85
+ end
86
+
87
+ # :enddoc:
88
+
89
+ # vim: set ts=2 sw=2 sts=2 et :
90
+ # encoding: utf-8
@@ -0,0 +1,90 @@
1
+ # -*- encoding: utf-8 -*-
2
+
3
+ # :stopdoc:
4
+
5
+ #
6
+ # integer.rb
7
+ #
8
+ # Copyright 2012 Krzysztof Wilczynski
9
+ #
10
+ # Licensed under the Apache License, Version 2.0 (the "License");
11
+ # you may not use this file except in compliance with the License.
12
+ # You may obtain a copy of the License at
13
+ #
14
+ # http://www.apache.org/licenses/LICENSE-2.0
15
+ #
16
+ # Unless required by applicable law or agreed to in writing, software
17
+ # distributed under the License is distributed on an "AS IS" BASIS,
18
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
19
+ # See the License for the specific language governing permissions and
20
+ # limitations under the License.
21
+ #
22
+
23
+ # :startdoc:
24
+
25
+ #
26
+ # Provides a convenient integration of _FizzBuzz_ with _Integer_ class.
27
+ #
28
+ class Integer
29
+ #
30
+ # call-seq:
31
+ # Integer.fizz? -> true or false
32
+ #
33
+ # Returns +true+ if a given integer value is divisible by *three* (given
34
+ # value is a _Fizz_), or +false+ otherwise.
35
+ #
36
+ # Example:
37
+ #
38
+ # 3.fizz? #=> true
39
+ # 5.fizz? #=> false
40
+ # 15.fizz? #=> false
41
+ #
42
+ # See also: FizzBuzz::[] and FizzBuzz::is_fizz?
43
+ #
44
+ def fizz?
45
+ FizzBuzz.is_fizz?(self)
46
+ end
47
+
48
+ #
49
+ # call-seq:
50
+ # Integer.buzz? -> true or false
51
+ #
52
+ # Returns +true+ if a given integer value is divisible by *five* (given
53
+ # value is a _Buzz_), or +false+ otherwise.
54
+ #
55
+ # Example:
56
+ #
57
+ # 3.buzz? #=> false
58
+ # 5.buzz? #=> true
59
+ # 15.buzz? #=> false
60
+ #
61
+ # See also: FizzBuzz::[] and FizzBuzz::is_buzz?
62
+ #
63
+ def buzz?
64
+ FizzBuzz.is_buzz?(self)
65
+ end
66
+
67
+ #
68
+ # call-seq:
69
+ # Integer.fizzbuzz? -> true or false
70
+ #
71
+ # Returns +true+ if a given integer value is divisible by both *three*
72
+ # and *five* (given value is a _FizzBuzz_), or +false+ otherwise.
73
+ #
74
+ # Example:
75
+ #
76
+ # 3.fizzbuzz? #=> false
77
+ # 5.fizzbuzz? #=> false
78
+ # 15.fizzbuzz? #=> true
79
+ #
80
+ # See also: FizzBuzz::[] and FizzBuzz::is_fizzbuzz?
81
+ #
82
+ def fizzbuzz?
83
+ FizzBuzz.is_fizzbuzz?(self)
84
+ end
85
+ end
86
+
87
+ # :enddoc:
88
+
89
+ # vim: set ts=2 sw=2 sts=2 et :
90
+ # encoding: utf-8