Post on 06-May-2015
F*cking with FizzBuzzScott Windsor
@swindsor
Wednesday, July 3, 13
about me
2001-2007 amazon.com
2007-2007 BillMonk/Obopay
2007-2012 TeachStreet
2012-? amazon local
Wednesday, July 3, 13
I interview a lot.
Wednesday, July 3, 13
FizzBuzz
Wednesday, July 3, 13
FizzBuzz
Print numbers 1-100.
Wednesday, July 3, 13
FizzBuzz
Print numbers 1-100.
For multiples of 3, print “Fizz”.
Wednesday, July 3, 13
FizzBuzz
Print numbers 1-100.
For multiples of 3, print “Fizz”.
For multiples of 5, print “Buzz”.
Wednesday, July 3, 13
FizzBuzz
Print numbers 1-100.
For multiples of 3, print “Fizz”.
For multiples of 5, print “Buzz”.
For multiples of 3 and 5, print “FizzBuzz”.
Wednesday, July 3, 13
fizzbuzz.rb
1.upto(100) do |i| if i % 15 == 0 puts "FizzBuzz" elsif i % 3 == 0 puts "Fizz" elsif i % 5 == 0 puts "Buzz" else puts i endend
Wednesday, July 3, 13
Wednesday, July 3, 13
Not good for interviews
Wednesday, July 3, 13
Not good for interviews
∅ data structures
Wednesday, July 3, 13
Not good for interviews
∅ data structures
∅ algorithms
Wednesday, July 3, 13
Not good for interviews
∅ data structures
∅ algorithms
∅ problem solving
Wednesday, July 3, 13
Not good for interviews
∅ data structures
∅ algorithms
∅ problem solving
~ coding
Wednesday, July 3, 13
Not good for interviews
∅ data structures
∅ algorithms
∅ problem solving
~ coding
Wednesday, July 3, 13
How can we make this more fun?
Wednesday, July 3, 13
Fun with DSLs
class FizzBuzz < Bazinator default_rule ->(i){ i } rule ->(i){"Fizz" if i % 3 == 0 } rule ->(i){"Buzz" if i % 5 == 0 }end
FizzBuzz.new(1..100).print
Wednesday, July 3, 13
Wednesday, July 3, 13
ActiveRecord-styleclass Bazinator attr_accessor :range
def initialize(range) @range = range end
def rules @@rules end
def default_rule @@default_rule end
def self.default_rule(rule) @@default_rule = rule end
def self.rule(rule) @@rules ||= [] @@rules << rule end...
Wednesday, July 3, 13
ActiveRecord-style... def run_rules(i) results = rules.map{|rule| rule.call(i) } results.delete_if(&:nil?) results << default_rule.call(i) if results.empty? results end
def each(&block) range.each do |i| yield run_rules(i).join('') end end
def print each do |item| puts item end endend
Wednesday, July 3, 13
I can haz DSL.
class FizzBuzz < Bazinator default_rule ->(i){ i } rule ->(i){"Fizz" if i % 3 == 0 } rule ->(i){"Buzz" if i % 5 == 0 }end
FizzBuzz.new(1..100).print
Wednesday, July 3, 13
What about other languages?
Wednesday, July 3, 13
Let’s try some C#include <stdio.h>#include <string.h>
const char* fizz(int i) { if((i % 3) == 0) { return "Fizz"; } else { return ""; }}
const char* buzz(int i) { if((i % 5) == 0) { return "Buzz"; } else { return ""; }}
Wednesday, July 3, 13
Function Pointers++
Wednesday, July 3, 13
Function Pointers++#define MAX_BUFF 10#define NUMBER_FUNCTIONS 2
const char* (*dispatch[NUMBER_FUNCTIONS])(int i) = {fizz,buzz};
void itoa(int i, char* a) { snprintf(a, sizeof(a), "%i", i);}
void clear(char* s) { strncpy(s, "", sizeof(s));}
void run_functions(int i, char* result) { int f; for(f=0; f < NUMBER_FUNCTIONS; f++) { strlcat(result,(*dispatch[f])(i),sizeof(result)); }}
void add_number(int i, char* result) { char number[MAX_BUFF]; if(strnlen(result,sizeof(result)) < 1) { itoa(i,number); strlcat(result,number,sizeof(result)); }}
Wednesday, July 3, 13
Somewhere, Knuth is crying.
int main(){ char result[MAX_BUFF]; int i; for(i=1; i < 100; i++) { clear(result); run_functions(i, result); add_number(i, result); printf("%s\n", result); } return 0;}
Wednesday, July 3, 13
But wait, Java is missing out.
package com.sentientmonkey.fizzbuzz;
import com.sentientmonkey.fizzbuzz.service.FizzBuzzService;
public class Runner {
public static void main(String[] args) { FizzBuzzService fizzBuzz = new FizzBuzzService(); fizzBuzz.print(1, 100); }
}
Wednesday, July 3, 13
Best thing is the patterns.
Wednesday, July 3, 13
First you get the Service Facade.
package com.sentientmonkey.fizzbuzz.service;
import com.sentientmonkey.fizzbuzz.rules.*;
public class FizzBuzzService { RuleManager ruleManager;
public FizzBuzzService() { ruleManager = new RuleManager(); ruleManager.addRule(new FizzRule()); ruleManager.addRule(new BuzzRule()); ruleManager.addRule(new DefaultRule()); }
public void print(int start, int end) { for (int i = start; i <= end; i++) { System.out.println(ruleManager.evaluateRules(i)); } }}
Wednesday, July 3, 13
Then you get the Manager.
package com.sentientmonkey.fizzbuzz.rules;
import java.util.ArrayList;
public class RuleManager {
ArrayList<Rule> rules;
public RuleManager() { rules = new ArrayList<Rule>(); }
public void addRule(Rule rule) { rules.add(rule); }
public String evaluateRules(int number) { StringBuilder builder = new StringBuilder(); for (Rule rule : rules) { rule.withBuilder(builder).append(number); } return builder.toString(); }}
Wednesday, July 3, 13
Now you get a Builder.
package com.sentientmonkey.fizzbuzz.rules;
public abstract class Rule { StringBuilder builder = null;
public Rule withBuilder(StringBuilder builder) { this.builder = builder; return this; }
public abstract void append(int number);}
Wednesday, July 3, 13
Default Rule.
package com.sentientmonkey.fizzbuzz.rules;
public class DefaultRule extends Rule {
@Override public void append(int number) { if (builder.length() == 0) { builder.append(number); } }
}
Wednesday, July 3, 13
Fizz Rule.package com.sentientmonkey.fizzbuzz.rules;
public class FizzRule extends Rule {
@Override public void append(int number) { if ((number % 3) == 0) { builder.append("Fizz"); } }
}
Wednesday, July 3, 13
Buzz Rule.
package com.sentientmonkey.fizzbuzz.rules;
public class BuzzRule extends Rule {
@Override public void append(int number) { if ((number % 5) == 0) { builder.append("Buzz"); } }}
Wednesday, July 3, 13
le java.
package com.sentientmonkey.fizzbuzz;
import com.sentientmonkey.fizzbuzz.service.FizzBuzzService;
public class Runner {
public static void main(String[] args) { FizzBuzzService fizzBuzz = new FizzBuzzService(); fizzBuzz.print(1, 100); }
}
Wednesday, July 3, 13
Don’t forget clojure.(defn fizz [i] (if(= (mod i 3) 0) "Fizz"))
(defn buzz [i] (if(= (mod i 5) 0) "Buzz"))
(defn join [a b] (str a b))
(defn run-rules [numbers] (map join (map fizz numbers) (map buzz numbers)))
(defn number [s n] (if (= s "") n s))
Wednesday, July 3, 13
Something clever about McCarthy.
(defn fizzbuzz [start end] (let [numbers (range start end)] (doall (map println (map number (run-rules numbers) numbers)))))
(fizzbuzz 1 100)
Wednesday, July 3, 13
or javascriptfunction fizz(i) { if((i % 3) == 0){ return "Fizz"; }}
function buzz(i) { if((i % 5) == 0){ return "Buzz"; }}
var rules = [fizz,buzz];
Wednesday, July 3, 13
or javascript.function default_rule(result,i){ if(result.length > 0) { return result; } else { return i; }}
function fizz_buzz(start,end) { for(var i=start; i<=end; i++) { var result = rules.map(function(rule){ return rule(i); }).join(''); print(default_rule(result,i)); }};
fizz_buzz(1,100);
Wednesday, July 3, 13
So what did we learn?
• Interviewees: Even fizzbuzz can be fun
• Interviewers: Ask better interview questions
• Everyone: Coding is still hard
Wednesday, July 3, 13
Thanks!
Play along at home:http://github.com/sentientmonkey/fizzbuzz
Questions?
@swindsorP.S. we’re hiring
Wednesday, July 3, 13