Optimize Conditionals with a Branch Table

I learned a little trick today, courtesy of this answer on quora.

Basically, rather than using a bunch of if statements, you can use an array for each option.  For example, here’s some code I created to benchmark multiple if statements vs. a switch vs. a branch table:

testing branch tables
I tried a few different ways but the branch table is consistently fastest, with the case statement coming in second.

One thing about my benchmark tests is that the first two required an array lookup in the CHOICES constant, while the branch table doesn’t require this, so that could throw off the results.  So I tried a different test:

alternate benchmarkIt turns out that CHOICES lookup was a performance hit for the first two tests, but  the branch table was still faster.

This seems obvious in hindsight.  I’m kind of surprised I never learned it before now.

Everything looks like a nail

I finished the code kata I blogged about yesterday.  I won’t share the solution since others might want to try it.  But it’s interesting how my thought process was shaped by the challenge to try not to use a nested loop.  Because of this, I didn’t think about the simplest solution, or the most efficient solution.  I thought about how I could do it without using a nested loop.  I approached it as a coding challenge rather than a math challenge, which is what it actually was.

And once I solved it as a math problem, rather than as a coding problem, the complexity dropped from exponential to linear.  So the code was improved by stepping outside of the coding domain.

I Am Determined to Build a Twitter Bot!

I haven’t figured out the problem with the MicroBlogger tutorial that I’ve been posting about. But I’ve become intrigued by the idea of building a twitter bot.

I went through the Codecademy Twitter API course. It was a nice, very basic introduction. A little googling led me to several more tutorials on building a twitterbot, which I’m posting here for reference.

How to Make an eBooks Bot

Five Steps To Build Your Own Random Non-Sequitur Twitter Bot

Create a Twitter Bot Using Ruby

Do You Know How to Create a Bot in Ruby?

LOAD_PATH problem solved, another problem pops up

I’ve been working on the hangman project at the Odin Project.

I had a basic working program. I decided to break it up into some different files to get a better understanding of how classes and files interact with each other.

I had a lot of trouble with getting the dictionary to work once I did this. The game loads a word from a text file containing a long list of random words. Once I put the game into a couple different files, I couldn’t get the text file to load anymore. I was finally able to figure out a solution, although I still don’t completely understand what happened, once I read this blog post.

It seems that once a program has been executed, the file path for that program is set. So when I changed the file structure, the program was still looking for the dictionary (the “5desk.txt” file) in the same old place and couldn’t find it. This is strange, because I didn’t move the dictionary file, just split the ruby code into two different files. I added the following to my code:

File.join(File.expand_path(File.dirname(__FILE__)), "..", "5desk.txt")

and now things work.

I am still not 100% clear on how this works (more like 60%), so if any readers have reading materials or comments that can help me understand, please share!

Once I got the dictionary to work, I had to change the ruby code a little to reference the right instance variables. As it currently stands, the program runs, but the turns are borked. Instead of the turns variable counting up from 0, I can only run one game round, the turns variable gets set to the length of the word, and the program exits. I have pushed the code to github here, and I’ll copy some of it below since the github code will change in the future.

play.rb:

File.join(File.expand_path(File.dirname(__FILE__)), "..", "5desk.txt")
require_relative "lib/hangman.rb"
require_relative "lib/game_engine.rb"

play = GameEngine.new
play.play_game

lib/game_engine.rb:

require_relative "hangman.rb"

class GameEngine

def initialize
@game = Game.new
@turns = 0
@score = 0
end

attr_accessor :turns
attr_accessor :score
attr_accessor :game

def take_guess
puts "Guess a letter!"
print ">"
input = gets.chomp.downcase
@game.guesses.push(input)
i = 0
while i <= @game.word.length
if input == @game.word[i]
puts "The word contains #{input}!"
@game.word_board[i] = input
i += 1
else
i += 1
@turns += 1
end
end
print "#{@game.word_board.join} Guesses: #{@game.guesses.join} "
end

def play_game
print @game.word.join+"n"
print @game.word_board.join
while @turns < @game.word.length
take_guess
puts " Turn #{@turns}"
end
end
#end class
end

lib/hangman.rb:
require_relative "game_engine.rb"

puts "Hangman initialized"

class Game

def initialize
puts "New game initialized"
@word = pick_random.downcase.split(//).slice(0..-2)
@word_board = []
@guesses = []
create_word_board
end

attr_accessor :word_board
attr_accessor :word
attr_accessor :guesses

def pick_random
chosen_line = nil
File.foreach("5desk.txt").each_with_index do |line, number|
chosen_line = line if rand < 1.0/(number+1)
end
return chosen_line
end

def create_word_board
@word.length.times do
@word_board.push("_ ")
end
end
end