Skip to content

Instantly share code, notes, and snippets.

@mipearson
Forked from parameme/scrabble_benchmarking.rb
Last active June 1, 2017 10:11
Show Gist options
  • Save mipearson/c88ff6ed5b0c801eb41f3c5a2eb6ad6b to your computer and use it in GitHub Desktop.
Save mipearson/c88ff6ed5b0c801eb41f3c5a2eb6ad6b to your computer and use it in GitHub Desktop.
POINTS = {
"A" => 1, "B" => 3, "C" => 3, "D" => 2,
"E" => 1, "F" => 4, "G" => 2, "H" => 4,
"I" => 1, "J" => 8, "K" => 5, "L" => 1,
"M" => 3, "N" => 1, "O" => 1, "P" => 3,
"Q" => 10, "R" => 1, "S" => 1, "T" => 1,
"U" => 1, "V" => 4, "W" => 4, "X" => 8,
"Y" => 4, "Z" => 10
}
MP_BYTE_CACHE = []
POINTS.each do |k, v|
MP_BYTE_CACHE[k.bytes.first] = v
MP_BYTE_CACHE[k.bytes.first + 32] = v
end
MP_BYTE_CACHE.freeze
class Letter
attr_reader :letter
def initialize letter
@letter = letter
end
def score
POINTS[letter.upcase] || 0
end
end
class Word
attr_reader :word
def initialize word
@word = word
end
def score
word.to_s.chars.map { |l| Letter.new(l).score }.inject(:+).to_i
end
end
POINTS_BY_FIXNUM = POINTS.map{ |k, v| [k.bytes.first, v] }.to_h
ASCII_CAPITALISATION_BITMASK = (255 - 32) # Mask off all but bit 6
class Scrabble
def self.hackling(word)
word ||= ""
return 0 if word == ""
word.upcase.chars.map {|char| POINTS[char] }.inject(&:+)
end
def self.jma(word)
String(word).upcase.each_char.map { |char| POINTS[char] }.inject(0, :+)
end
def self.fuzzmonkey(word)
word.to_s.chars.map{|c| POINTS[c.upcase].to_i }.inject(:+).to_i
end
def self.hybrid(word)
# I thought upcasing in the block might be faster by saving a pass through the array
String(word).each_char.map { |char| POINTS[char.upcase] }.inject(0, :+)
end
def self.hybrid2(word)
word ||= ""
return 0 if word == ""
word.chars.map {|char| POINTS[char.upcase] }.inject(&:+)
end
def self.parameme(word)
return 0 unless (word && word.is_a?(String) && word.size > 0)
word.each_byte.reduce(0) { |_, byte| _ + POINTS_BY_FIXNUM.fetch(byte & ASCII_CAPITALISATION_BITMASK) }
end
def self.mp_oop(word)
Word.new(word).score
end
def self.mp_flat(word)
sum = 0
word&.each_byte do |b|
sum += MP_BYTE_CACHE[b] || 0
end
sum
end
end
require "fruity"
word = "qwertyuiopasdfghjklzxcvbnm"
compare do
hackling { Scrabble.hackling(word) }
jma { Scrabble.jma(word) }
fuzzmonkey { Scrabble.fuzzmonkey(word) }
hybrid { Scrabble.hybrid(word) }
hybrid2 { Scrabble.hybrid2(word) }
parameme { Scrabble.parameme(word) }
mp_oop { Scrabble.mp_oop(word) }
mp_flat { Scrabble.mp_flat(word) }
end
TIMES = 500_000
require 'benchmark'
word = "qwertyuiopasdfghjklzxcvbnm"
puts "Number of Times: #{TIMES}"
puts ""
puts "Long Word"
word = "qwertyuiopasdfghjklzxcvbnm"
Benchmark.bm(12) do |x|
x.report("hackling: ") { TIMES.times { Scrabble.hackling(word) } }
x.report(" jma: ") { TIMES.times { Scrabble.jma(word) } }
x.report("fuzzmnky: ") { TIMES.times { Scrabble.fuzzmonkey(word) } }
x.report(" hybrid: ") { TIMES.times { Scrabble.hybrid(word) } }
x.report(" hybrid2: ") { TIMES.times { Scrabble.hybrid2(word) } }
x.report("parameme: ") { TIMES.times { Scrabble.parameme(word) } }
x.report(" mp_oop: ") { TIMES.times { Scrabble.mp_oop(word) } }
x.report(" mp_flat: ") { TIMES.times { Scrabble.mp_flat(word) } }
end
puts ""
puts "Short Word"
word = "qwerty"
Benchmark.bm(12) do |x|
x.report("hackling: ") { TIMES.times { Scrabble.hackling(word) } }
x.report(" jma: ") { TIMES.times { Scrabble.jma(word) } }
x.report("fuzzmnky: ") { TIMES.times { Scrabble.fuzzmonkey(word) } }
x.report(" hybrid: ") { TIMES.times { Scrabble.hybrid(word) } }
x.report(" hybrid2: ") { TIMES.times { Scrabble.hybrid2(word) } }
x.report("parameme: ") { TIMES.times { Scrabble.parameme(word) } }
x.report(" mp_oop: ") { TIMES.times { Scrabble.mp_oop(word) } }
x.report(" mp_flat: ") { TIMES.times { Scrabble.mp_flat(word) } }
end
puts ""
puts "Nil Word"
word = nil
Benchmark.bm(12) do |x|
x.report("hackling: ") { TIMES.times { Scrabble.hackling(word) } }
x.report(" jma: ") { TIMES.times { Scrabble.jma(word) } }
x.report("fuzzmnky: ") { TIMES.times { Scrabble.fuzzmonkey(word) } }
x.report(" hybrid: ") { TIMES.times { Scrabble.hybrid(word) } }
x.report(" hybrid2: ") { TIMES.times { Scrabble.hybrid2(word) } }
x.report("parameme: ") { TIMES.times { Scrabble.parameme(word) } }
x.report(" mp_oop: ") { TIMES.times { Scrabble.mp_oop(word) } }
x.report(" mp_flat: ") { TIMES.times { Scrabble.mp_flat(word) } }
end
puts ""
puts "Empty Word"
word = ""
Benchmark.bm(12) do |x|
x.report("hackling: ") { TIMES.times { Scrabble.hackling(word) } }
x.report(" jma: ") { TIMES.times { Scrabble.jma(word) } }
x.report("fuzzmnky: ") { TIMES.times { Scrabble.fuzzmonkey(word) } }
x.report(" hybrid2: ") { TIMES.times { Scrabble.hybrid2(word) } }
x.report("parameme: ") { TIMES.times { Scrabble.parameme(word) } }
x.report(" mp_oop: ") { TIMES.times { Scrabble.mp_oop(word) } }
x.report(" mp_flat: ") { TIMES.times { Scrabble.mp_flat(word) } }
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment