rubywarrior-i18n 0.0.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (122) hide show
  1. data/CHANGELOG.rdoc +38 -0
  2. data/Gemfile +3 -0
  3. data/Gemfile.lock +44 -0
  4. data/LICENSE +20 -0
  5. data/README.md +199 -0
  6. data/Rakefile +17 -0
  7. data/bin/rubywarrior +5 -0
  8. data/features/command_options.feature +46 -0
  9. data/features/levels.feature +71 -0
  10. data/features/profiles.feature +56 -0
  11. data/features/step_definitions/common_steps.rb +19 -0
  12. data/features/step_definitions/interaction_steps.rb +65 -0
  13. data/features/support/env.rb +12 -0
  14. data/features/support/mockio.rb +57 -0
  15. data/features/towers.feature +14 -0
  16. data/i18n/en.yml +232 -0
  17. data/i18n/es.yml +233 -0
  18. data/lib/ruby_warrior.rb +53 -0
  19. data/lib/ruby_warrior/abilities/attack.rb +25 -0
  20. data/lib/ruby_warrior/abilities/base.rb +44 -0
  21. data/lib/ruby_warrior/abilities/bind.rb +20 -0
  22. data/lib/ruby_warrior/abilities/detonate.rb +34 -0
  23. data/lib/ruby_warrior/abilities/direction_of.rb +13 -0
  24. data/lib/ruby_warrior/abilities/direction_of_stairs.rb +13 -0
  25. data/lib/ruby_warrior/abilities/distance_of.rb +13 -0
  26. data/lib/ruby_warrior/abilities/explode.rb +28 -0
  27. data/lib/ruby_warrior/abilities/feel.rb +14 -0
  28. data/lib/ruby_warrior/abilities/form.rb +25 -0
  29. data/lib/ruby_warrior/abilities/health.rb +13 -0
  30. data/lib/ruby_warrior/abilities/listen.rb +15 -0
  31. data/lib/ruby_warrior/abilities/look.rb +16 -0
  32. data/lib/ruby_warrior/abilities/pivot.rb +17 -0
  33. data/lib/ruby_warrior/abilities/rescue.rb +24 -0
  34. data/lib/ruby_warrior/abilities/rest.rb +20 -0
  35. data/lib/ruby_warrior/abilities/shoot.rb +24 -0
  36. data/lib/ruby_warrior/abilities/walk.rb +21 -0
  37. data/lib/ruby_warrior/config.rb +22 -0
  38. data/lib/ruby_warrior/core_additions.rb +29 -0
  39. data/lib/ruby_warrior/floor.rb +71 -0
  40. data/lib/ruby_warrior/game.rb +209 -0
  41. data/lib/ruby_warrior/level.rb +123 -0
  42. data/lib/ruby_warrior/level_loader.rb +56 -0
  43. data/lib/ruby_warrior/player_generator.rb +41 -0
  44. data/lib/ruby_warrior/position.rb +82 -0
  45. data/lib/ruby_warrior/profile.rb +120 -0
  46. data/lib/ruby_warrior/runner.rb +34 -0
  47. data/lib/ruby_warrior/space.rb +71 -0
  48. data/lib/ruby_warrior/tower.rb +14 -0
  49. data/lib/ruby_warrior/turn.rb +38 -0
  50. data/lib/ruby_warrior/ui.rb +54 -0
  51. data/lib/ruby_warrior/units/archer.rb +34 -0
  52. data/lib/ruby_warrior/units/base.rb +100 -0
  53. data/lib/ruby_warrior/units/captive.rb +17 -0
  54. data/lib/ruby_warrior/units/golem.rb +20 -0
  55. data/lib/ruby_warrior/units/sludge.rb +30 -0
  56. data/lib/ruby_warrior/units/thick_sludge.rb +13 -0
  57. data/lib/ruby_warrior/units/warrior.rb +73 -0
  58. data/lib/ruby_warrior/units/wizard.rb +34 -0
  59. data/lib/ruby_warrior/version.rb +3 -0
  60. data/spec/fixtures/short-tower/level_001.rb +15 -0
  61. data/spec/fixtures/short-tower/level_002.rb +15 -0
  62. data/spec/fixtures/walking_player.rb +5 -0
  63. data/spec/ruby_warrior/abilities/attack_spec.rb +51 -0
  64. data/spec/ruby_warrior/abilities/base_spec.rb +38 -0
  65. data/spec/ruby_warrior/abilities/bind_spec.rb +19 -0
  66. data/spec/ruby_warrior/abilities/direction_of_spec.rb +13 -0
  67. data/spec/ruby_warrior/abilities/direction_of_stairs_spec.rb +13 -0
  68. data/spec/ruby_warrior/abilities/distance_of_spec.rb +13 -0
  69. data/spec/ruby_warrior/abilities/explode_spec.rb +32 -0
  70. data/spec/ruby_warrior/abilities/feel_spec.rb +13 -0
  71. data/spec/ruby_warrior/abilities/form_spec.rb +48 -0
  72. data/spec/ruby_warrior/abilities/health_spec.rb +13 -0
  73. data/spec/ruby_warrior/abilities/listen_spec.rb +17 -0
  74. data/spec/ruby_warrior/abilities/look_spec.rb +15 -0
  75. data/spec/ruby_warrior/abilities/pivot_spec.rb +18 -0
  76. data/spec/ruby_warrior/abilities/rescue_spec.rb +40 -0
  77. data/spec/ruby_warrior/abilities/rest_spec.rb +29 -0
  78. data/spec/ruby_warrior/abilities/shoot_spec.rb +22 -0
  79. data/spec/ruby_warrior/abilities/throw_spec.rb +46 -0
  80. data/spec/ruby_warrior/abilities/walk_spec.rb +25 -0
  81. data/spec/ruby_warrior/core_additions_spec.rb +7 -0
  82. data/spec/ruby_warrior/floor_spec.rb +81 -0
  83. data/spec/ruby_warrior/game_spec.rb +119 -0
  84. data/spec/ruby_warrior/level_loader_spec.rb +54 -0
  85. data/spec/ruby_warrior/level_spec.rb +203 -0
  86. data/spec/ruby_warrior/player_generator_spec.rb +12 -0
  87. data/spec/ruby_warrior/position_spec.rb +108 -0
  88. data/spec/ruby_warrior/profile_spec.rb +171 -0
  89. data/spec/ruby_warrior/space_spec.rb +190 -0
  90. data/spec/ruby_warrior/tower_spec.rb +15 -0
  91. data/spec/ruby_warrior/turn_spec.rb +42 -0
  92. data/spec/ruby_warrior/ui_spec.rb +93 -0
  93. data/spec/ruby_warrior/units/archer_spec.rb +23 -0
  94. data/spec/ruby_warrior/units/base_spec.rb +133 -0
  95. data/spec/ruby_warrior/units/captive_spec.rb +23 -0
  96. data/spec/ruby_warrior/units/golem_spec.rb +28 -0
  97. data/spec/ruby_warrior/units/sludge_spec.rb +27 -0
  98. data/spec/ruby_warrior/units/thick_sludge_spec.rb +19 -0
  99. data/spec/ruby_warrior/units/warrior_spec.rb +65 -0
  100. data/spec/ruby_warrior/units/wizard_spec.rb +23 -0
  101. data/spec/spec_helper.rb +10 -0
  102. data/templates/README.erb +33 -0
  103. data/templates/player.rb +5 -0
  104. data/towers/beginner/level_001.rb +18 -0
  105. data/towers/beginner/level_002.rb +19 -0
  106. data/towers/beginner/level_003.rb +23 -0
  107. data/towers/beginner/level_004.rb +20 -0
  108. data/towers/beginner/level_005.rb +24 -0
  109. data/towers/beginner/level_006.rb +21 -0
  110. data/towers/beginner/level_007.rb +20 -0
  111. data/towers/beginner/level_008.rb +23 -0
  112. data/towers/beginner/level_009.rb +22 -0
  113. data/towers/intermediate/level_001.rb +20 -0
  114. data/towers/intermediate/level_002.rb +22 -0
  115. data/towers/intermediate/level_003.rb +25 -0
  116. data/towers/intermediate/level_004.rb +26 -0
  117. data/towers/intermediate/level_005.rb +21 -0
  118. data/towers/intermediate/level_006.rb +25 -0
  119. data/towers/intermediate/level_007.rb +27 -0
  120. data/towers/intermediate/level_008.rb +25 -0
  121. data/towers/intermediate/level_009.rb +33 -0
  122. metadata +226 -0
@@ -0,0 +1,123 @@
1
+ module RubyWarrior
2
+ class Level
3
+ attr_reader :profile, :number
4
+ attr_accessor :description, :tip, :clue, :warrior, :floor, :time_bonus, :ace_score
5
+
6
+ def self.grade_letter(percent)
7
+ if percent >= 1.0 then "S"
8
+ elsif percent >= 0.9 then "A"
9
+ elsif percent >= 0.8 then "B"
10
+ elsif percent >= 0.7 then "C"
11
+ elsif percent >= 0.6 then "D"
12
+ else "F"
13
+ end
14
+ end
15
+
16
+ def initialize(profile, number)
17
+ @profile = profile
18
+ @number = number
19
+ @time_bonus = 0
20
+ end
21
+
22
+ def player_path
23
+ @profile.player_path
24
+ end
25
+
26
+ def load_path
27
+ File.join(
28
+ File.expand_path('../../../towers/', __FILE__),
29
+ File.basename(@profile.tower_path) + "/level_" +
30
+ @number.to_s.rjust(3, '0') + ".rb"
31
+ )
32
+ end
33
+
34
+ def load_level
35
+ LevelLoader.new(self).instance_eval(File.read(load_path))
36
+ end
37
+
38
+ def load_player
39
+ $: << player_path
40
+ load 'player.rb'
41
+ end
42
+
43
+ def generate_player_files
44
+ load_level
45
+ PlayerGenerator.new(self).generate
46
+ end
47
+
48
+ def play(turns = 1000)
49
+ load_level
50
+ turns.times do |n|
51
+ return if passed? || failed?
52
+ UI.puts "- #{R18n.t.turn} #{n+1} -"
53
+ UI.print @floor.character
54
+ @floor.units.each { |unit| unit.prepare_turn }
55
+ @floor.units.each { |unit| unit.perform_turn }
56
+ yield if block_given?
57
+ @time_bonus -= 1 if @time_bonus > 0
58
+ end
59
+ end
60
+
61
+ def tally_points
62
+ score = 0
63
+
64
+ UI.puts "#{R18n.t.level.score}: #{warrior.score}"
65
+ score += warrior.score
66
+
67
+ UI.puts "#{R18n.t.bonus.time}: #{time_bonus}"
68
+ score += @time_bonus
69
+
70
+ if floor.other_units.empty?
71
+ UI.puts "#{R18n.t.bonus.clear}: #{clear_bonus}"
72
+ score += clear_bonus
73
+ end
74
+
75
+ if @profile.epic?
76
+ UI.puts "#{R18n.t.level.grade}: #{grade_for(score)}" if grade_for(score)
77
+ UI.puts "#{R18n.t.score.total}: " + score_calculation(@profile.current_epic_score, score)
78
+ @profile.current_epic_grades[@number] = (score / ace_score.to_f) if ace_score
79
+ @profile.current_epic_score += score
80
+ else
81
+ UI.puts "#{R18n.t.score.total}: " + score_calculation(@profile.score, score)
82
+ @profile.score += score
83
+ @profile.abilities = warrior.abilities.keys
84
+ end
85
+ end
86
+
87
+ def grade_for(score)
88
+ if ace_score
89
+ self.class.grade_letter(score / ace_score.to_f)
90
+ end
91
+ end
92
+
93
+ def clear_bonus
94
+ ((warrior.score + time_bonus)*0.2).round
95
+ end
96
+
97
+ def score_calculation(current_score, addition)
98
+ if current_score.zero?
99
+ addition.to_s
100
+ else
101
+ "#{current_score} + #{addition} = #{current_score + addition}"
102
+ end
103
+ end
104
+
105
+ def passed?
106
+ @floor.stairs_space.warrior?
107
+ end
108
+
109
+ def failed?
110
+ !@floor.units.include?(warrior)
111
+ end
112
+
113
+ def exists?
114
+ File.exist? load_path
115
+ end
116
+
117
+ def setup_warrior(warrior)
118
+ @warrior = warrior
119
+ @warrior.add_abilities(*profile.abilities)
120
+ @warrior.name = profile.warrior_name
121
+ end
122
+ end
123
+ end
@@ -0,0 +1,56 @@
1
+ module RubyWarrior
2
+ class LevelLoader
3
+ def initialize(level)
4
+ @floor = RubyWarrior::Floor.new
5
+ @level = level
6
+ @level.floor = @floor
7
+ end
8
+
9
+ def description(desc)
10
+ @level.description = desc
11
+ end
12
+
13
+ def tip(tip)
14
+ @level.tip = tip
15
+ end
16
+
17
+ def clue(clue)
18
+ @level.clue = clue
19
+ end
20
+
21
+ def time_bonus(bonus)
22
+ @level.time_bonus = bonus
23
+ end
24
+
25
+ def ace_score(score)
26
+ @level.ace_score = score
27
+ end
28
+
29
+ def size(width, height)
30
+ @floor.width = width
31
+ @floor.height = height
32
+ end
33
+
34
+ def stairs(x, y)
35
+ @floor.place_stairs(x, y)
36
+ end
37
+
38
+ def unit(unit, x, y, facing = :north)
39
+ unit = unit_to_constant(unit).new unless unit.kind_of? Units::Base
40
+ @floor.add(unit, x, y, facing)
41
+ yield unit if block_given?
42
+ unit
43
+ end
44
+
45
+ def warrior(*args, &block)
46
+ @level.setup_warrior unit(Units::Warrior.new, *args, &block)
47
+ end
48
+
49
+ private
50
+
51
+ def unit_to_constant(name)
52
+ camel = name.to_s.split('_').map { |s| s.capitalize }.join
53
+ eval("Units::#{camel}")
54
+ end
55
+ end
56
+ end
@@ -0,0 +1,41 @@
1
+ require 'rubygems'
2
+ require 'fileutils'
3
+ require 'erb'
4
+
5
+ module RubyWarrior
6
+ class PlayerGenerator
7
+ def initialize(level)
8
+ @level = level
9
+ end
10
+
11
+ def level
12
+ @level
13
+ end
14
+
15
+ def previous_level
16
+ @previous_level ||= Level.new(level.profile, level.number-1)
17
+ end
18
+
19
+ # TODO refactor and test this method
20
+ def generate
21
+ if level.number == 1
22
+ FileUtils.mkdir_p(level.player_path) unless File.exists? level.player_path
23
+ FileUtils.cp(templates_path + '/player.rb', level.player_path)
24
+ end
25
+
26
+ File.open(level.player_path + '/README', 'w') do |f|
27
+ f.write read_template(templates_path + '/README.erb')
28
+ end
29
+ end
30
+
31
+ def templates_path
32
+ File.expand_path("../../../templates", __FILE__)
33
+ end
34
+
35
+ private
36
+
37
+ def read_template(path)
38
+ ERB.new(File.read(path), nil, '-').result(binding)
39
+ end
40
+ end
41
+ end
@@ -0,0 +1,82 @@
1
+ module RubyWarrior
2
+ class Position
3
+ attr_reader :floor
4
+ DIRECTIONS = [:north, :east, :south, :west]
5
+ RELATIVE_DIRECTIONS = [:forward, :right, :backward, :left]
6
+
7
+ def initialize(floor, x, y, direction = nil)
8
+ @floor = floor
9
+ @x = x
10
+ @y = y
11
+ @direction_index = DIRECTIONS.index(direction || :north)
12
+ end
13
+
14
+ def at?(x, y)
15
+ @x == x && @y == y
16
+ end
17
+
18
+ def direction
19
+ DIRECTIONS[@direction_index]
20
+ end
21
+
22
+ def rotate(amount)
23
+ @direction_index += amount
24
+ @direction_index -= 4 while @direction_index > 3
25
+ @direction_index += 4 while @direction_index < 0
26
+ end
27
+
28
+ def relative_space(forward, right = 0)
29
+ @floor.space(*translate_offset(forward, right))
30
+ end
31
+
32
+ def space
33
+ @floor.space(@x, @y)
34
+ end
35
+
36
+ def move(forward, right = 0)
37
+ @x, @y = *translate_offset(forward, right)
38
+ end
39
+
40
+ def distance_from_stairs
41
+ distance_of(@floor.stairs_space)
42
+ end
43
+
44
+ def distance_of(space)
45
+ x, y = *space.location
46
+ (@x - x).abs + (@y - y).abs
47
+ end
48
+
49
+ def relative_direction_of_stairs
50
+ relative_direction_of(@floor.stairs_space)
51
+ end
52
+
53
+ def relative_direction_of(space)
54
+ relative_direction(direction_of(space))
55
+ end
56
+
57
+ def direction_of(space)
58
+ space_x, space_y = *space.location
59
+ if (@x - space_x).abs > (@y - space_y).abs
60
+ space_x > @x ? :east : :west
61
+ else
62
+ space_y > @y ? :south : :north
63
+ end
64
+ end
65
+
66
+ def relative_direction(direction)
67
+ offset = DIRECTIONS.index(direction) - @direction_index
68
+ offset -= 4 while offset > 3
69
+ offset += 4 while offset < 0
70
+ RELATIVE_DIRECTIONS[offset]
71
+ end
72
+
73
+ def translate_offset(forward, right)
74
+ case direction
75
+ when :north then [@x + right, @y - forward]
76
+ when :east then [@x + forward, @y + right]
77
+ when :south then [@x - right, @y + forward]
78
+ when :west then [@x - forward, @y - right]
79
+ end
80
+ end
81
+ end
82
+ end
@@ -0,0 +1,120 @@
1
+ require 'base64'
2
+
3
+ module RubyWarrior
4
+ class Profile
5
+ attr_accessor :score, :epic_score, :current_epic_score, :average_grade, :current_epic_grades, :abilities, :level_number, :last_level_number, :tower_path, :warrior_name, :player_path
6
+
7
+ def initialize
8
+ @tower_path = nil
9
+ @warrior_name = nil
10
+ @score = 0
11
+ @current_epic_score = 0
12
+ @current_epic_grades = {}
13
+ @epic_score = 0
14
+ @average_grade = nil
15
+ @abilities = []
16
+ @level_number = 0
17
+ @last_level_number = nil
18
+ end
19
+
20
+ def encode
21
+ Base64.encode64(Marshal.dump(self))
22
+ end
23
+
24
+ def save
25
+ update_epic_score
26
+ @level_number = 0 if epic?
27
+ File.open(player_path + '/.profile', 'w') { |f| f.write(encode) }
28
+ end
29
+
30
+ def self.decode(str)
31
+ Marshal.load(Base64.decode64(str))
32
+ end
33
+
34
+ def self.load(path)
35
+ player = decode(File.read(path))
36
+ player.player_path = File.dirname(path)
37
+ player
38
+ end
39
+
40
+ def player_path
41
+ @player_path || Config.path_prefix + "/rubywarrior/#{directory_name}"
42
+ end
43
+
44
+ def directory_name
45
+ [warrior_name.downcase.gsub(/[^a-z0-9]+/, '-'), tower.name].join('-')
46
+ end
47
+
48
+ def to_s
49
+ if epic?
50
+ [warrior_name, tower.name, "#{R18n.t.score.first} #{score}", "#{R18n.t.score.epic} #{epic_score_with_grade}"].join(' - ')
51
+ else
52
+ [warrior_name, tower.name, "#{R18n.t.level.level} #{level_number}", "#{R18n.t.score.score} #{score}"].join(' - ')
53
+ end
54
+ end
55
+
56
+ def epic_score_with_grade
57
+ if average_grade
58
+ "#{epic_score} (#{Level.grade_letter(average_grade)})"
59
+ else
60
+ epic_score
61
+ end
62
+ end
63
+
64
+ def tower
65
+ Tower.new(File.basename @tower_path)
66
+ end
67
+
68
+ def current_level
69
+ Level.new(self, level_number)
70
+ end
71
+
72
+ def next_level
73
+ Level.new(self, level_number+1)
74
+ end
75
+
76
+ def add_abilities(*abilities)
77
+ @abilities += abilities
78
+ @abilities.uniq!
79
+ end
80
+
81
+ def enable_epic_mode
82
+ @epic = true
83
+ @epic_score ||= 0
84
+ @current_epic_score ||= 0
85
+ @last_level_number ||= @level_number
86
+ end
87
+
88
+ def enable_normal_mode
89
+ @epic = false
90
+ @epic_score = 0
91
+ @current_epic_score = 0
92
+ @current_epic_grades = {}
93
+ @average_grade = nil
94
+ @level_number = @last_level_number
95
+ @last_level_number = nil
96
+ end
97
+
98
+ def epic?
99
+ @epic
100
+ end
101
+
102
+ def level_after_epic?
103
+ Level.new(self, last_level_number+1).exists? if last_level_number
104
+ end
105
+
106
+ def update_epic_score
107
+ if @current_epic_score > @epic_score
108
+ @epic_score = @current_epic_score
109
+ @average_grade = calculate_average_grade
110
+ end
111
+ end
112
+
113
+ def calculate_average_grade
114
+ if @current_epic_grades.size > 0
115
+ sum = @current_epic_grades.values.inject(0) { |sum, value| sum + value }
116
+ sum / @current_epic_grades.size
117
+ end
118
+ end
119
+ end
120
+ end
@@ -0,0 +1,34 @@
1
+ require 'optparse'
2
+
3
+ module RubyWarrior
4
+ class Runner
5
+ def initialize(arguments, stdin, stdout)
6
+ @arguments = arguments
7
+ @stdin = stdin
8
+ @stdout = stdout
9
+ @game = RubyWarrior::Game.new
10
+ end
11
+
12
+ def run
13
+ Config.in_stream = @stdin
14
+ Config.out_stream = @stdout
15
+ Config.delay = 0.6
16
+ parse_options
17
+ @game.start
18
+ end
19
+
20
+ private
21
+
22
+ def parse_options
23
+ t = R18n.t.runner.options
24
+ options = OptionParser.new
25
+ options.banner = t.banner
26
+ options.on('-d', '--directory DIR', t.directory) { |dir| Config.path_prefix = dir }
27
+ options.on('-l', '--level LEVEL', t.level) { |level| Config.practice_level = level.to_i }
28
+ options.on('-s', '--skip', t.skip) { Config.skip_input = true }
29
+ options.on('-t', '--time SECONDS', t.time) { |seconds| Config.delay = seconds.to_f }
30
+ options.on('-h', '--help', t.help) { puts(options); exit }
31
+ options.parse!(@arguments)
32
+ end
33
+ end
34
+ end