Rails developer by day, snowboard ski patroller by powder days

Lets talk Ruby and Ruby warrior. I love this gem. Its fun to challenge myself to beat the game in epic mode while writing some ruby code challenging myself to complete not just the game but to do it with some of my style. Github: Ruby Warrior So to start I wrote code that got…

Written by

×

Rubies Warrior Way, part:1

Lets talk Ruby and Ruby warrior. I love this gem. Its fun to challenge myself to beat the game in epic mode while writing some ruby code challenging myself to complete not just the game but to do it with some of my style.

Github: Ruby Warrior

So to start I wrote code that got me all the way through then passed the Epic level I.E. code ran start to finish from level 1 – 9; Since then its been lets optimize the code and see if we cannot beat the score for epic.

Not a large score but a 488 with a grade of B is not too bad.

My player class wants to leverage Ruby and so I put code into separate classes depending on need.

Current player.rb class. Note: loading the additional files as well as pry which I constantly use to debug.

require 'pry'
load 'warrior_recon.rb'
load 'warrior_turn.rb'
load 'threat_check.rb'

class Player

attr_reader :warrior, :recon, :turn_end_health, :stashed_recon

def play_turn(warrior)
@warrior = warrior
warrior_turn = WarriorTurn.new(warrior, @turn_end_health, @stashed_recon)
warrior_turn.next_turn
@turn_end_health = warrior.health
@stashed_recon = warrior_turn.current_recon
puts "This is the player health at end of turn #{turn_end_health}"
end

end

Still in the process of refactoring so some of the classes still need cleaning up.

Recon class (warrior_recon.rb). Reconnaissance done for the warrior. This is a passive skill I.E. it does not count as a turn; leveraging this as much as possible to streamline the turn seems like a good idea.

# frozen_string_literal: true
# Class will do reconnaissance for warrior
# Stash will add current recon to stashed recon
class WarriorRecon
attr_reader :warrior

def initialize(warrior)
@warrior = warrior
end

def stash_additions(recon_result, new_recon)
recon_result = {} if recon_result.nil?
recon_result.merge(new_recon)
end

def warrior_direction(position)
space = warrior.look(:forward).first
front_location = space.location.first
return :west if front_location > position

:east
end

def reconnaissance
eval_look(warrior.look(:forward)).merge(eval_look(warrior.look(:backward)))
end

def warrior_position
front_space = warrior.look(:forward).first.location
back_space = warrior.look(:backward).first.location

front_space.zip(back_space).map { |front, back| (front + back) / 2 }
end

def eval_look(look)
look.each_with_object({}) do |item, recon_result|
next if item.location.first < -1
location = item.location.first
recon_result[location] =
if item.captive?
{ name: 'captive' }
elsif item.wall?
{ name: location == -1 ? 'east_wall' : 'west_wall' }
elsif item.unit
{ name: item.unit.name }
elsif item.stairs?
{ name: 'stairs' }
else
{ name: 'space' }
end
end
end
end

Threat Check class (threat_check.rb) works with the recon class.

# frozen_string_literal: true

require 'pry'
# Class looks for threats about to happen to warrior
class ThreatCheck
attr_reader :warrior, :recon, :turn_end_health

ENEMIES = {
'Sludge' => { health: 12, power: 3 },
'Archer' => { health: 7, power: 3 },
'Thick Sludge' => { health: 24, power: 3 },
'Wizard' => { health: 3, power: 11 }
}.freeze

LONG_DISTANCE_ENEMIES = %w[Archer Wizard 'Thick Sludge'].freeze
STAIRS = %w[stairs].freeze
WALLS = %w[east_wall west_wall].freeze
CAPTIVE = 'captive'.freeze

def initialize(recon_team, recon)
@recon = recon
@warrior_position = recon_team.warrior_position.first
@warrior_direction = recon_team.warrior_direction(@warrior_position)
end

def health_needs_replenish?(health)
return false unless enemy_on_next_space?

enemy = recon[@warrior_position + 2]
return false unless enemy

enemy_stats = ENEMIES[enemy[:name]]
(enemy_stats[:health] / 5) >= (health / enemy_stats[:power])
end

def threat_in_front?
enemy_in_locations?(@warrior_position + 1, @warrior_position + 1)
end

def threat_from_behind?
enemy_in_locations?(@warrior_position - 2, @warrior_position)
end

def long_range_threat?
enemy_in_locations?(@warrior_position - 2, @warrior_position + 2)
end

def enemy_on_next_space?
enemy_in_locations?(@warrior_position + 2, @warrior_position + 2)
end

def enemy_in_locations?(local1, local2)
recon.any? do |pos, space|
pos.between?(local1, local2) && ENEMIES.key?(space[:name])
end
end

def captive_in_front?
enemy_space = recon[@warrior_position + 1]
enemy_space[:name] == CAPTIVE
end

def long_distance_enemy?
enemy_space = recon[@warrior_position + 2]
enemy_space && LONG_DISTANCE_ENEMIES.include?(enemy_space[:name])
end

def long_distance_attack?
return false if recon.empty?

recon.any? do |pos, space|
LONG_DISTANCE_ENEMIES.include?(space[:name]) && [@warrior_position + 1, @warrior_position + 2].include?(pos)
end
end
end

Warrior turn class. (warrior_turn.rb)

class WarriorTurn
attr_reader :warrior, :recon_team, :turn_end_health, :recon, :threatened,
:check, :current_recon

def initialize(warrior, turn_end_health, stashed_recon)
@warrior = warrior
@recon_team = WarriorRecon.new(warrior)
@current_recon = recon_team.stash_additions(stashed_recon, recon_team.reconnaissance)
@check = ThreatCheck.new(@recon_team, @current_recon)
@turn_end_health = turn_end_health
end

def walking
puts 'Warrior walks forward'
warrior.walk!
end

def walking_backward
puts 'Walking backward, likely a need to refresh health'
warrior.walk!(:backward)
end

def shoot
warrior.shoot!
end

def attack
warrior.attack!
end

def release
warrior.rescue!
end

def rest
puts 'Player is resting until max health reached'
warrior.rest!
end

def pivot
warrior.pivot!
end

def handle_ranged_threat
return shoot if check.long_distance_enemy?
pivot
end

def next_turn
return attack if check.threat_in_front?
return pivot if check.threat_from_behind?
return rest if check.health_needs_replenish?(warrior.health)
# return shoot if check.long_distance_attack?
return release if check.captive_in_front?
walking
end

end

Currently my code will only make it to level 6 then break.

Level 6 setup:

The fix is going to be rescue the captive then account for the two(2) archers in a row that have to be dealt with. Health needs replenish works well to get the S rating(highest score possible) but is having issues with the multiple archers after the thick sludge attack.

Next update coming soon.

Leave a comment