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