patternrubyMinor
Communication between two classes in ruby
Viewed 0 times
communicationtwobetweenclassesruby
Problem
I cannot understand how I can make two classes work together by passing variables between them.
During the last 5 days, I learned the basics of inheritance, singleton methods and eval methods. I even read about template methods, but since I have no programming background, I'm in no position to learn from other languages.
The only aim here is to learn how to make use of classes. The whole game is an exercise.
The game has 5 classes:
The
I have to admit that I had a hard time to understand how to pass variables to/between methods in ruby, and this curse is following me in the classes, too.
So, as a last thing, you can see the horrible code in the choices method in
During the last 5 days, I learned the basics of inheritance, singleton methods and eval methods. I even read about template methods, but since I have no programming background, I'm in no position to learn from other languages.
The only aim here is to learn how to make use of classes. The whole game is an exercise.
The game has 5 classes:
Game, Creature, Weapon, Armor, Scene.Creature class is used to produce the hero and several monsters (currently only a dragon is created).Weapon and Armor classes (with only name and power attributes) are there to produce equipment and while they may be joined as a single Equipment class with name, defense and attack attributes, currently this is not my concern.Scene class is there to produce several places/rooms, which is the main point of the exercise. The exercise clearly states "Use one class per room and give the classes names that fit their purpose." Therefore I made a class containing name, history and armor/weapon and monster attributes. The reason for name and history are clearly to be able to give an introduction when the player enters the scene.The
armor/weapon and monster attributes are required to make the player to encounter different armors, weapons to equip and different monsters to fight in different scenes. I tried to pass them as variables (arrays) to the scene class during initialize but couldn't succeed. The roots of this failure probably is the reason why I can't make the two classes work together.I have to admit that I had a hard time to understand how to pass variables to/between methods in ruby, and this curse is following me in the classes, too.
So, as a last thing, you can see the horrible code in the choices method in
Scene class. I cannot exactly explain what I was thinking while coding this. But the only good thing I have done is adding self to the @city = Scene.newSolution
The problem is more about the organization of the game. Normally you would not want to have two classes tightly coupled to each other.
Also location of some methods are not correct. For example battle method in Creature should not be there. Or you should not need two parameters for that method.
You are suffering from the responsibilities of objects at the moment. I would suggest to rethink this.
For example you can decide that "Battle" is not something creature is responsible but game.
I came up with this code which also requires much refactoring. I tried not to change your code too much.
Also location of some methods are not correct. For example battle method in Creature should not be there. Or you should not need two parameters for that method.
You are suffering from the responsibilities of objects at the moment. I would suggest to rethink this.
For example you can decide that "Battle" is not something creature is responsible but game.
I came up with this code which also requires much refactoring. I tried not to change your code too much.
#game.rb
class World
attr_accessor :armor_list, :weapon_list, :monsters, :scenes
def initialize()
@weapon_list = {
short: {name: "Short sword", power: 5 },
long: {name: "Long sword", power: 8 },
two_handed: {name: "Two-Handed sword", power: 12 },
warhammer: {name: "Warhammer sword", power: 10 }
}
@armor_list = {
leather: {name: "Leather Armor", power: 5 },
chain: {name: "Chain Mail", power: 10 },
plate: {name: "Plate Mail", power: 15 },
elven: {name: "Elven Chain Mail", power: 50 }
}
@monsters = {
rat: {name: "Rat", level: 1 },
thief: {name: "Thief", level: 50 },
dragon: {name: "Dragon", level: 12 }
}
@scenes = [
{ name: "City", history: "The city.", weapons: [@weapon_list[:long]], armors: [@armor_list[:chain]], monsters: [@monsters[:thief], @monsters[:rat]] },
{ name: "Mountain", history: "The mountain.", weapons: [@weapon_list[:warhammer]], armors: [@armor_list[:chain]], monsters: [@monsters[:dragon]] }
]
end
end
class Game
def initialize
@player = Creature.new name: "You", level: 5
@world = World.new
end
def play
@current_scene = Scene.new(@world.scenes.first)
@current_scene.intro
while @player.is_alive?
self.show_choices
end
end
def show_choices
puts nil, :weapon => nil}
@armor = 0
@weapon = 0
#3.times rand(7) or 3*rand(7) doesn't create the effect, I tried rand(16)+3 but didn't like it.
@strength = rand(7) + rand(7) + rand(7)
@condition = rand(7) + rand(7) + rand(7)
@life = @level * (rand(8) + 1)
@power = @strength * (rand(4) + 1)
@regen = @condition
end
def introduce_self()
puts "You wear " + (@equipment[:armor] || "no armor!")
puts "You carry " + (@equipment[:weapon] || "no no weapon!")
end
def wear_armor(armor)
@armor = armor.power
@equipment[:armor] = armor.name
end
def wear_weapon(weapon)
@weapon = weapon.power
@equipment[:weapon] = weapon.name
end
def attack(defender)
[@power + @weapon - defender.armor, 0].max
end
def defend(attack)
@life -= attack
end
def regen
@life += @regen
@regen
end
def is_alive?
@life > 0
end
end
class Weapon
attr_reader :name, :power
def initialize(setup)
@name = setup[:name]
@power = setup[:power] end
end
class Armor
attr_reader :name, :power
def initialize(setup)
@name = setup[:name]
@power = setup[:power]
end
end
game = Game.new()
game.play()Code Snippets
#game.rb
class World
attr_accessor :armor_list, :weapon_list, :monsters, :scenes
def initialize()
@weapon_list = {
short: {name: "Short sword", power: 5 },
long: {name: "Long sword", power: 8 },
two_handed: {name: "Two-Handed sword", power: 12 },
warhammer: {name: "Warhammer sword", power: 10 }
}
@armor_list = {
leather: {name: "Leather Armor", power: 5 },
chain: {name: "Chain Mail", power: 10 },
plate: {name: "Plate Mail", power: 15 },
elven: {name: "Elven Chain Mail", power: 50 }
}
@monsters = {
rat: {name: "Rat", level: 1 },
thief: {name: "Thief", level: 50 },
dragon: {name: "Dragon", level: 12 }
}
@scenes = [
{ name: "City", history: "The city.", weapons: [@weapon_list[:long]], armors: [@armor_list[:chain]], monsters: [@monsters[:thief], @monsters[:rat]] },
{ name: "Mountain", history: "The mountain.", weapons: [@weapon_list[:warhammer]], armors: [@armor_list[:chain]], monsters: [@monsters[:dragon]] }
]
end
end
class Game
def initialize
@player = Creature.new name: "You", level: 5
@world = World.new
end
def play
@current_scene = Scene.new(@world.scenes.first)
@current_scene.intro
while @player.is_alive?
self.show_choices
end
end
def show_choices
puts <<-CHOICES
What would you like to do here?
1. Look for armor
2. Look for weapons
3. Look for monsters to fight
4. Go to another place!
CHOICES
choice = gets.chomp
case choice
when "1"
self.look_for_armor
when "2"
self.look_for_weapons
when "3"
self.look_for_monsters
when "4"
puts "bad choice, since I am not ready yet!"
else
puts "Can't you read?"
exit
end
end
def look_for_monsters
monster = @current_scene.monsters.first
battle [@player, monster]
end
def look_for_armor
armor = select_equipment @current_scene.armors
return if armor.nil?
@player.wear_armor(@current_scene.armor_picked(armor))
end
def look_for_weapons
weapon = select_equipment @current_scene.weapons
return if weapon.nil?
@player.wear_weapon(@current_scene.weapon_picked(weapon))
end
def select_equipment(equipment)
@player.introduce_self
puts "You wanna some equipment?"
equipment.each_with_index do |item, i|
puts "#{i+1}. #{item.name}"
end
gets.chomp.to_i - 1
end
def battle(opponents)
attack_turn = 0
while opponents.all?(&:is_alive?)
attacker = opponents[attack_turn]
defender = opponents[(attack_turn + 1) % 2]
attack = attacker.attack(defender)
defender.defend(attack)
puts "#{attacker.name} hit #{defender.name} with #{attack} points of damage!"
puts "#{defender.name} regenerates #{defender.regen} points of life!" if defenContext
StackExchange Code Review Q#10312, answer score: 3
Revisions (0)
No revisions yet.