Skip to content

Commit

Permalink
Massive patch. This is an example of how not to do revision control
Browse files Browse the repository at this point in the history
  • Loading branch information
practicingruby committed Mar 11, 2011
1 parent 2c02a37 commit afa4970
Show file tree
Hide file tree
Showing 22 changed files with 274 additions and 30 deletions.
8 changes: 8 additions & 0 deletions TODO
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
- IvoryTower::Map is poorly tested.
- IvoryTower::Map has several opportunities for refactoring.
- Most tiles are only lightly tested.
- Text based UI is horrible
- IvoryTower::Monsters::BlindMouse completely untested
- IvoryTower::Towers::ArrowTower limited testing
- Many missing features and validations in core engine

36 changes: 30 additions & 6 deletions example/map_to_text.rb
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,35 @@
file = "#{File.dirname(__FILE__)}/../data/maps/simple.txt"
map = IvoryTower::Map.from_file(file, base_health: 9)

map[3,3].occupants << Object.new
map[3,3].occupants << Object.new
map[3,3].occupants << Object.new
current_tick = 0

#require "pp"
#pp map
loop do
puts "Tick: #{current_tick}"

if current_tick % 3 == 0
map.rally_points["A"] << IvoryTower::Monsters::BlindMouse.new(map)
end


if current_tick % 20 == 0
random_forest = map.forests.sample
unless random_forest.tower
random_forest.build_tower(IvoryTower::Towers::ArrowTower.new(map))
end
end

map.towers.each do |t|
t.fire(tick: current_tick)
end

map.each do |tile|
if tile.occupied?
tile.occupants.each { |o| o.move(tick: current_tick) }
end
end

current_tick += 1
puts IvoryTower::Map::TextFormatter.new(map)
sleep 0.25
end

puts IvoryTower::Map::TextFormatter.new(map)
5 changes: 5 additions & 0 deletions lib/ivory_tower.rb
Original file line number Diff line number Diff line change
@@ -1,4 +1,9 @@
require "mocha"

require_relative "ivory_tower/errors"
require_relative "ivory_tower/allowed_units"
require_relative "ivory_tower/tile"
require_relative "ivory_tower/map"
require_relative "ivory_tower/towers"
require_relative "ivory_tower/monsters"

7 changes: 7 additions & 0 deletions lib/ivory_tower/allowed_units.rb
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,13 @@ def self.included(base)
base.extend(ClassMethods)
end

def <<(monster)
monster.location = location
occupants << monster

self
end

def occupants
@occupants ||= []
end
Expand Down
44 changes: 37 additions & 7 deletions lib/ivory_tower/map.rb
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ def from_file(file, params)
# FIXME: Would love to remove the class based dependency here
# also, bit of a god method here...
def from_string(string, params)
attributes = { base: nil, rally_points: [], forests: [] }
attributes = { base: nil, rally_points: {}, forests: [] }

data = string.lines.map.with_index do |line, row_number|
line.chomp.chars.map.with_index do |symbol, col_number|
Expand All @@ -23,7 +23,7 @@ def from_string(string, params)
attributes[:base] = tile_class.new(params[:base_health])
when tile_class == IvoryTower::Tile::RallyPoint
rally_point = tile_class.new(symbol)
attributes[:rally_points] << rally_point
attributes[:rally_points][symbol] = rally_point

rally_point
when tile_class == IvoryTower::Tile::Forest
Expand All @@ -35,7 +35,6 @@ def from_string(string, params)
tile_class.new
end

tile_object.extend(MappableTile)
tile_object.map_symbol = symbol
tile_object.location = [row_number, col_number]

Expand Down Expand Up @@ -63,10 +62,6 @@ def tile_class_by_symbol(symbol)
private :new, :tile_class_by_symbol
end

module MappableTile
attr_accessor :map_symbol, :location
end

def initialize(params)
@tiles = params[:tiles]
@base = params[:base]
Expand All @@ -79,6 +74,41 @@ def initialize(params)
def [](row,col)
@tiles[row][col]
end

def rows
@tiles
end

# Costly, how might we do it better?
def columns
@tiles_by_columns ||= @tiles.transpose
end

def towers
forests.map { |e| e.tower }.compact
end

def neighbors_of(position, params)
current_row, current_col = position

delta = params[:distance]

min_row = [current_row - delta, 0].max
max_row = [current_row + delta, rows.count - 1].min

min_col = [current_col - delta, 0].max
max_col = [current_col + delta, columns.count - 1].min

neighbors = []

(min_row..max_row).each do |row|
(min_col..max_col).each do |col|
neighbors << self[row,col] unless [row,col] == position
end
end

return neighbors
end

def each
@tiles.flatten.each { |t| yield(t) }
Expand Down
6 changes: 6 additions & 0 deletions lib/ivory_tower/map/text_formatter.rb
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,12 @@ def to_s
case tile
when Tile::Base
"#{tile.map_symbol}[#{tile.health}]"
when Tile::Forest
if tile.tower
"&(#{tile.occupants.count})"
else
"#{tile.map_symbol}(#{tile.occupants.count})"
end
else
"#{tile.map_symbol}(#{tile.occupants.count})"
end
Expand Down
1 change: 1 addition & 0 deletions lib/ivory_tower/monsters.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
require_relative "monsters/blind_mouse"
42 changes: 42 additions & 0 deletions lib/ivory_tower/monsters/blind_mouse.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
module IvoryTower
module Monsters
class BlindMouse
MOVE_FREQUENCY = 2

def initialize(map)
@map = map
@health = 5
end

attr_reader :map
attr_accessor :location, :health

def defend_against(tower)
self.health = [0, health - tower.weapon_power].max

die if health == 0
end

def move_on_tick?(tick)
(tick % MOVE_FREQUENCY) == 0
end

def move(params)
return unless move_on_tick?(params[:tick])

remove_from_current_tile

neighbors = map.neighbors_of(location, distance: 1)
next_tile = neighbors.select { |e| e.allows?(:ground_units) }.sample

map[*next_tile.location] << self
end

def remove_from_current_tile
@map[*location].occupants.delete(self)
end

alias_method :die, :remove_from_current_tile
end
end
end
11 changes: 10 additions & 1 deletion lib/ivory_tower/tile/base.rb
Original file line number Diff line number Diff line change
Expand Up @@ -9,15 +9,24 @@ def initialize(health)
@health = health
end

attr_accessor :health
attr_accessor :health, :map_symbol, :location

def <<(monster)
@health -= 1
monster.die
end

def destroyed?
@health == 0
end

def occupied?
false
end

def occupants
raise NotImplementError, "Base cannot have occupants"
end
end
end
end
6 changes: 4 additions & 2 deletions lib/ivory_tower/tile/forest.rb
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,16 @@ module IvoryTower
module Tile
class Forest
include AllowedUnits
allows :ground_units, :air_units, :towers
allows :air_units, :towers

attr_reader :tower
attr_reader :tower
attr_accessor :map_symbol, :location

def build_tower(new_tower)
raise Errors::TowerPresent if tower

@tower = new_tower
@tower.location = location
end

def destroy_tower
Expand Down
1 change: 1 addition & 0 deletions lib/ivory_tower/tile/meadow.rb
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ module Tile
class Meadow
include AllowedUnits
allows :ground_units, :air_units
attr_accessor :map_symbol, :location
end
end
end
1 change: 1 addition & 0 deletions lib/ivory_tower/tile/mountain.rb
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ module Tile
class Mountain
include AllowedUnits
allows :air_units
attr_accessor :map_symbol, :location
end
end
end
9 changes: 2 additions & 7 deletions lib/ivory_tower/tile/rally_point.rb
Original file line number Diff line number Diff line change
Expand Up @@ -8,13 +8,8 @@ def initialize(name)
@name = name
end

attr_reader :name

def <<(monster)
occupants << monster

self
end
attr_reader :name
attr_accessor :map_symbol, :location

def delete(monster)
occupants.delete(monster)
Expand Down
1 change: 1 addition & 0 deletions lib/ivory_tower/tile/sea.rb
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ module Tile
class Sea
include AllowedUnits
allows :sea_units
attr_accessor :map_symbol, :location
end
end
end
1 change: 1 addition & 0 deletions lib/ivory_tower/towers.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
require_relative "towers/arrow_tower"
44 changes: 44 additions & 0 deletions lib/ivory_tower/towers/arrow_tower.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
module IvoryTower
module Towers
class ArrowTower
FIRE_FREQUENCY = 3
WEAPON_POWER = 1

def initialize(map)
@map = map
end

attr_reader :map
attr_accessor :location

def fire(params)
return unless fire_on_tick?(params[:tick])

monster = target_monster
return unless monster

monster.defend_against(self)
end

def fire_on_tick?(tick)
(tick % FIRE_FREQUENCY) == 0
end

def weapon_power
WEAPON_POWER
end

def target_monster
tile = target_tile
return unless tile

tile.occupants.sample
end

def target_tile
neighbors = map.neighbors_of(location, distance: 1)
neighbors.find { |t| t.occupied? }
end
end
end
end
2 changes: 1 addition & 1 deletion test/map_test.rb
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@
assert 4, map.forests.count
assert 1, map.rally_points.count

assert "A", map.rally_points.first.name
assert "A", map.rally_points["A"].name
end

test "#from_file" do
Expand Down
1 change: 1 addition & 0 deletions test/suite.rb
Original file line number Diff line number Diff line change
Expand Up @@ -4,3 +4,4 @@
require_relative "tile/mountain_test"
require_relative "tile/forest_test"
require_relative "tile/sea_test"
require_relative "towers/arrow_tower_test"
2 changes: 1 addition & 1 deletion test/tile/base_test.rb
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,6 @@

# hack to replace later
def new_monster
Object.new
mock(:die => nil)
end
end
7 changes: 3 additions & 4 deletions test/tile/forest_test.rb
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,10 @@
refute forest.occupied?
end

test "should allow air and ground units" do
test "should allow air units" do
forest = IvoryTower::Tile.forest

assert_allows_units(forest, :air_units, :ground_units)
assert_allows_units(forest, :air_units)
end

test "should allow towers" do
Expand Down Expand Up @@ -63,8 +63,7 @@
end
end

# hack, to be removed later
def new_tower
Object.new
stub(:location= => nil)
end
end
2 changes: 1 addition & 1 deletion test/tile/rally_point_test.rb
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,6 @@

# hack to be replaced later
def new_monster
Object.new
mock(:location= => nil)
end
end
Loading

0 comments on commit afa4970

Please sign in to comment.