--Apple-Mail-3-871338967
Content-Transfer-Encoding: 7bit
Content-Type: text/plain;
	charset=US-ASCII;
	delsp=yes;
	format=flowed

Begin forwarded message:

> From: Benjohn Barnes <benjohn / fysh.org>
> Date: May 28, 2006 6:30:23 AM CDT
> To: Gray II <james / grayproductions.net>
> Subject: Quiz submission
>
> Hi James,
>
> I hope you don't mind if I send you my entry for this weeks quiz  
> before the end of the spoiler period. I'm not going to be in net  
> contact after the period ends, or have my laptop on me either.  
> Would you please forward it to the list at the appointed time?
>
> Thanks very much for all your work on the quiz, and sorry for any  
> inconvenience. This weeks has been a really inspiring :) I'm sure I  
> can feel my brain beating just a little faster now.
>
> Cheers,
> 	Benjohn
>
>
>

--Apple-Mail-3-871338967
Content-Transfer-Encoding: 7bit
Content-Type: text/x-ruby-script;
	x-unix-mode=0644;
	name="tc_arena.rb"
Content-Disposition: attachment;
	filename=tc_arena.rb


require 'test/unit'
require 'arena'

class TestArena < Test::Unit::TestCase
  def test_default
    arena = Arena.new
    assert_equal('#', arena[0,0])
    assert_equal('#', arena[100,100])
  end
  
  def test_can_use_negatives
    arena = Arena.new
    assert_equal('#', arena[-10,-10])
    assert_equal('#', arena[-10,10])
    assert_equal('#', arena[10,-10])
  end 
  
  def test_can_set
    arena = Arena.new
    arena[0,0] = '1'
    assert_equal('1', arena[0,0])
  end
  
  def test_barfs_about_bad_coords
    assert_raise(ArgumentError) {(Arena.new)[123,123,123]}
    assert_raise(ArgumentError) {(Arena.new)[123]}
  end

  def test_extents
    arena = Arena.new
    arena[-3,0] = '.'
    arena[4,0] = '.'
    arena[0,-5] = '.'
    arena[0,6] = '.'
    
    assert_equal(-3, arena.left)
    assert_equal(4, arena.right)
    assert_equal(-5, arena.top)
    assert_equal(6, arena.bottom)
  end

  def test_to_array
    arena = Arena.new
    arena[0,0] = '.'
    assert_equal([%w{# # #}, %w{# . #}, %w{# # #}], arena.to_array)
  end

  def test_to_s
    arena = Arena.new
    arena[0,0] = '.'
    assert_equal("###\n#.#\n###", arena.to_s)
  end
end


--Apple-Mail-3-871338967
Content-Transfer-Encoding: 7bit
Content-Type: text/x-ruby-script;
	x-unix-mode=0644;
	name="arena.rb"
Content-Disposition: attachment;
	filename=arena.rb


class Arena
  attr_reader :left, :right, :top, :bottom
  def initialize
    @arena = Hash.new {|h,k| h[k]=Hash.new('#')}
    @left = @right = @top = @bottom = 0
  end
  
  def [](x,y)
    @arena[y][x]
  end

  def []=(x,y,v)
    # I originally worked out the width and height at the end by scanning the map.
    # I was also using a single map, rather than the 'map in a map' now used. I
    # found that dungeon creation  was slow, but almost all of it was the final
    # rendering stage, so switched over to the current approach.
    @arena[y][x]=v
    @left = [@left, x].min
    @right = [@right, x].max
    @top = [@top, y].min
    @bottom = [@bottom, y].max
  end

  def to_s
    to_array.collect {|row| row.join}.join("\n")
  end

  def to_array
    (top-1..bottom+1).collect do |y|
      (left-1..right+1).collect do |x|
        self[x,y]
      end
    end
  end
end
--Apple-Mail-3-871338967
Content-Transfer-Encoding: 7bit
Content-Type: text/plain;
	charset=US-ASCII;
	format=flowed

>

--Apple-Mail-3-871338967
Content-Transfer-Encoding: 7bit
Content-Type: text/x-ruby-script;
	x-unix-mode=0644;
	name="tc_walker.rb"
Content-Disposition: attachment;
	filename=tc_walker.rb


require 'test/unit'
require 'walker'

class TestDungeonWalker < Test::Unit::TestCase
  def test_direction
    walker = Walker.new(0,0,0)
    walker.direction = 1.1
    walker.walk
    assert_equal([0,1], walker.position)
  end

  def test_walk
    walker = Walker.new(0,0,0)
    assert_equal([1,0], walker.walk(0.1).position)
    assert_equal([1,1], walker.walk(1.1).position)
    assert_equal([0,1], walker.walk(1.8).position)
    assert_equal([0,0], walker.walk(3.1).position)
    assert_equal([0,-1], walker.walk(-1.1).position)
  end

  def test_wonder
    walker_before = Walker.new
    walker_after = walker_before.dup.wonder
    assert_not_equal( walker_before.position, walker_after.position )
  end
end


--Apple-Mail-3-871338967
Content-Transfer-Encoding: 7bit
Content-Type: text/x-ruby-script;
	x-unix-mode=0644;
	name="walker.rb"
Content-Disposition: attachment;
	filename=walker.rb


# This class basically implements a random walk. I remember
# my direction, and it's this that I randomly adjust, rather
# than simply jittering my position.
class Walker
  attr_accessor :x, :y, :direction
  
  def initialize(x=0, y=0, direction=0)
    @x, @y, @direction = x, y, direction
  end

  # Handy for testing.
  def position
    [x,y]
  end
  
  # Adjust direction, and walk once.
  def wonder
    perturb_direction
    walk
  end

  # Make the child pointing of 90 degrees away from me.
  def create_child
    Walker.new(x, y, direction + 2*rand(2) - 1)
  end

  def perturb_direction
    @direction += rand*wiggle_max - (wiggle_max/2)
  end
  
  def walk(d = direction_with_smoothing_fuzz)
    # Ensure that the direction is correctly wrapped around.
    d = (d.round)%4
    @x += [1,0,-1,0][d]
    @y += [0,1,0,-1][d]
    self
  end
  
  # Adding some noise on to the direction "stocastically" samples
  # it, smoothing off turns, and making it more catacombey.
  def direction_with_smoothing_fuzz
    @direction + rand*smoothing - smoothing/2
  end

  # How wiggley are the dungeons? Bigger numbers are more wiggly
  # and compact.
  def wiggle_max
    0.5
  end
  
  # How smooth are tunnels? Larger numbers give smoother more
  # 'catacombe' like tunnels (and smaller dungeons). Smaller
  # numbers give more cartesian & straight tunnels.
  def smoothing
    0.9
  end

end


--Apple-Mail-3-871338967
Content-Transfer-Encoding: 7bit
Content-Type: text/plain;
	charset=US-ASCII;
	format=flowed

>

--Apple-Mail-3-871338967
Content-Transfer-Encoding: 7bit
Content-Type: text/x-ruby-script;
	x-unix-mode=0644;
	name="dungeon.rb"
Content-Disposition: attachment;
	filename=dungeon.rb

require 'walker.rb'
require 'arena.rb'

def create_dungeon( arena, walk_length, have_stairs = true, walker = Walker.new )
  while(walk_length>0)
    walk_length -=1
    
    # Cut out a bit of tunnel where I am.
    arena[*walker.position] = ' '
    walker.wonder

    # Bosh down a room ocaissionally.
    if(walk_length%80==0)
      create_room(arena, walker)
    end

    # Spawn off a child now and then. Split the remaining walk_length with it.
    # Only one of us gets the stairs though.
    if(walk_length%40==0)
      child_walk_length = rand(walk_length)
      walk_length -= child_walk_length
      if child_walk_length > walk_length
        create_dungeon(arena, child_walk_length, have_stairs, walker.create_child)
        have_stairs = false
      else
        create_dungeon(arena, child_walk_length, false, walker.create_child)
      end
    end
  end

  # Put in the down stairs, if I have them.
  if(have_stairs)
    arena[*(walker.position)] = '>'
  end
end

def create_room(arena, walker)
  max = 10
  width = -rand(max)..rand(max)
  height = -rand(max)..rand(max)
  height.each do |y|
    width.each do |x|
      arena[x+walker.x, y+walker.y] = ' '
    end
  end
end

# Create an arena, and set of a walker in it.
arena = Arena.new
create_dungeon(arena, 400)

# Put in the up stairs.
arena[0,0] = '<'

# Show the dungeon.
puts arena


--Apple-Mail-3-871338967
Content-Transfer-Encoding: 7bit
Content-Type: text/plain;
	charset=US-ASCII;
	format=flowed

>


--Apple-Mail-3-871338967--