Ruby Turing Machine (quiz #24 solution)

James Edward Gray II <james-AUi9nNu29NfWNcQ1/[email protected]> Fri, 17 Sep 2004 10:08:22 -0500
Newsgroups gmane.comp.lang.perl.qotw.discuss
Message-ID <[email protected]>
My compliments to the quiz maker for finding something quick yet 
interesting.

Below is my solution in Ruby.

James Edward Gray II

#!/usr/bin/ruby

class Tape
	def initialize(value)
		@value = value.split("");
		@head = 0;
	end
	
	def left
		if @head == 0
			@value.unshift "_"
		else
			@head -= 1
		end
	end
	
	def right
		if @head == @value.size - 1
			@value.push "_"
		end
		@head += 1
	end
	
	def read
		return @value[@head]
	end
	
	def write(char)
		@value[@head] = char
	end
	
	def to_s
		return @value.join("").sub(/^_+/, "").sub(/_+$/, "")
	end
end

class TuringMachine
	def initialize(instructions, tape = "_")
		@instructions = { }
		IO.foreach instructions do |line|
			if line =~ /^\s*(\w+)\s+(\w)\s+(\w+)\s+(\w)\s+([LR])/i
				@instructions[$1 + " " + $2] = [$3, $4, $5.downcase]
				@state = $1 if @state.nil?
			end
		end
		@tape = Tape.new tape
	end
	
	def run
		while action = @instructions[@state + " " + @tape.read]
			@state = action[0]
			@tape.write action[1]
			if action[2] == "l"
				@tape.left
			else
				@tape.right
			end
		end
	end
	
	def result
		return @tape.to_s
	end
end

unless ARGV.size >= 1
	puts "Usage:  turing.rb TURING_MACHINE_CODE_FILE [ INITIAL_TAPE ]"
	exit
end

machine = TuringMachine.new *ARGV
machine.run
puts machine.result