studio_game_michaelwestphal 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: a4cbbecafa0ce19433f2eceed117e16771cd618dc3dbd0d1d720c1f985754123
4
+ data.tar.gz: '030397178ecb162e1554410aa2c0fc4d1352805f2a7c2e008880630f3cb2c679'
5
+ SHA512:
6
+ metadata.gz: 2d95850bf962e2ee726767b4b225e4a2b90b7fd09d0038c690a818f22bce973d303d319baa1b4a5878ffdbfbef12e2795a1f14ab921b0fb97e4cbbddf86a69b9
7
+ data.tar.gz: ad368f65659c6447d0be0739465516383d2b24b2afee4ba250347fcc1f6be15d4517968b8abb747d9691a8ff69abf9fded349a0004a9be7e2a18321b6a42d26b
data/LICENSE ADDED
@@ -0,0 +1,19 @@
1
+ Copyright (c) 2022 Michael Westphal
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining a copy
4
+ of this software and associated documentation files (the "Software"), to deal
5
+ in the Software without restriction, including without limitation the rights
6
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7
+ copies of the Software, and to permit persons to whom the Software is
8
+ furnished to do so, subject to the following conditions:
9
+
10
+ The above copyright notice and this permission notice shall be included in all
11
+ copies or substantial portions of the Software.
12
+
13
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
19
+ SOFTWARE.
data/README ADDED
@@ -0,0 +1,5 @@
1
+ # Studio Game
2
+
3
+ The Studio Game developed while taking the [Ruby Programming course](https://pragmaticstudio.com/courses/ruby) from the [Pragmatic Studio](https://pragmaticstudio.com/).
4
+
5
+ 📚 **[My Pragmatic Studio alumni page](https://pragmaticstudio.com/alumni/michaelwestphal)**
data/bin/players.csv ADDED
@@ -0,0 +1,3 @@
1
+ Alvin,100
2
+ Simon,60
3
+ Theo,125
data/bin/studio_game ADDED
@@ -0,0 +1,36 @@
1
+ #!/usr/bin/env ruby
2
+ require_relative '../lib/studio_game/player'
3
+ require_relative '../lib/studio_game/clumsy_player'
4
+ require_relative '../lib/studio_game/berserk_player'
5
+ require_relative '../lib/studio_game/game'
6
+
7
+ klutz = StudioGame::ClumsyPlayer.new('klutz', 105)
8
+ berserker = StudioGame::BerserkPlayer.new('berserker', 50)
9
+
10
+ knuckleheads = StudioGame::Game.new('Knuckleheads')
11
+
12
+ default_player_file = File.join(File.dirname(__FILE__), 'players.csv')
13
+ knuckleheads.load_players(ARGV.shift || default_player_file)
14
+ knuckleheads.add_player(klutz)
15
+ knuckleheads.add_player(berserker)
16
+
17
+ loop do
18
+ puts "How many game rounds? ('quit' to exit)"
19
+ # Chomp removes new line
20
+ answer = gets.chomp.downcase
21
+
22
+ case answer
23
+ when /^\d+$/
24
+ knuckleheads.play(answer.to_i)
25
+ when 'exit', 'quit'
26
+ knuckleheads.print_stats
27
+ break
28
+ else
29
+ puts "Please enter a number or 'quit'"
30
+ end
31
+ end
32
+ knuckleheads.save_high_scores
33
+
34
+ # knuckleheads.play(10) { knuckleheads.total_points >= 2000 }
35
+
36
+ # puts player3.inspect
@@ -0,0 +1,7 @@
1
+ module StudioGame
2
+ module Auditable
3
+ def audit
4
+ puts "Rolled a #{self.number} (#{self.class})"
5
+ end
6
+ end
7
+ end
@@ -0,0 +1,35 @@
1
+ require_relative 'player'
2
+
3
+ module StudioGame
4
+ class BerserkPlayer < Player
5
+ def initialize(name, health = 100)
6
+ super(name, health)
7
+ @w00t_count = 0
8
+ end
9
+
10
+ def berserk?
11
+ @w00t_count > 5
12
+ end
13
+
14
+ def w00t
15
+ super
16
+ @w00t_count += 1
17
+ puts "#{@name} is berserk!" if berserk?
18
+ end
19
+
20
+ def blam
21
+ if berserk?
22
+ w00t
23
+ else
24
+ super
25
+ end
26
+ end
27
+ end
28
+ end
29
+
30
+ if __FILE__ == $PROGRAM_NAME
31
+ berserker = StudioGame::BerserkPlayer.new("berserker", 50)
32
+ 6.times { berserker.w00t }
33
+ 2.times { berserker.blam }
34
+ puts berserker.health
35
+ end
@@ -0,0 +1,47 @@
1
+ require_relative 'player'
2
+ require_relative 'treasure_trove'
3
+
4
+ module StudioGame
5
+ class ClumsyPlayer < Player
6
+ attr_reader :boost_factor
7
+
8
+ def initialize(name, health = 100, boost_factor = 1)
9
+ super(name, health)
10
+ @boost_factor = boost_factor
11
+ end
12
+
13
+ def found_treasure(treasure)
14
+ # NOTE: The 2.0 denominator is changing the numeric type of the points held in the treasure
15
+ # from an Integer to Float. (See the test within the TreasureTrove module.) This is changing
16
+ # the value of the total_points method on the Game automatically converts the returned sum
17
+ # into a Float when it comes across it in the treasures. Float must "supersede" Integer,
18
+ # forcing a type conversion when working between integers and decimals. I bet we could force
19
+ # it back with to_i...
20
+ damaged_treasure = Treasure.new(treasure.name, treasure.points / 2.0)
21
+ super(damaged_treasure)
22
+ end
23
+
24
+ def w00t
25
+ @boost_factor.times { super }
26
+ end
27
+ end
28
+ end
29
+
30
+ if __FILE__ == $PROGRAM_NAME
31
+ clumsy = StudioGame::ClumsyPlayer.new("klutz", 100, 3)
32
+
33
+ hammer = StudioGame::Treasure.new(:hammer, 50)
34
+ clumsy.found_treasure(hammer)
35
+ clumsy.found_treasure(hammer)
36
+ clumsy.found_treasure(hammer)
37
+
38
+ crowbar = StudioGame::Treasure.new(:crowbar, 400)
39
+ clumsy.found_treasure(crowbar)
40
+
41
+ clumsy.w00t
42
+
43
+ clumsy.each_found_treasure do |treasure|
44
+ puts "#{treasure.points} total #{treasure.name} points"
45
+ end
46
+ puts "#{clumsy.points} grand total points"
47
+ end
@@ -0,0 +1,26 @@
1
+ require_relative 'auditable'
2
+
3
+ module StudioGame
4
+ class Die
5
+ include Auditable
6
+
7
+ attr_reader :number
8
+
9
+ # Introduced during Chapter 13: Conditionals and TDD as a means to ensure the number
10
+ # instance variable always has a valid value given the attribute reader.
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
22
+
23
+ if __FILE__ == $PROGRAM_NAME
24
+ die = StudioGame::Die.new
25
+ die.roll
26
+ end
@@ -0,0 +1,133 @@
1
+ # require 'csv'
2
+ require_relative 'player'
3
+ require_relative 'game_turn'
4
+ require_relative 'treasure_trove'
5
+
6
+ module StudioGame
7
+ class Game
8
+ attr_reader :title
9
+
10
+ def initialize(title)
11
+ @title = title
12
+ @players = []
13
+ end
14
+
15
+ def add_player(player)
16
+ @players << player
17
+ # Or with push
18
+ # @players.push(player)
19
+ end
20
+
21
+ def load_players(from_file = "players.csv")
22
+ # CSV.foreach(from_file) do |row|
23
+ # name, health = row
24
+ # add_player(Player.new(name, Integer(health)))
25
+ # end
26
+ File.readlines(from_file).each do |line|
27
+ # In the course we refactored the original implementation
28
+ # to be within the new class-level from_csv method on Player.
29
+ # The idea being that we are keeping code at the same general
30
+ # level of abstraction and the from_csv portion was lower
31
+ # than the reading of lines and adding them as players.
32
+ add_player(Player.from_csv(line))
33
+ end
34
+ end
35
+
36
+ def save_high_scores(to_file = "high_scores.txt")
37
+ File.open(to_file, "w") do |file|
38
+ file.puts "#{@title} High Scores:"
39
+ @players.sort.each do |player|
40
+ file.puts high_score_entry(player)
41
+ end
42
+ end
43
+ end
44
+
45
+ def high_score_entry(player)
46
+ formatted_name = player.name.ljust(20,'.')
47
+ "#{formatted_name} #{player.health}"
48
+ end
49
+
50
+ # I'm trying to think about the data modeling and design they have going on here
51
+ # How they're choosing to encapsulate data and the like. I feel I "design on the fly"
52
+ # too often at what expense? It feels like that the expense of my models and the ability
53
+ # to see what is really happening. I "just want to code" at the expense of the feature
54
+ # even if I'm relatively satisfied with the end result, it does not feel like enough
55
+ # care and forethought has been given...
56
+ def total_points
57
+ # ClumsyPlayer can have Float value Treasure points. If we want to force the sum
58
+ # back to an Integer, try to_i...
59
+ @players.reduce(0) { |acc,n| acc + n.points }
60
+ end
61
+
62
+ def play(rounds)
63
+ current_formatted_time = Time.new.strftime('%A %m/%d/%Y at %H:%M')
64
+ puts "The game started on #{current_formatted_time}"
65
+ puts "There are #{@players.size} players in #{@title}:"
66
+
67
+ @players.each do |player|
68
+ puts player
69
+ end
70
+
71
+ treasures = TreasureTrove::TREASURES
72
+ puts "\nThere are #{treasures.size} treasures to be found:"
73
+ treasures.each do |treasure|
74
+ puts "A #{treasure.name} is worth #{treasure.points} points"
75
+ end
76
+
77
+ 1.upto(rounds) do |round|
78
+ if block_given?
79
+ break if yield
80
+ end
81
+ # OR
82
+ # break if block_given? and yield
83
+
84
+ puts "\nRound: #{round}:"
85
+
86
+ @players.each do |player|
87
+ GameTurn.take_turn(player)
88
+ puts player
89
+ end
90
+ end
91
+ end
92
+
93
+ def print_name_and_health(player)
94
+ puts "#{player.name} (#{player.health})"
95
+ end
96
+
97
+ def print_stats
98
+ puts "\n#{@title} Statistics"
99
+
100
+ strong_players, wimpy_players = @players.partition { |player| player.strong? }
101
+
102
+ puts "\n#{strong_players.length} strong players:"
103
+ strong_players.each do |player|
104
+ print_name_and_health(player)
105
+ end
106
+
107
+ puts "\n#{wimpy_players.length} wimpy players:"
108
+ wimpy_players.each do |player|
109
+ print_name_and_health(player)
110
+ end
111
+
112
+ puts "\n#{@title} High Scores:"
113
+ @players.sort.each do |player|
114
+ puts high_score_entry(player)
115
+ end
116
+
117
+ @players.each do |player|
118
+ puts "\n#{player.name}'s total points:"
119
+ player.each_found_treasure do |treasure|
120
+ puts "#{treasure.points} total #{treasure.name} points"
121
+ end
122
+ puts "#{player.points} grand total points"
123
+ end
124
+
125
+ puts "\n#{total_points} total points from treasures found"
126
+ end
127
+ end
128
+ end
129
+
130
+ if __FILE__ == $PROGRAM_NAME
131
+ game = StudioGame::Game.new('Bingo')
132
+ game.load_players
133
+ end
@@ -0,0 +1,24 @@
1
+ require_relative 'player'
2
+ require_relative 'die'
3
+ # require_relative 'loaded_die'
4
+ require_relative 'treasure_trove'
5
+
6
+ module StudioGame
7
+ module GameTurn
8
+ def self.take_turn(player)
9
+ die = Die.new
10
+ # die = LoadedDie.new
11
+ case die.roll
12
+ when 1..2
13
+ player.blam
14
+ when 3..4
15
+ puts "#{player.name} was skipped."
16
+ else
17
+ player.w00t
18
+ end
19
+
20
+ treasure = TreasureTrove.random
21
+ player.found_treasure(treasure)
22
+ end
23
+ end
24
+ end
@@ -0,0 +1,16 @@
1
+ require_relative 'auditable'
2
+
3
+ module StudioGame
4
+ class LoadedDie
5
+ include Auditable
6
+
7
+ attr_accessor :number
8
+
9
+ def roll
10
+ numbers = [1, 1, 2, 5, 6, 6]
11
+ @number = numbers.sample
12
+ audit
13
+ @number
14
+ end
15
+ end
16
+ end
@@ -0,0 +1,20 @@
1
+ module StudioGame
2
+ module Playable
3
+ def strong?
4
+ health > 100
5
+ end
6
+
7
+ def blam
8
+ self.health -= 10
9
+ puts "#{name} got blammed!"
10
+ end
11
+
12
+ def w00t
13
+ self.health += 15
14
+ puts "#{name} got w00ted!"
15
+ end
16
+
17
+ # TODO: Move the comparison operator into here too since it's health related?
18
+ # Is that a "playable" trait?
19
+ end
20
+ end
@@ -0,0 +1,70 @@
1
+ require_relative 'playable'
2
+ require_relative 'treasure_trove'
3
+
4
+ module StudioGame
5
+ class Player
6
+ include Playable
7
+ attr_accessor :health
8
+ attr_reader :name
9
+
10
+ def initialize(name, health = 100)
11
+ @name = name.capitalize
12
+ @health = health
13
+ @found_treasures = Hash.new(0)
14
+ end
15
+
16
+ def self.from_csv(string)
17
+ name, health = string.split(',')
18
+ Player.new(name, Integer(health))
19
+ end
20
+
21
+ def name=(new_name)
22
+ @name = new_name.capitalize
23
+ end
24
+
25
+ def score
26
+ @health + points
27
+ end
28
+
29
+ def points
30
+ @found_treasures.values.reduce(0, :+)
31
+ end
32
+
33
+ def each_found_treasure
34
+ @found_treasures.each do |name, points|
35
+ yield Treasure.new(name, points)
36
+ end
37
+ end
38
+
39
+ def found_treasure(treasure)
40
+ @found_treasures[treasure.name] += treasure.points
41
+ puts "#{@name} found a #{treasure.name} worth #{treasure.points} points."
42
+ puts "#{@name}'s treasures: #{@found_treasures}"
43
+ end
44
+
45
+ def to_s
46
+ "I'm #{@name} with health = #{@health}, points = #{points}, and score = #{score}."
47
+ end
48
+
49
+ def time
50
+ current_time = Time.new
51
+ current_time.strftime('%H:%M:%S')
52
+ end
53
+
54
+ def <=>(other)
55
+ # TODO: Why don't I need the at-sign here to reference the health of this player?
56
+ # other.health <=> @health
57
+ other.health <=> health
58
+ end
59
+ end
60
+ end
61
+
62
+ if __FILE__ == $PROGRAM_NAME
63
+ player = StudioGame::Player.new('moe')
64
+ puts player.name
65
+ puts player.health
66
+ player.w00t
67
+ puts player.health
68
+ player.blam
69
+ puts player.health
70
+ end
@@ -0,0 +1,34 @@
1
+ module StudioGame
2
+ Treasure = Struct.new(:name, :points)
3
+
4
+ module TreasureTrove
5
+ TREASURES = [
6
+ Treasure.new(:pie, 5),
7
+ Treasure.new(:bottle, 25),
8
+ Treasure.new(:hammer, 50),
9
+ Treasure.new(:skillet, 100),
10
+ Treasure.new(:broomstick, 200),
11
+ Treasure.new(:crowbar, 400)
12
+ ]
13
+
14
+ def self.random
15
+ TREASURES.sample
16
+ end
17
+ end
18
+ end
19
+
20
+ if __FILE__ == $PROGRAM_NAME
21
+ # I want to see how numeric types are converted
22
+ # Please see the found_treasure method in ClumsyPlayer
23
+ treasure_one = StudioGame::Treasure.new('one', 1)
24
+ treasure_two = StudioGame::Treasure.new('two', 2.0)
25
+
26
+ puts treasure_one.points.class
27
+ puts treasure_two.points.class
28
+
29
+ treasure_one = StudioGame::Treasure.new('one', 1/1)
30
+ treasure_two = StudioGame::Treasure.new('two', 2/1.0)
31
+
32
+ puts treasure_one.points.class
33
+ puts treasure_two.points.class
34
+ end
@@ -0,0 +1,45 @@
1
+ require 'studio_game/berserk_player'
2
+
3
+ module StudioGame
4
+ describe BerserkPlayer do
5
+ before do
6
+ # Hide console output
7
+ $stdout = StringIO.new
8
+
9
+ @initial_health = 100
10
+ @player = BerserkPlayer.new("berserker", @initial_health)
11
+ end
12
+
13
+ it "goes berserk after six w00ts" do
14
+ 5.times { @player.w00t }
15
+ @player.blam
16
+
17
+ current_health = @initial_health + (5 * 15) - 10
18
+ expect(@player.health).to eq(current_health)
19
+
20
+ @player.w00t
21
+ @player.blam
22
+
23
+ expect(@player.health).to eq(current_health + (2 * 15))
24
+ end
25
+
26
+ it "does not go berserk when w00ted up to 5 times" do
27
+ 1.upto(5) { @player.w00t }
28
+
29
+ expect(@player.berserk?).to be_falsey
30
+ end
31
+
32
+ it "goes berserk when w00ted more than 5 times" do
33
+ 1.upto(6) { @player.w00t }
34
+
35
+ expect(@player.berserk?).to be_truthy
36
+ end
37
+
38
+ it "gets w00ted instead of blammed when it's gone berserk" do
39
+ 1.upto(6) { @player.w00t }
40
+ 1.upto(2) { @player.blam }
41
+
42
+ expect(@player.health).to eq(@initial_health + (8 * 15))
43
+ end
44
+ end
45
+ end
@@ -0,0 +1,57 @@
1
+ require 'studio_game/clumsy_player'
2
+
3
+ module StudioGame
4
+ describe ClumsyPlayer do
5
+ before do
6
+ # Hide console output
7
+ $stdout = StringIO.new
8
+
9
+ @player = ClumsyPlayer.new("klutz")
10
+ end
11
+
12
+ it "only gets half the point value for each treasure" do
13
+ expect(@player.points).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.points).to eq(75)
21
+
22
+ crowbar = Treasure.new(:crowbar, 400)
23
+ @player.found_treasure(crowbar)
24
+
25
+ expect(@player.points).to eq(275)
26
+
27
+ yielded = []
28
+ @player.each_found_treasure do |treasure|
29
+ yielded << treasure
30
+ end
31
+
32
+ expect(yielded).to eq([Treasure.new(:hammer, 75), Treasure.new(:crowbar, 200)])
33
+ end
34
+
35
+ context "with a boost factor" do
36
+ before do
37
+ # Hide console output
38
+ $stdout = StringIO.new
39
+
40
+ @boost_factor = 3
41
+ @initial_health = 100
42
+ @player = ClumsyPlayer.new("klutz", @initial_health, @boost_factor)
43
+ end
44
+
45
+ it "has a boost factor" do
46
+ expect(@player.boost_factor).to eq(@boost_factor)
47
+ end
48
+
49
+ it "gets boost factor number of w00ts when w00ted" do
50
+ @player.w00t
51
+
52
+ expect(@player.health).to eq(@initial_health + (15 * @boost_factor))
53
+ end
54
+ end
55
+
56
+ end
57
+ end
@@ -0,0 +1,90 @@
1
+ require 'studio_game/game'
2
+
3
+ module StudioGame
4
+ describe Game do
5
+ before do
6
+ $stdout = StringIO.new
7
+
8
+ @game = Game.new('Knuckleheads')
9
+
10
+ @initial_health = 100
11
+ @player = Player.new('moe', @initial_health)
12
+
13
+ @game.add_player(@player)
14
+ end
15
+
16
+ it 'w00ts the player if a high number is rolled' do
17
+ allow_any_instance_of(Die).to receive(:roll).and_return(5)
18
+
19
+ @game.play(2)
20
+
21
+ expect(@player.health).to eq(@initial_health + (15 * 2))
22
+ end
23
+
24
+ it 'skips the player if a medium number is rolled' do
25
+ allow_any_instance_of(Die).to receive(:roll).and_return(3)
26
+
27
+ @game.play(2)
28
+
29
+ expect(@player.health).to eq(@initial_health)
30
+ end
31
+
32
+ it 'blams the player if a low number is rolled' do
33
+ allow_any_instance_of(Die).to receive(:roll).and_return(1)
34
+
35
+ @game.play(2)
36
+
37
+ expect(@player.health).to eq(@initial_health - (10 * 2))
38
+ end
39
+
40
+ it 'plays a number of rounds' do
41
+ # FIXME: It appears I added this as my own "extra credit". What should I do? Should I leave it?
42
+ # 👇 This does not work
43
+ allow_any_instance_of(Die).to receive(:roll).and_return(1, 3, 5)
44
+ # allow_any_instance_of(Die).to receive(:roll).and_return(1)
45
+ # allow_any_instance_of(Die).to receive(:roll).and_return(3)
46
+ # allow_any_instance_of(Die).to receive(:roll).and_return(5)
47
+
48
+ # The reason is around the allow_any_instance_of works on a call
49
+ # and not an instance, so effectively it seems to only be able to utilize the first
50
+ # value in the and_return. Is there a way to spy upon the GameTurn module to find and
51
+ # wrap, or something like it, its use of the Die class?
52
+ #
53
+ # https://rspec.info/documentation/3.10/rspec-mocks/#settings-mocks-or-stubs-on-any-instance-of-a-class
54
+ # https://rubydoc.info/gems/rspec-mocks/3.10.2/RSpec/Mocks/MessageExpectation#and_return-instance_method
55
+
56
+ @game.play(3)
57
+
58
+ # 👇 should be the result
59
+ # expect(@player.health).to eq(@initial_health + 5)
60
+ expect(@player.health).to eq(@initial_health - (3 * 10))
61
+ end
62
+
63
+ it "assigns a treasure for points during a player's turn" do
64
+ game = Game.new("Knuckleheads")
65
+ player = Player.new("moe")
66
+
67
+ game.add_player(player)
68
+
69
+ game.play(1)
70
+
71
+ expect(player.points).not_to be_zero
72
+ end
73
+
74
+ it "computes total points as the sum of all player points" do
75
+ game = Game.new("Knuckleheads")
76
+
77
+ player1 = Player.new("moe")
78
+ player2 = Player.new("larry")
79
+
80
+ game.add_player(player1)
81
+ game.add_player(player2)
82
+
83
+ player1.found_treasure(Treasure.new(:hammer, 50))
84
+ player1.found_treasure(Treasure.new(:hammer, 50))
85
+ player2.found_treasure(Treasure.new(:crowbar, 400))
86
+
87
+ expect(game.total_points).to eq(500)
88
+ end
89
+ end
90
+ end
@@ -0,0 +1,119 @@
1
+ require 'studio_game/player'
2
+ require 'studio_game/treasure_trove'
3
+
4
+ module StudioGame
5
+ describe Player do
6
+ before do
7
+ $stdout = StringIO.new
8
+
9
+ @name = 'larry'
10
+ @initial_health = 150
11
+ @player = Player.new(@name, @initial_health)
12
+ end
13
+
14
+ it 'creates a Player from a CSV string' do
15
+ player = Player.from_csv('Megan,150')
16
+
17
+ expect(player.name).to eq('Megan')
18
+ expect(player.health).to eq(150)
19
+ end
20
+
21
+ it 'has a capitalized name' do
22
+ expect(@player.name).to eq(@name.capitalize)
23
+ end
24
+
25
+ it 'has an initial health' do
26
+ expect(@player.health).to eq(@initial_health)
27
+ end
28
+
29
+ it 'has a string representation' do
30
+ @player.found_treasure(Treasure.new(:hammer, 50))
31
+ @player.found_treasure(Treasure.new(:hammer, 50))
32
+
33
+ expect(@player.to_s).to eq("I'm Larry with health = 150, points = 100, and score = 250.")
34
+ end
35
+
36
+ it "computes a score as the sum of its health and points" do
37
+ @player.found_treasure(Treasure.new(:hammer, 50))
38
+ @player.found_treasure(Treasure.new(:hammer, 50))
39
+
40
+ expect(@player.score).to eq(250)
41
+ end
42
+
43
+ it 'increases health by 15 when w00ted' do
44
+ @player.w00t
45
+
46
+ expect(@player.health).to eq(@initial_health + 15)
47
+ end
48
+
49
+ it 'decreases health by 10 when blammed' do
50
+ @player.blam
51
+
52
+ expect(@player.health).to eq(@initial_health - 10)
53
+ end
54
+
55
+ context 'with a health greater than 100' do
56
+ it 'is strong' do
57
+ player = Player.new('Someone', 150)
58
+ expect(player).to be_strong
59
+ end
60
+ end
61
+
62
+ context 'with a health of 100 or less' do
63
+ it 'is whimpy' do
64
+ player = Player.new('Someone', 100)
65
+ expect(player).not_to be_strong
66
+ end
67
+ end
68
+
69
+ context "in a collection of players" do
70
+ before do
71
+ @player1 = Player.new("moe", 100)
72
+ @player2 = Player.new("larry", 200)
73
+ @player3 = Player.new("curly", 300)
74
+
75
+ @players = [@player1, @player2, @player3]
76
+ end
77
+
78
+ it "is sorted by decreasing score" do
79
+ # @players.sort.should == [@player3, @player2, @player1]
80
+ expect(@players.sort).to eq([@player3, @player2, @player1])
81
+ end
82
+ end
83
+
84
+ it "computes points as the sum of all treasure points" do
85
+ expect(@player.points).to eq(0)
86
+
87
+ @player.found_treasure(Treasure.new(:hammer, 50))
88
+ expect(@player.points).to eq(50)
89
+
90
+ @player.found_treasure(Treasure.new(:crowbar, 400))
91
+ expect(@player.points).to eq(450)
92
+
93
+ @player.found_treasure(Treasure.new(:hammer, 50))
94
+ expect(@player.points).to eq(500)
95
+ end
96
+
97
+ it "yields each found treasure and its total points" do
98
+ @player.found_treasure(Treasure.new(:skillet, 100))
99
+ @player.found_treasure(Treasure.new(:skillet, 100))
100
+ @player.found_treasure(Treasure.new(:hammer, 50))
101
+ @player.found_treasure(Treasure.new(:bottle, 5))
102
+ @player.found_treasure(Treasure.new(:bottle, 5))
103
+ @player.found_treasure(Treasure.new(:bottle, 5))
104
+ @player.found_treasure(Treasure.new(:bottle, 5))
105
+ @player.found_treasure(Treasure.new(:bottle, 5))
106
+
107
+ yielded = []
108
+ @player.each_found_treasure do |treasure|
109
+ yielded << treasure
110
+ end
111
+
112
+ expect(yielded).to eq([
113
+ Treasure.new(:skillet, 200),
114
+ Treasure.new(:hammer, 50),
115
+ Treasure.new(:bottle, 25)
116
+ ])
117
+ end
118
+ end
119
+ end
@@ -0,0 +1,57 @@
1
+ require 'studio_game/treasure_trove'
2
+
3
+ module StudioGame
4
+ describe Treasure do
5
+
6
+ before do
7
+ @treasure = Treasure.new(:hammer, 50)
8
+ end
9
+
10
+ it "has a name attribute" do
11
+ expect(@treasure.name).to eq(:hammer)
12
+ end
13
+
14
+ it "has a points attribute" do
15
+ expect(@treasure.points).to eq(50)
16
+ end
17
+
18
+ end
19
+
20
+ describe TreasureTrove do
21
+
22
+ it "has six treasures" do
23
+ expect(TreasureTrove::TREASURES.size).to eq(6)
24
+ end
25
+
26
+ it "has a pie worth 5 points" do
27
+ expect(TreasureTrove::TREASURES[0]).to eq(Treasure.new(:pie, 5))
28
+ end
29
+
30
+ it "has a bottle worth 25 points" do
31
+ expect(TreasureTrove::TREASURES[1]).to eq(Treasure.new(:bottle, 25))
32
+ end
33
+
34
+ it "has a hammer worth 50 points" do
35
+ expect(TreasureTrove::TREASURES[2]).to eq(Treasure.new(:hammer, 50))
36
+ end
37
+
38
+ it "has a skillet worth 100 points" do
39
+ expect(TreasureTrove::TREASURES[3]).to eq(Treasure.new(:skillet, 100))
40
+ end
41
+
42
+ it "has a broomstick worth 200 points" do
43
+ expect(TreasureTrove::TREASURES[4]).to eq(Treasure.new(:broomstick, 200))
44
+ end
45
+
46
+ it "has a crowbar worth 400 points" do
47
+ expect(TreasureTrove::TREASURES[5]).to eq(Treasure.new(:crowbar, 400))
48
+ end
49
+
50
+ it "returns a random treasure" do
51
+ treasure = TreasureTrove.random
52
+
53
+ expect(TreasureTrove::TREASURES).to include(treasure)
54
+ end
55
+
56
+ end
57
+ end
metadata ADDED
@@ -0,0 +1,89 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: studio_game_michaelwestphal
3
+ version: !ruby/object:Gem::Version
4
+ version: 1.0.0
5
+ platform: ruby
6
+ authors:
7
+ - Michael Westphal
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2022-12-30 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: '3.10'
20
+ - - ">="
21
+ - !ruby/object:Gem::Version
22
+ version: 3.10.0
23
+ type: :development
24
+ prerelease: false
25
+ version_requirements: !ruby/object:Gem::Requirement
26
+ requirements:
27
+ - - "~>"
28
+ - !ruby/object:Gem::Version
29
+ version: '3.10'
30
+ - - ">="
31
+ - !ruby/object:Gem::Version
32
+ version: 3.10.0
33
+ description: "# Studio Game\n\nThe Studio Game developed while taking the [Ruby Programming
34
+ course](https://pragmaticstudio.com/courses/ruby) from the [Pragmatic Studio](https://pragmaticstudio.com/).\n\n\U0001F4DA
35
+ **[My Pragmatic Studio alumni page](https://pragmaticstudio.com/alumni/michaelwestphal)**\n"
36
+ email: michaelwestphal@hey.com
37
+ executables:
38
+ - studio_game
39
+ extensions: []
40
+ extra_rdoc_files: []
41
+ files:
42
+ - LICENSE
43
+ - README
44
+ - bin/players.csv
45
+ - bin/studio_game
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_turn.rb
52
+ - lib/studio_game/loaded_die.rb
53
+ - lib/studio_game/playable.rb
54
+ - lib/studio_game/player.rb
55
+ - lib/studio_game/treasure_trove.rb
56
+ - spec/studio_game/berserk_player_spec.rb
57
+ - spec/studio_game/clumsy_player_spec.rb
58
+ - spec/studio_game/game_spec.rb
59
+ - spec/studio_game/player_spec.rb
60
+ - spec/studio_game/treasure_trove_spec.rb
61
+ homepage: https://github.com/michaelwestphal/ruby-studio-game
62
+ licenses:
63
+ - MIT
64
+ metadata: {}
65
+ post_install_message:
66
+ rdoc_options: []
67
+ require_paths:
68
+ - lib
69
+ required_ruby_version: !ruby/object:Gem::Requirement
70
+ requirements:
71
+ - - ">="
72
+ - !ruby/object:Gem::Version
73
+ version: '3.0'
74
+ required_rubygems_version: !ruby/object:Gem::Requirement
75
+ requirements:
76
+ - - ">="
77
+ - !ruby/object:Gem::Version
78
+ version: '0'
79
+ requirements: []
80
+ rubygems_version: 3.3.7
81
+ signing_key:
82
+ specification_version: 4
83
+ summary: Studio Game from Pragmatic Studio Ruby course
84
+ test_files:
85
+ - spec/studio_game/berserk_player_spec.rb
86
+ - spec/studio_game/clumsy_player_spec.rb
87
+ - spec/studio_game/game_spec.rb
88
+ - spec/studio_game/player_spec.rb
89
+ - spec/studio_game/treasure_trove_spec.rb