# Fwd: Please Forward: Ruby Quiz Submission

**URL:** <https://www.ruby-forum.com/t/fwd-please-forward-ruby-quiz-submission/104298>\
**Category:** Ruby\
**Created:** [July 30, 2006, 9:00pm UTC](https://www.ruby-forum.com/t/fwd-please-forward-ruby-quiz-submission/104298 "2006-07-30T21:00:36Z")\
**Posts on this page:** 2\
**Page:** 1

<div class="post-metadata">

**Author:** ![bbazzarrakk](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/b/47e85d/32.png) [@bbazzarrakk](https://www.ruby-forum.com/u/bbazzarrakk)\
**Post date:** [July 30, 2006, 9:00pm UTC](https://www.ruby-forum.com/t/fwd-please-forward-ruby-quiz-submission/104298/1 "2006-07-30T21:00:36Z")

</div>

Begin forwarded message:

---

<div class="post-metadata">

**Author:** ![bbazzarrakk](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/b/47e85d/32.png) [@bbazzarrakk](https://www.ruby-forum.com/u/bbazzarrakk)\
**Post date:** [July 31, 2006, 1:58pm UTC](https://www.ruby-forum.com/t/fwd-please-forward-ruby-quiz-submission/104298/2 "2006-07-31T13:58:53Z")

</div>

> # Here’s my entry for the Chip8 quiz question - I expect to be far
> 
> # away from net access when the time limit expires. I implemented

Well who knew they’d have easily accessible wireless within spitting  
distance of Rocky Mountain National Park?

Here’s my solution again, but this time without \> marks that prevent  
people from trying it, and hopefully without mangled lines:

* * *

#! /usr/bin/env ruby

# Here’s my entry for the Chip8 quiz question - I expect to be far

# away from net access when the time limit expires. I implemented

# a few of the operations not in the quiz because they were very

# easy to add, and I thought that they would be useful in writing

# some of my own Chip-8 programs, but I ran out of time before vacation

# and so never wrote my Chip-8 division program. Doing a full simulator

# of Chip-8 with ASCII-art graphics sounds a bit interesting, and I

# might do it at some point, depending on my desire for serious retro

# computing.

# 

# My program runs the file given as the first argument, or, if given

# no arguments runs the test program from the quiz. The second and

# subsequent arguments should be of the form =, with

# both and written in hex.

# 

# Only the registers whose values are changed (including those

initialized

# from the command line) are dumped when the program exits.

class Chip8  
def initialize(memblock)  
@ip = 0  
@memblock = memblock  
@registers = Array.new(16){nil}  
end

# These are the pieces of the current operation

def op; (@memblock[@ip]||0)/16; end  
def x; (@memblock[@ip]||0)%16; end  
def y; (@memblock[@ip+1]||0)/16; end  
def k; (@memblock[@ip+1]||0); end  
def n; 256\*x + k; end  
def op2;(@memblock[@ip+1]||0)%16; end

# Some convenient accessor functions

def ; @registers[r]; end  
def []=(r,v); @registers[r]=v; end  
def vx; self[x]; end  
def vy; self[y]; end

# Used to implement both addition and subtraction

def add(a,b)  
ret1 = a + b  
ret = ret1 & 0xff  
self[0xF] = (ret1!=ret)?1:0  
ret  
end

def do\_instruction  
case op  
when 0  
return false if [x,k] == [0,0]  
raise “bad/unknown opcode #{@memblock[@ip,2].unpack(‘H4’)}”  
when 1; @ip=n; return true  
when 3; @ip += 2 if vx == k  
when 4; @ip += 2 if vx != k  
when 5; @ip += 2 if vx == vy  
when 6; self[x] = k  
when 7; self[x] = add(vx,k)  
when 8  
case op2  
when 0; self[x] = vy  
when 1; self[x] |= vy  
when 2; self[x] &= vy  
when 3; self[x] ^= vy  
when 4; self[x] = add(vx,vy)  
when 5; self[x] = add(vx,256-vy)  
when 7; self[x] = add(256-vx,vy)  
when 6; self[0xF] = vx & 1; self[x] \>\>= 1  
when 0xE; self[0xF] = vx \>\> 7; self[x] \<\<= 1  
else  
raise “bad opcode #{@memblock[@ip,2].unpack(‘H4’)}”  
end  
when 12; self[x] = k & rand(256)  
else  
raise “bad opcode #{@memblock[@ip,2].unpack(‘H4’)}”  
end  
@ip += 2  
return true  
end

def run  
1 while do\_instruction  
end

def dump  
contents = @registers.map {|a| a ? [a].pack(‘C’).unpack(“B8”) : nil}  
@registers.each\_index { |i|  
printf(“V%X:%s (%d)\n”,i,contents[i],@registers[i]) if contents[i]  
}  
end

def Chip8.run(memblock, init={})  
a = Chip8.new(memblock)  
init.each{|h,k| a[h] = k}  
a.run  
a.dump  
end  
end

if **FILE** == $0  
if ARGV.empty?  
# test program from the quiz spec  
Chip8.run(%w{ 61 77 62 45 71 01 83 20 81 21 81 22  
82 33 81 34 82 35 81 06 83 27 83 0e 64 ff c4 11  
32 bb 10 00 00 00 }.map{|b| [b].pack(“H2”)}.join)  
else  
init = {}  
buff = “”  
if ARGV[1] and ARGV[1] =~ /^\d+$/  
buff = “\0” \* ARGV[1].to\_i  
end  
File.open(ARGV[0], “rb”) {|f| buff += f.read}  
ARGV[1…-1].each {|s| r,v = s.split(/=/); init[r.hex]=v.hex}  
Chip8.run(buff, init)  
end  
end

**END**
