studio_game_gem_zf 1.0.0

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.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: 23f820f54c79cc331dd2e153279c40214edebbf9fc0e9e6ba5d2e4e1877fd52f
4
+ data.tar.gz: 040544d926f5356195de996ad8c43cdc28f97b2005767f47df08f5e37acdcada
5
+ SHA512:
6
+ metadata.gz: e9f41b0588cd25337c636b152b05fecf9ebc4d7a8cafbbe5422c1cd16ab1e8e87d54a22ed7f2f568062bf93317b1c92707c0c5b2d2816f82c04e9993c6af1157
7
+ data.tar.gz: e29e45ac8c9fdf469cb78a5c650d9fb9269005e873450e329077044a5f3618b8301cacd40e9e7227f1e16b88e9804f74814689bcc02340131872029eb7c3e138
data/LICENSE ADDED
@@ -0,0 +1,11 @@
1
+ Copyright (C) <date> X Consortium
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
4
+
5
+ The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
6
+
7
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE X CONSORTIUM BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
8
+
9
+ Except as contained in this notice, the name of the X Consortium shall not be used in advertising or otherwise to promote the sale, use or other dealings in this Software without prior written authorization from the X Consortium.
10
+
11
+ X Window System is a trademark of X Consortium, Inc.
data/README ADDED
@@ -0,0 +1,3 @@
1
+ #### TO DO
2
+ - When creating a game using a .csv file and passing players with no health, players are being created with 0 HP instead of 100 HP.
3
+ - Allow players to decide coin limit when creating game.
data/bin/players.csv ADDED
@@ -0,0 +1,3 @@
1
+ Alvin,100
2
+ Simon,60
3
+ Theo, 100
@@ -0,0 +1,40 @@
1
+ # frozen_string_literal: false
2
+
3
+ require 'csv'
4
+
5
+ require_relative '../lib/studio_game/game'
6
+ require_relative '../lib/studio_game/player'
7
+ require_relative '../lib/studio_game/player_helpers'
8
+ require_relative '../lib/studio_game/clumsy_player'
9
+ require_relative '../lib/studio_game/berserk_player'
10
+
11
+ module StudioGame
12
+ game = StudioGame::Game.new('Vis Maior')
13
+
14
+ default_player_file = File.join(File.dirname(__FILE__), 'players.csv')
15
+ game.load_players(ARGV.shift || default_player_file)
16
+
17
+ klutz = ClumsyPlayer.new('klutz', 105, 14)
18
+ game.add_player(klutz)
19
+
20
+ berserker = BerserkPlayer.new('berserker', 50)
21
+ game.add_player(berserker)
22
+
23
+ loop do
24
+ puts "\nHow many game rounds? ('quit' to exit)"
25
+
26
+ answer = gets.chomp.downcase
27
+
28
+ case answer
29
+ when /^\d+$/
30
+ game.play(answer.to_i)
31
+ when 'quit', 'q', 'exit', 'x'
32
+ puts "\nGame Quit."
33
+ break
34
+ else
35
+ puts "\nEnter a round number or 'quit'"
36
+ end
37
+ end
38
+
39
+ game.save_high_scores
40
+ end
@@ -0,0 +1,9 @@
1
+ # frozen_string_literal: false
2
+
3
+ module StudioGame
4
+ module Auditable
5
+ def audit
6
+ puts "Rolled a #{@number} (#{self.class})"
7
+ end
8
+ end
9
+ end
@@ -0,0 +1,33 @@
1
+ # frozen_string_literal: false
2
+
3
+ require_relative 'player'
4
+
5
+ module StudioGame
6
+ class BerserkPlayer < Player
7
+ def initialize(name, health = 100)
8
+ super(name, health)
9
+ @w00t_count = 0
10
+ end
11
+
12
+ def berserk?
13
+ @w00t_count > 5
14
+ end
15
+
16
+ def w00t
17
+ super
18
+ @w00t_count += 1
19
+ puts "#{@name} is berserk!" if berserk?
20
+ end
21
+
22
+ def blam
23
+ berserk? ? w00t : super
24
+ end
25
+ end
26
+
27
+ if __FILE__ == $PROGRAM_NAME
28
+ berserker = BerserkPlayer.new('berserker', 50)
29
+ 6.times { berserker.w00t }
30
+ 2.times { berserker.blam }
31
+ puts berserker.health
32
+ end
33
+ end
@@ -0,0 +1,50 @@
1
+ # frozen_string_literal: false
2
+
3
+ require_relative 'player'
4
+
5
+ module StudioGame
6
+ class ClumsyPlayer < Player
7
+ attr_reader :boost_factor
8
+
9
+ def initialize(name, health = 100, boost_factor = 1)
10
+ super(name, health)
11
+ @boost_factor = boost_factor
12
+ end
13
+
14
+ # An additional w00t is called from super.
15
+ # If boost_factor = 9, there will be 10 total w00ts.
16
+ def w00t
17
+ @boost_factor.times { super }
18
+ end
19
+
20
+ def found_treasure(treasure)
21
+ damaged_treasure = Treasure.new(treasure.name, treasure.coins / 2)
22
+ super(damaged_treasure)
23
+ end
24
+ end
25
+
26
+ if __FILE__ == $PROGRAM_NAME
27
+ clumsy = ClumsyPlayer.new('klutz', 100, 9)
28
+
29
+ hammer = Treasure.new(:hammer, 50)
30
+ clumsy.found_treasure(hammer)
31
+ clumsy.found_treasure(hammer)
32
+
33
+ puts ''
34
+ puts clumsy
35
+ puts ''
36
+ clumsy.w00t
37
+ puts ''
38
+ puts clumsy
39
+
40
+ # crowbar = Treasure.new(:crowbar, 400)
41
+ # clumsy.found_treasure(crowbar)
42
+
43
+ # puts ''
44
+ # clumsy.each_found_treasure do |treasure|
45
+ # puts " - #{treasure.coins} total #{treasure.name} coins"
46
+ # end
47
+ # puts ''
48
+ # puts "#{clumsy.coins} grand total coins"
49
+ end
50
+ end
@@ -0,0 +1,21 @@
1
+ # frozen_string_literal: false
2
+
3
+ require_relative 'auditable'
4
+
5
+ module StudioGame
6
+ class Die
7
+ include Auditable
8
+
9
+ attr_writer :number
10
+
11
+ def initialize
12
+ roll
13
+ end
14
+
15
+ def roll
16
+ @number = rand(1..6)
17
+ audit
18
+ @number
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,213 @@
1
+ # frozen_string_literal: true
2
+
3
+ # clear terminal
4
+ system('cls') || system('clear')
5
+
6
+ require_relative 'player'
7
+ require_relative 'die'
8
+ require_relative 'loaded_die'
9
+ require_relative 'game_turn'
10
+ require_relative 'game_helpers'
11
+ require_relative 'treasure_trove'
12
+
13
+ module StudioGame
14
+ class Game
15
+ include GameHelpers
16
+
17
+ attr_reader :played_rounds
18
+
19
+ def initialize(title)
20
+ @title = title.upcase
21
+ @players = []
22
+ @coin_limit = nil
23
+ @played_rounds = 0
24
+ end
25
+
26
+ def load_players(from_file)
27
+ CSV.foreach(from_file) do |row|
28
+ string = CSV.generate_line(row)
29
+ player = Player.from_csv(string)
30
+ add_player(player)
31
+ end
32
+
33
+ # File.readlines(from_file).each do |line|
34
+ # player = Player.from_csv(line)
35
+ # add_player(player)
36
+ # end
37
+ end
38
+
39
+ def add_player(player)
40
+ @players << player
41
+ end
42
+
43
+ def list_players
44
+ primary_header(@title)
45
+ puts ''
46
+ @players.each_with_index do |player, i|
47
+ puts "#{i + 1}- #{player.name} (#{player.health}HP)"
48
+ end
49
+ end
50
+
51
+ def name_and_health(players)
52
+ players.each do |player|
53
+ puts " - #{player.name} (#{player.health} HP)"
54
+ end
55
+ end
56
+
57
+ def available_treasures
58
+ secondary_header('Available Treasures')
59
+ treasures = TreasureTrove::TREASURES
60
+ treasures.each do |treasure|
61
+ puts " - #{treasure.name.capitalize} is worth #{treasure.coins} coins."
62
+ end
63
+ end
64
+
65
+ def players_by_strength
66
+ puts primary_header('Players by Strength')
67
+
68
+ strong_players, wimpy_players = @players.partition(&:strong?)
69
+
70
+ if strong_players.size == @players.size
71
+ puts "Only strong players this game! (#{strong_players.size})\n"
72
+ name_and_health(strong_players)
73
+ elsif strong_players.size.positive?
74
+ puts "Strong Players (#{strong_players.size})\n"
75
+ name_and_health(strong_players)
76
+ end
77
+
78
+ if wimpy_players.size == @players.size
79
+ puts "Only wimpy players this game! (#{wimpy_players.size})\n"
80
+ name_and_health(wimpy_players)
81
+ elsif wimpy_players.size.positive?
82
+ puts "\nWimpy Players (#{wimpy_players.size})\n"
83
+ name_and_health(wimpy_players)
84
+ end
85
+
86
+ # score(@players)
87
+ end
88
+
89
+ def health_per_player(player)
90
+ puts player.name.upcase
91
+ player.player_health do |health|
92
+ puts " * Health: #{health} HP"
93
+ end
94
+ end
95
+
96
+ def treasures_per_player(player)
97
+ player.each_found_treasure do |treasure, treasure_frequency|
98
+ puts "\t- #{treasure.name.capitalize} (x#{treasure_frequency}) = #{treasure.coins} coins"
99
+ end
100
+ end
101
+
102
+ def score_per_player(player)
103
+ player.player_score do |score|
104
+ puts "\n >> Final score: #{GameHelpers.delimiter(score)} points <<"
105
+ end
106
+ end
107
+
108
+ def total_coins
109
+ @players.reduce(0) { |sum, player| sum + player.coins }
110
+ end
111
+
112
+ def game_stoppage
113
+ limit = @coin_limit.nil? ? '(no coin limit set)' : "(limit set to #{@coin_limit} coins)"
114
+ puts "Game stopped at round #{GameHelpers.delimiter(@played_rounds)}."
115
+ puts "#{GameHelpers.delimiter(total_coins)} coins were found in total #{limit}."
116
+ puts ''
117
+ end
118
+
119
+ def game_stats
120
+ primary_header('Game Stats')
121
+ @players.sort.each_with_index do |player, index|
122
+ health_per_player(player)
123
+ treasures_per_player(player)
124
+ score_per_player(player)
125
+ puts "\n\n" unless index == @players.size - 1
126
+ end
127
+ end
128
+
129
+ def high_score_entry(player, i)
130
+ " #{i + 1}- #{player.name.ljust(20, '.')}#{GameHelpers.delimiter(player.score)}"
131
+ end
132
+
133
+ def score
134
+ puts primary_header('Final Score')
135
+
136
+ game_stoppage if @played_rounds || @coin_limit
137
+
138
+ @players.sort.each_with_index do |player, i|
139
+ text = high_score_entry(player, i)
140
+ if i.zero?
141
+ puts "#{text} 🏆 WINNER 🏆"
142
+ else
143
+ puts text
144
+ end
145
+ end
146
+ end
147
+
148
+ def start_rounds(rounds)
149
+ puts primary_header('Let the games begin!')
150
+
151
+ 1.upto(rounds) do |round|
152
+ # Stops the game when given block condition is met
153
+ if block_given? && yield
154
+ @played_rounds = round - 1
155
+ break
156
+ end
157
+
158
+ puts "ROUND #{round}:"
159
+ @players.each_with_index do |player, i|
160
+ puts '' unless i.zero?
161
+ GameTurn.take_turn(player)
162
+ end
163
+ @played_rounds = round
164
+ puts '' unless round == rounds
165
+ end
166
+ end
167
+
168
+ def play(rounds, coin_limit = nil)
169
+ list_players
170
+ available_treasures
171
+
172
+ if coin_limit&.positive?
173
+ @coin_limit = coin_limit
174
+ start_rounds(rounds) do
175
+ total_coins >= @coin_limit
176
+ end
177
+ else
178
+ start_rounds(rounds)
179
+ end
180
+
181
+ # players_by_strength
182
+ game_stats
183
+ score
184
+ end
185
+
186
+ def save_high_scores(to_file = 'high_scores.txt')
187
+ File.open(to_file, 'w') do |file|
188
+ file.puts("#{@title} High Scores:")
189
+
190
+ @players.sort.each_with_index do |player, i|
191
+ text = high_score_entry(player, i)
192
+ if i.zero?
193
+ file.puts "#{text} 🏆 WINNER 🏆"
194
+ else
195
+ file.puts text
196
+ end
197
+ end
198
+ end
199
+ end
200
+ end
201
+
202
+ # Common use-case example of Game class.
203
+ if __FILE__ == $PROGRAM_NAME
204
+ game_one = Game.new('Lux Lucis')
205
+ player_one = Player.new('vayl')
206
+ player_two = Player.new('atheas', 90)
207
+
208
+ game_one.add_player(player_one)
209
+ game_one.add_player(player_two)
210
+
211
+ game_one.play(1)
212
+ end
213
+ end
@@ -0,0 +1,29 @@
1
+ # frozen_string_literal: false
2
+
3
+ module StudioGame
4
+ module GameHelpers
5
+ def primary_header(title)
6
+ title = "|| #{title} ||"
7
+ border = '=' * title.length
8
+
9
+ puts ''
10
+ puts border
11
+ puts title
12
+ puts border
13
+ end
14
+
15
+ def secondary_header(title)
16
+ title = "| #{title} |"
17
+ border = '-' * title.length
18
+
19
+ puts ''
20
+ puts border
21
+ puts title
22
+ puts border
23
+ end
24
+
25
+ def self.delimiter(number)
26
+ number.to_s.reverse.gsub(/(\d{3})(?=\d)/, '\\1,').reverse
27
+ end
28
+ end
29
+ end
@@ -0,0 +1,29 @@
1
+ # frozen_string_literal: false
2
+
3
+ require_relative 'treasure_trove'
4
+
5
+ module StudioGame
6
+ module GameTurn
7
+ def self.take_turn(player)
8
+ # # Normal Die
9
+ die = Die.new
10
+ number_rolled = die.roll
11
+
12
+ # # Loaded Die
13
+ # loaded_die = LoadedDie.new
14
+ # number_rolled = loaded_die.roll
15
+
16
+ case number_rolled
17
+ when 5..6
18
+ player.w00t
19
+ when 3..4
20
+ player.skip
21
+ else
22
+ player.blam
23
+ end
24
+
25
+ treasure = TreasureTrove.random
26
+ player.found_treasure(treasure)
27
+ end
28
+ end
29
+ end
@@ -0,0 +1,18 @@
1
+ # frozen_string_literal: false
2
+
3
+ require_relative 'auditable'
4
+
5
+ module StudioGame
6
+ class LoadedDie
7
+ include Auditable
8
+
9
+ attr_reader :number
10
+
11
+ def roll
12
+ numbers = [1, 1, 2, 5, 6, 6]
13
+ @number = numbers.sample
14
+ audit
15
+ @number
16
+ end
17
+ end
18
+ end
@@ -0,0 +1,25 @@
1
+ # frozen_string_literal: false
2
+
3
+ module StudioGame
4
+ module Playable
5
+ def w00t
6
+ increase = 15
7
+ # self is needed as we're modifying an attribute.
8
+ self.health += increase
9
+
10
+ # when reading from an instance variable, you can omit "self"
11
+ # as it is the implicit (default) receiver of the method call.
12
+ puts " - #{name} got w00ted! (+#{increase} HP)"
13
+ end
14
+
15
+ def blam
16
+ decrease = 10
17
+ self.health -= decrease
18
+ puts " - #{name} got blammed! (-10 HP)"
19
+ end
20
+
21
+ def strong?
22
+ health >= 100
23
+ end
24
+ end
25
+ end
@@ -0,0 +1,98 @@
1
+ # frozen_string_literal: false
2
+
3
+ require_relative 'game_helpers'
4
+ require_relative 'treasure_trove'
5
+ require_relative 'playable'
6
+
7
+ module StudioGame
8
+ class Player
9
+ include Playable
10
+
11
+ attr_reader :name
12
+ attr_accessor :health
13
+
14
+ def initialize(name, health = 100)
15
+ @name = name.capitalize
16
+ @health = health
17
+ @found_treasures = Hash.new(0)
18
+ end
19
+
20
+ def self.from_csv(string)
21
+ name, health = string.split(',')
22
+ Player.new(name, health.to_i)
23
+ end
24
+
25
+ # virtual accessor
26
+ def score
27
+ @health + coins
28
+ end
29
+
30
+ def skip
31
+ puts " - #{@name} got skipped!"
32
+ end
33
+
34
+ # virtual accessor
35
+ def coins
36
+ @found_treasures.values.reduce(0, :+)
37
+ end
38
+
39
+ def found_treasure(treasure)
40
+ @found_treasures[treasure.name] += treasure.coins
41
+ puts " #{@name} found a #{treasure.name} worth #{treasure.coins} points."
42
+ end
43
+
44
+ def treasure_frequency(coins, treasure)
45
+ treasures = {
46
+ pie: 5,
47
+ bottle: 25,
48
+ hammer: 50,
49
+ skillet: 100,
50
+ broomstick: 200,
51
+ crowbar: 400
52
+ }
53
+ coins / treasures[treasure.name]
54
+ end
55
+
56
+ def each_found_treasure
57
+ puts ' * Treasures:'
58
+ @found_treasures.each do |name, coins|
59
+ treasure = Treasure.new(name, coins)
60
+ treasure_frequency = treasure_frequency(coins, treasure)
61
+ yield treasure, treasure_frequency
62
+ end
63
+ puts "\t--------------------------------"
64
+ puts "\t Total: #{GameHelpers.delimiter(coins)} coins"
65
+ end
66
+
67
+ def player_health
68
+ yield health
69
+ end
70
+
71
+ def player_score
72
+ yield score
73
+ end
74
+
75
+ def name=(new_name)
76
+ @name = new_name.capitalize
77
+ end
78
+
79
+ def <=>(other)
80
+ other.score <=> score
81
+ end
82
+
83
+ def to_s
84
+ "#{@name}, #{@health}HP and a score of #{score}."
85
+ end
86
+ end
87
+
88
+ # Common use-case example of Player class.
89
+ if __FILE__ == $PROGRAM_NAME
90
+ player = Player.new('moe', 90)
91
+ puts player.name
92
+ puts player.health
93
+ player.w00t
94
+ puts player.health
95
+ player.blam
96
+ puts player.health
97
+ end
98
+ end
@@ -0,0 +1,30 @@
1
+ # frozen_string_literal: false
2
+
3
+ require_relative 'game'
4
+ require_relative 'player'
5
+
6
+ module StudioGame
7
+ module PlayerHelpers
8
+ def self.random_health
9
+ rand(80..120)
10
+ end
11
+
12
+ def self.generate_players(number_of_players)
13
+ puts number_of_players
14
+ many_players = []
15
+
16
+ number_of_players.times do |n|
17
+ name = "Player #{n + 1}"
18
+ many_players << Player.new(name, random_health)
19
+ end
20
+
21
+ many_players
22
+ end
23
+
24
+ def self.add_players_to_game(game_name, players)
25
+ players.each do |player|
26
+ game_name.add_player(player)
27
+ end
28
+ end
29
+ end
30
+ end
@@ -0,0 +1,20 @@
1
+ # frozen_string_literal: false
2
+
3
+ module StudioGame
4
+ Treasure = Struct.new(:name, :coins)
5
+
6
+ module TreasureTrove
7
+ TREASURES = [
8
+ Treasure.new(:pie, 5),
9
+ Treasure.new(:bottle, 25),
10
+ Treasure.new(:hammer, 50),
11
+ Treasure.new(:skillet, 100),
12
+ Treasure.new(:broomstick, 200),
13
+ Treasure.new(:crowbar, 400)
14
+ ]
15
+
16
+ def self.random
17
+ TREASURES.sample
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,29 @@
1
+ # frozen_string_literal: false
2
+
3
+ require 'studio_game/berserk_player'
4
+
5
+ module StudioGame
6
+ describe BerserkPlayer do
7
+ before do
8
+ $stdout = StringIO.new
9
+ @initial_health = 50
10
+ @berserker = BerserkPlayer.new('berserker', @initial_health)
11
+ end
12
+
13
+ it 'does not go berserk when w00ted up to 5 times' do
14
+ 1.upto(5) { @berserker.w00t }
15
+ expect(@berserker.berserk?).to eq(false)
16
+ end
17
+
18
+ it 'goes berserk when w00ted more than 5 times' do
19
+ 1.upto(6) { @berserker.w00t }
20
+ expect(@berserker.berserk?).to eq(true)
21
+ end
22
+
23
+ it "gets w00ted instead of blammed when it's gone berserk" do
24
+ 6.times { @berserker.w00t }
25
+ 2.times { @berserker.blam }
26
+ expect(@berserker.health).to eq(@initial_health + (8 * 15))
27
+ end
28
+ end
29
+ end
@@ -0,0 +1,54 @@
1
+ # frozen_string_literal: false
2
+
3
+ require 'studio_game/clumsy_player'
4
+
5
+ module StudioGame
6
+ describe ClumsyPlayer do
7
+ before do
8
+ $stdout = StringIO.new
9
+ @player = ClumsyPlayer.new('klutz')
10
+ end
11
+
12
+ it 'only gets half the coin value for each treasure' do
13
+ expect(@player.coins).to eq(0)
14
+
15
+ hammer = Treasure.new(:hammer, 50)
16
+ @player.found_treasure(hammer)
17
+ @player.found_treasure(hammer)
18
+ @player.found_treasure(hammer)
19
+
20
+ expect(@player.coins).to eq(75)
21
+
22
+ crowbar = Treasure.new(:crowbar, 400)
23
+ @player.found_treasure(crowbar)
24
+
25
+ expect(@player.coins).to eq(275)
26
+
27
+ yielded = []
28
+
29
+ @player.each_found_treasure do |treasure|
30
+ yielded << treasure
31
+ end
32
+
33
+ expect(yielded).to eq([Treasure.new(:hammer, 75), Treasure.new(:crowbar, 200)])
34
+ end
35
+
36
+ context 'with a boost factor' do
37
+ before do
38
+ @initial_health = 100
39
+ @boost_factor = 5
40
+ @player = ClumsyPlayer.new('klutz', @initial_health, @boost_factor)
41
+ end
42
+
43
+ it 'has a boost factor' do
44
+ expect(@player.boost_factor).to eq(5)
45
+ end
46
+
47
+ it 'gets boost factor number of w00ts when w00ted' do
48
+ @player.w00t
49
+
50
+ expect(@player.health).to eq(@initial_health + (15 * @boost_factor))
51
+ end
52
+ end
53
+ end
54
+ end
@@ -0,0 +1,91 @@
1
+ # frozen_string_literal: false
2
+
3
+ require 'studio_game/game'
4
+
5
+ module StudioGame
6
+ describe Game do
7
+ before do
8
+ $stdout = StringIO.new
9
+ @game = Game.new('Knuckleheads')
10
+ @initial_health = 100
11
+ @player = Player.new('moe', @initial_health)
12
+ @game.add_player(@player)
13
+ end
14
+
15
+ it 'w00ts the player if high roll (5..6)' do
16
+ allow_any_instance_of(Die).to receive(:roll).and_return(5)
17
+ @game.play(2)
18
+ expect(@player.health).to eq(@initial_health + (15 * 2))
19
+ end
20
+
21
+ it 'skips the player if medium roll (3..4)' do
22
+ allow_any_instance_of(Die).to receive(:roll).and_return(3)
23
+ @game.play(2)
24
+ expect(@player.health).to eq(@initial_health)
25
+ end
26
+
27
+ it 'blams the player if low roll (1..2)' do
28
+ allow_any_instance_of(Die).to receive(:roll).and_return(2)
29
+ @game.play(2)
30
+ expect(@player.health).to eq(@initial_health - (10 * 2))
31
+ end
32
+
33
+ it "assigns a treasure for coins during a player's turn" do
34
+ game = Game.new('Knuckleheads')
35
+ player = Player.new('moe')
36
+
37
+ game.add_player(player)
38
+ game.play(1)
39
+
40
+ expect(player.coins).not_to be_zero
41
+ end
42
+
43
+ it 'computes total coins as the sum of all player coins' do
44
+ game = Game.new('Knuckleheads')
45
+
46
+ player1 = Player.new('moe')
47
+ player2 = Player.new('larry')
48
+
49
+ game.add_player(player1)
50
+ game.add_player(player2)
51
+
52
+ player1.found_treasure(Treasure.new(:hammer, 50))
53
+ player1.found_treasure(Treasure.new(:hammer, 50))
54
+ player2.found_treasure(Treasure.new(:crowbar, 400))
55
+
56
+ expect(game.total_coins).to eq(500)
57
+ end
58
+
59
+ it 'stops based on coin limit' do
60
+ game = Game.new('Knuckleheads')
61
+
62
+ player1 = Player.new('moe')
63
+ player2 = Player.new('larry')
64
+
65
+ game.add_player(player1)
66
+ game.add_player(player2)
67
+
68
+ player1.found_treasure(Treasure.new(:hammer, 50))
69
+ player1.found_treasure(Treasure.new(:hammer, 50))
70
+ player2.found_treasure(Treasure.new(:crowbar, 400))
71
+
72
+ game.play(10, 500)
73
+
74
+ expect(game.played_rounds).to eq(0)
75
+ end
76
+
77
+ it 'runs without a coin limit' do
78
+ game = Game.new('Knuckleheads')
79
+
80
+ player1 = Player.new('moe')
81
+ player2 = Player.new('larry')
82
+
83
+ game.add_player(player1)
84
+ game.add_player(player2)
85
+
86
+ game.play(10, 1000)
87
+
88
+ expect(game.played_rounds).to_not eq(0)
89
+ end
90
+ end
91
+ end
@@ -0,0 +1,153 @@
1
+ # frozen_string_literal: false
2
+
3
+ # clear terminal
4
+ system('cls') || system('clear')
5
+
6
+ require 'studio_game/player'
7
+ require 'studio_game/treasure_trove'
8
+
9
+ module StudioGame
10
+ describe Player do
11
+ before do
12
+ $stdout = StringIO.new
13
+ @initial_health = 150
14
+ @name = 'vayl'
15
+ @score = @initial_health
16
+ @player = Player.new(@name, @initial_health)
17
+ end
18
+
19
+ it 'has a capitalized name' do
20
+ expect(@player.name).to eq('Vayl')
21
+ end
22
+
23
+ it 'has an initial health' do
24
+ expect(@player.health).to eq(@initial_health)
25
+ end
26
+
27
+ it 'has a string representation' do
28
+ expect(@player.to_s).to eq("Vayl, #{@initial_health}HP and a score of #{@score}.")
29
+ end
30
+
31
+ it 'computes a score as the sum of its health and coins' do
32
+ @player.found_treasure(Treasure.new(:hammer, 50))
33
+ @player.found_treasure(Treasure.new(:hammer, 50))
34
+
35
+ expect(@player.score).to eq(250)
36
+ end
37
+
38
+ it 'increases health by 15 when w00ted' do
39
+ @player.w00t
40
+ expect(@player.health).to eq(@initial_health + 15)
41
+ end
42
+
43
+ it 'decreases health by 10 when blammed' do
44
+ @player.blam
45
+ expect(@player.health).to eq(@initial_health - 10)
46
+ end
47
+
48
+ it 'computes coins as the sum of all treasure coins' do
49
+ expect(@player.coins).to eq(0)
50
+
51
+ @player.found_treasure(Treasure.new(:hammer, 50))
52
+ expect(@player.coins).to eq(50)
53
+
54
+ @player.found_treasure(Treasure.new(:crowbar, 400))
55
+ expect(@player.coins).to eq(450)
56
+
57
+ @player.found_treasure(Treasure.new(:hammer, 50))
58
+ expect(@player.coins).to eq(500)
59
+ end
60
+
61
+ it 'yields each found treasure and its total coins' do
62
+ @player.found_treasure(Treasure.new(:skillet, 100))
63
+ @player.found_treasure(Treasure.new(:skillet, 100))
64
+ @player.found_treasure(Treasure.new(:hammer, 50))
65
+ @player.found_treasure(Treasure.new(:bottle, 5))
66
+ @player.found_treasure(Treasure.new(:bottle, 5))
67
+ @player.found_treasure(Treasure.new(:bottle, 5))
68
+ @player.found_treasure(Treasure.new(:bottle, 5))
69
+ @player.found_treasure(Treasure.new(:bottle, 5))
70
+
71
+ yielded = []
72
+ @player.each_found_treasure do |treasure|
73
+ yielded << treasure
74
+ end
75
+
76
+ expect(yielded).to eq([Treasure.new(:skillet, 200), Treasure.new(:hammer, 50), Treasure.new(:bottle, 25)])
77
+ end
78
+
79
+ it 'calculates the frequency of treasures found' do
80
+ @player.found_treasure(Treasure.new(:skillet, 100))
81
+ @player.found_treasure(Treasure.new(:skillet, 100))
82
+ @player.found_treasure(Treasure.new(:hammer, 50))
83
+ @player.found_treasure(Treasure.new(:bottle, 25))
84
+ @player.found_treasure(Treasure.new(:bottle, 25))
85
+ @player.found_treasure(Treasure.new(:bottle, 25))
86
+
87
+ yielded = []
88
+ @player.each_found_treasure do |treasure, treasure_frequency|
89
+ puts treasure
90
+ yielded << treasure_frequency
91
+ end
92
+
93
+ expect(yielded).to eq([2, 1, 3])
94
+ end
95
+
96
+ it 'can be created from a CSV string' do
97
+ player = Player.from_csv('larry,150')
98
+
99
+ expect(player.name).to eq('Larry')
100
+ expect(player.health).to eq(150)
101
+ end
102
+
103
+ context 'with no health parameter' do
104
+ before do
105
+ @player = Player.new('vayl')
106
+ end
107
+
108
+ it 'sets health to 100' do
109
+ expect(@player.health).to eq(100)
110
+ end
111
+ end
112
+
113
+ context 'with a health greater than 100' do
114
+ before do
115
+ @increase = 15
116
+ @initial_health = 150
117
+ @player = Player.new('Vayl', @initial_health)
118
+ end
119
+
120
+ it 'is strong' do
121
+ # allow(@player).to receive(:strong?) { true }
122
+ expect(@player.strong?).to be(true)
123
+ end
124
+ end
125
+
126
+ context 'with a health smaller than 100' do
127
+ before do
128
+ @decrease = -10
129
+ @initial_health = 99
130
+ @player = Player.new('Vayl', @initial_health)
131
+ end
132
+
133
+ it 'is wimpy' do
134
+ # allow(@player).to receive(:strong?) { true }
135
+ expect(@player.strong?).to be(false)
136
+ end
137
+ end
138
+
139
+ context 'in a collection of players' do
140
+ before do
141
+ @player1 = Player.new('moe', 100)
142
+ @player2 = Player.new('larry', 200)
143
+ @player3 = Player.new('curly', 300)
144
+
145
+ @players = [@player1, @player2, @player3]
146
+ end
147
+
148
+ it 'is sorted by decreasing score' do
149
+ expect(@players.sort).to eq([@player3, @player2, @player1])
150
+ end
151
+ end
152
+ end
153
+ end
@@ -0,0 +1,57 @@
1
+ # frozen_string_literal: false
2
+
3
+ # clear terminal
4
+ system('cls') || system('clear')
5
+
6
+ require 'studio_game/treasure_trove'
7
+
8
+ module StudioGame
9
+ describe Treasure do
10
+ before do
11
+ @treasure = Treasure.new(:hammer, 50)
12
+ end
13
+
14
+ it 'has a name attribute' do
15
+ expect(@treasure.name).to eq(:hammer)
16
+ end
17
+
18
+ it 'has a coins attribute' do
19
+ expect(@treasure.coins).to eq(50)
20
+ end
21
+ end
22
+
23
+ describe TreasureTrove do
24
+ it 'has six treasures' do
25
+ expect(TreasureTrove::TREASURES.size).to eq(6)
26
+ end
27
+
28
+ it 'has a pie worth 5 coins' do
29
+ expect(TreasureTrove::TREASURES[0]).to eq(Treasure.new(:pie, 5))
30
+ end
31
+
32
+ it 'has a bottle worth 25 coins' do
33
+ expect(TreasureTrove::TREASURES[1]).to eq(Treasure.new(:bottle, 25))
34
+ end
35
+
36
+ it 'has a hammer worth 50 coins' do
37
+ expect(TreasureTrove::TREASURES[2]).to eq(Treasure.new(:hammer, 50))
38
+ end
39
+
40
+ it 'has a skillet worth 100 coins' do
41
+ expect(TreasureTrove::TREASURES[3]).to eq(Treasure.new(:skillet, 100))
42
+ end
43
+
44
+ it 'has a broomstick worth 200 coins' do
45
+ expect(TreasureTrove::TREASURES[4]).to eq(Treasure.new(:broomstick, 200))
46
+ end
47
+
48
+ it 'has a crowbar worth 400 coins' do
49
+ expect(TreasureTrove::TREASURES[5]).to eq(Treasure.new(:crowbar, 400))
50
+ end
51
+
52
+ it 'returns a random treasure' do
53
+ treasure = TreasureTrove.random
54
+ expect(TreasureTrove::TREASURES).to include(treasure)
55
+ end
56
+ end
57
+ end
metadata ADDED
@@ -0,0 +1,91 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: studio_game_gem_zf
3
+ version: !ruby/object:Gem::Version
4
+ version: 1.0.0
5
+ platform: ruby
6
+ authors:
7
+ - Vayl & The Pragmatic Studio
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2022-12-14 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: rspec
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '2.8'
20
+ - - ">="
21
+ - !ruby/object:Gem::Version
22
+ version: 2.8.0
23
+ type: :development
24
+ prerelease: false
25
+ version_requirements: !ruby/object:Gem::Requirement
26
+ requirements:
27
+ - - "~>"
28
+ - !ruby/object:Gem::Version
29
+ version: '2.8'
30
+ - - ">="
31
+ - !ruby/object:Gem::Version
32
+ version: 2.8.0
33
+ description: |-
34
+ #### TO DO
35
+ - When creating a game using a .csv file and passing players with no health, players are being created with 0 HP instead of 100 HP.
36
+ - Allow players to decide coin limit when creating game.
37
+ email: support@pragmaticstudio.com
38
+ executables: []
39
+ extensions: []
40
+ extra_rdoc_files: []
41
+ files:
42
+ - LICENSE
43
+ - README
44
+ - bin/players.csv
45
+ - bin/studio_game.rb
46
+ - lib/studio_game/auditable.rb
47
+ - lib/studio_game/berserk_player.rb
48
+ - lib/studio_game/clumsy_player.rb
49
+ - lib/studio_game/die.rb
50
+ - lib/studio_game/game.rb
51
+ - lib/studio_game/game_helpers.rb
52
+ - lib/studio_game/game_turn.rb
53
+ - lib/studio_game/loaded_die.rb
54
+ - lib/studio_game/playable.rb
55
+ - lib/studio_game/player.rb
56
+ - lib/studio_game/player_helpers.rb
57
+ - lib/studio_game/treasure_trove.rb
58
+ - spec/studio_game/berserk_player_spec.rb
59
+ - spec/studio_game/clumsy_player_spec.rb
60
+ - spec/studio_game/game_spec.rb
61
+ - spec/studio_game/player_spec.rb
62
+ - spec/studio_game/treasure_trove_spec.rb
63
+ homepage: http://pragmaticstudio.com
64
+ licenses:
65
+ - MIT
66
+ metadata: {}
67
+ post_install_message:
68
+ rdoc_options: []
69
+ require_paths:
70
+ - lib
71
+ required_ruby_version: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - ">="
74
+ - !ruby/object:Gem::Version
75
+ version: '2.6'
76
+ required_rubygems_version: !ruby/object:Gem::Requirement
77
+ requirements:
78
+ - - ">="
79
+ - !ruby/object:Gem::Version
80
+ version: '0'
81
+ requirements: []
82
+ rubygems_version: 3.3.7
83
+ signing_key:
84
+ specification_version: 4
85
+ summary: A fun, and entirely random, text-based game
86
+ test_files:
87
+ - spec/studio_game/berserk_player_spec.rb
88
+ - spec/studio_game/clumsy_player_spec.rb
89
+ - spec/studio_game/game_spec.rb
90
+ - spec/studio_game/player_spec.rb
91
+ - spec/studio_game/treasure_trove_spec.rb