studio-game-sebastian 2.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: d2152bf323c937bb74630cbf242f906502ac85235d52701263f69080a5609ba3
4
+ data.tar.gz: 9483004672dddd045ba45fd2181c62382ed38740ea102219dd5ec62bc44c76ad
5
+ SHA512:
6
+ metadata.gz: c7041714964d0c337deee20f389a7231004358f9636eaaf340b38541b7e3c509ac8d87427f445f6b5be09ca91f63012af759d4fada0d2bbbba2ad3b0843d2097
7
+ data.tar.gz: 1b8e926e14576d477a5333e2999ef23f0dd7a0ae147e52ae56341ef977c2ba1f4ed6b60aca8e0e822fc01a018e8162827d3cad303467364ad713c8bac8c1aab2
data/LICENSE.txt ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2024 Sebastian Alvarado
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,12 @@
1
+ # Flicks
2
+
3
+ A command-line movie playlist manager written in Ruby.
4
+
5
+ ## Description
6
+
7
+ Flicks is a simple CLI application that allows you to create and manage movie playlists. You can load movies from a CSV file, play them a specified number of times, and track movie ratings and viewing statistics.
8
+
9
+ ## Installation
10
+
11
+ Install the gem:
12
+
data/bin/flicks ADDED
@@ -0,0 +1,37 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ # Import relative classes
4
+ require_relative "../lib/flicks/playlist"
5
+
6
+
7
+ # movies = [Movie.new("titanic", 10), Movie.new("spacejam", 2), Movie.new("ghostbusters", 8)]
8
+ playlist = Flicks::Playlist.new("Kermit")
9
+ movies_file = File.join(__dir__, "movies.csv")
10
+
11
+ # Read the filename from cli
12
+ playlist.load(ARGV.shift || movies_file)
13
+
14
+ # Main program
15
+
16
+ loop do
17
+ print "\nHow many viewings? ('quit' or 'exit') "
18
+ answer = gets.chomp.downcase
19
+ case answer
20
+ when /^\d+$/ #digit
21
+ playlist.play(answer.to_i)
22
+ when "quit", "exit"
23
+ break
24
+ else
25
+ puts "Please enter a number or quit"
26
+ end
27
+ end
28
+
29
+ playlist.save
30
+ playlist.print_stats
31
+ # Arrays
32
+ # seats = %w[kermit ozzie gonzo] # Creates an array of strings
33
+ # seats << "animal" # append operator
34
+ # seats.shift # return the first element of the array
35
+ # seats.compact! # remove all nulls from the array (in place)
36
+ # seats.sample # pick a random element
37
+
data/bin/movies.csv ADDED
@@ -0,0 +1,3 @@
1
+ Arrival,10
2
+ Titanic,20
3
+ Spacejam,4
data/bin/players.csv ADDED
@@ -0,0 +1,10 @@
1
+ John Smith,75
2
+ Sarah Johnson,82
3
+ Michael Williams,45
4
+ Emma Davis,93
5
+ James Wilson,67
6
+ Olivia Brown,88
7
+ William Taylor,51
8
+ Sophia Martinez,79
9
+ Daniel Anderson,60
10
+ Isabella Thomas,95
data/bin/studio_game ADDED
@@ -0,0 +1,31 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require_relative "../lib/studio_game/game"
4
+ require_relative "../lib/studio_game/player"
5
+ require_relative "../lib/studio_game/berkser_player"
6
+ require_relative "../lib/studio_game/clumsy_player"
7
+
8
+
9
+ game = StudioGame::Game.new("NBA")
10
+ # There is also a CSV class we can use
11
+ file_name = File.join(__dir__, "players.csv")
12
+ game.load_players(ARGV.shift || file_name)
13
+ game.add_player(StudioGame::BerserkPlayer.new("berseker", 50))
14
+ game.add_player(StudioGame::ClumsyPlayer.new("clumsy", 100))
15
+ # Main program
16
+ loop do
17
+ print "\nHow many rounds ('quit' or 'exit') "
18
+ answer = gets.chomp.downcase
19
+ case answer
20
+ when /^\d+$/ #digit
21
+ game.play(answer.to_i)
22
+ when "quit", "exit"
23
+ break
24
+ else
25
+ puts "Please enter a number or quit"
26
+ end
27
+ end
28
+
29
+ # Results
30
+ game.print_stats()
31
+ game.save_scores()
@@ -0,0 +1,42 @@
1
+ require_relative "rankable"
2
+
3
+ module Flicks
4
+ class Movie
5
+ attr_reader :title, :rank, :snacks_eaten # setting a getter method
6
+ attr_accessor :title, :rank # setting a setter method
7
+
8
+ include Rankable # this is a mixin
9
+
10
+ def initialize(title, rank = 10)
11
+ @title = title.capitalize
12
+ @rank = rank
13
+ @snacks_eaten = Hash.new(0)
14
+ end
15
+
16
+ def add_snack(name, price)
17
+ @snacks_eaten[name] += price
18
+ end
19
+ def total_snack_price
20
+ @snacks_eaten.values.sum
21
+ end
22
+ def to_s = "#{@title} has a rank of #{@rank}"
23
+ def self.from_csv(line) #class method
24
+ title, rank = line.split(",")
25
+ Movie.new(title, Integer(rank))
26
+ rescue ArgumentError
27
+ puts "Ignored invalid rank: #{rank}"
28
+ Movie.new(title)
29
+ end
30
+ def to_csv
31
+ "#{@title},#{@rank}"
32
+ end
33
+
34
+ end
35
+ end
36
+
37
+ # __FILE__ is a special variable that holds the filename
38
+ # $0 is the name of the ruby file executing from the CLI
39
+ if __FILE__ ==$0
40
+ m = Movie.new('Titanic', 10)
41
+ puts m
42
+ end
@@ -0,0 +1,27 @@
1
+ require_relative "movie"
2
+
3
+ module Flicks
4
+ class Movie3D < Movie
5
+ def initialize(title, rank, wow_factor)
6
+ super(title, rank)
7
+ @wow_factor = wow_factor
8
+ end
9
+ def show_effect
10
+ puts "Wow!" * @wow_factor
11
+ end
12
+ def thumbs_up
13
+ @rank += (1 * @wow_factor)
14
+ end
15
+ end
16
+ end
17
+
18
+ if __FILE__ == $0
19
+ movie3d = Movie3D.new("godzilla", 7, 10)
20
+ puts movie3d.title
21
+ puts movie3d.rank
22
+ movie3d.thumbs_up
23
+ puts movie3d.rank
24
+ movie3d.show_effect
25
+ puts Movie3D.superclass
26
+ p Movie3D.ancestors
27
+ end
@@ -0,0 +1,74 @@
1
+ require_relative "snackbar"
2
+ require_relative "movie"
3
+
4
+ module Flicks
5
+ class Playlist
6
+ attr_reader :name, :movies
7
+
8
+ def initialize(name)
9
+ @name = name
10
+ @movies = []
11
+ end
12
+ def load(filename)
13
+ File.readlines(filename, chomp: true).each do |line|
14
+ add_movie(Movie.from_csv(line))
15
+ end
16
+ rescue Errno::ENOENT
17
+ puts "Whoops, #{filename} not found!"
18
+ exit 1
19
+ end
20
+ def save(to_file = "movie_rankings.csv")
21
+ File.open(to_file, "w") do |file|
22
+ sorted_movies.each do |movie|
23
+ file.puts movie.to_csv
24
+ end
25
+ end
26
+ end
27
+ def add_movie(movie)
28
+ @movies.append(movie)
29
+ end
30
+ def sorted_movies
31
+ @movies.sort_by { |movie| movie.rank}.reverse
32
+ end
33
+ def print_stats
34
+ puts "\n #{@name}'s Playlist Stats:"
35
+ puts "-" * 30
36
+ puts sorted_movies
37
+ @movies.each do |movie|
38
+ puts "\n#{movie.title} snack totals"
39
+ movie.snacks_eaten.each do |name, t_price|
40
+ puts "#{name}: $#{t_price}"
41
+ end
42
+ puts "total: $#{movie.total_snack_price}"
43
+ end
44
+ end
45
+ def roll_die
46
+ rand(1..6)
47
+ end
48
+ def play(viewings = 1)
49
+ puts "*" * 30
50
+ puts "#{@name}'s playlist"
51
+ puts "\nThe snackbar has:"
52
+ puts Snackbar.menu_items
53
+
54
+ 1.upto(viewings) do |viewing|
55
+ @movies.each do |movie|
56
+ number_rolled = roll_die
57
+ case number_rolled
58
+ when 1..2
59
+ movie.thumbs_down
60
+ puts "#{movie.title} got a 👎"
61
+ when 3..4
62
+ puts "#{movie.title} got skipped"
63
+ else
64
+ movie.thumbs_up
65
+ puts "#{movie.title} got a 👍"
66
+ end
67
+ random_snack = Snackbar.random_snack
68
+ movie.add_snack(random_snack.name, random_snack.price)
69
+ puts "During #{movie.title}, #{@name} ate #{random_snack.name} for $#{random_snack.price}."
70
+ end
71
+ end
72
+ end
73
+ end
74
+ end
@@ -0,0 +1,14 @@
1
+
2
+ # Encapsulating logic into a module
3
+ # It is better practice that the module not access the instance variables directly
4
+ # We can mix this module in different classes, not needing to have inheritance
5
+ module Flicks
6
+ module Rankable
7
+ def thumbs_down
8
+ self.rank -= 1
9
+ end
10
+ def thumbs_up
11
+ self.rank += 1
12
+ end
13
+ end
14
+ end
@@ -0,0 +1,14 @@
1
+ module Snackbar
2
+ Snack = Data.define(:name, :price)
3
+ SNACKS = [
4
+ Snack.new("popcorn", 3),
5
+ Snack.new("nachos", 20),
6
+ Snack.new("soda", 5)
7
+ ]
8
+ def self.random_snack # This is a module method (like static)
9
+ SNACKS.sample
10
+ end
11
+ def self.menu_items
12
+ SNACKS.map { |snack| "#{snack.name} for $#{snack.price}" }
13
+ end
14
+ end
@@ -0,0 +1,7 @@
1
+ module StudioGame
2
+ module Auditable
3
+ def audit(number)
4
+ puts "Audit: Rolled a #{number}"
5
+ end
6
+ end
7
+ end
@@ -0,0 +1,30 @@
1
+ require_relative "player"
2
+
3
+ module StudioGame
4
+ class BerserkPlayer < Player
5
+ def initialize(name, health = 100)
6
+ super(name, health)
7
+ @boost_count = 0
8
+ end
9
+ def boost
10
+ @health += 15
11
+ @boost_count += 1
12
+ puts "#{@name} is berserk!" if berserk?
13
+ end
14
+ def berserk?
15
+ @boost_count > 5
16
+ end
17
+ def drain
18
+ # When calling just super, it calls the same method in the parent class
19
+ berserk? ? boost : super
20
+ end
21
+ end
22
+ end
23
+
24
+
25
+ if __FILE__ == $0
26
+ berserker = BerserkPlayer.new("berserker", 50)
27
+ 6.times { berserker.boost }
28
+ 2.times { berserker.drain }
29
+ puts berserker.health
30
+ end
@@ -0,0 +1,34 @@
1
+ require_relative "player"
2
+
3
+ module StudioGame
4
+ class ClumsyPlayer < Player
5
+ def initialize(name, health = 50, boost_factor = 1)
6
+ super(name, health)
7
+ @boost_factor = boost_factor
8
+ end
9
+ def found_treasure(name, points)
10
+ points = points / 2.0
11
+ super.found_treasure(name, points)
12
+ end
13
+ def boost
14
+ @boost_factor.times { super }
15
+ end
16
+ end
17
+ end
18
+
19
+
20
+ if __FILE__ === $0
21
+ clumsy = ClumsyPlayer.new("klutz")
22
+
23
+ clumsy.add_treasure("flute", 50)
24
+ clumsy.add_treasure("flute", 50)
25
+ clumsy.add_treasure("flute", 50)
26
+ clumsy.add_treasure("star", 100)
27
+
28
+ clumsy.found_treasures.each do |name, points|
29
+ puts "#{name}: #{points} points"
30
+ end
31
+ puts "#{clumsy.points} total points"
32
+ clumsy.boost
33
+ puts "#{clumsy.points} total points"
34
+ end
@@ -0,0 +1,93 @@
1
+ require_relative "treasure_trove"
2
+ require_relative "player"
3
+ require_relative "auditable"
4
+
5
+ module StudioGame
6
+ class Game
7
+ attr_reader :name, :players
8
+
9
+ include Auditable
10
+
11
+ def initialize(name)
12
+ @name = name.capitalize
13
+ @players = []
14
+ @sorted_players = []
15
+ end
16
+ def load_players(filename="players.csv")
17
+ if File.exist?(filename)
18
+ File.readlines(filename, chomp: true).each do |line|
19
+ next if line.empty?
20
+ add_player(Player.from_csv(line))
21
+ end
22
+ else
23
+ puts "Whoops, #{filename} not found!"
24
+ exit 1
25
+ end
26
+ rescue Errno::ENOENT
27
+ puts "Whoops, file #{filename} does not exist"
28
+ exit 1
29
+ end
30
+ def save_scores(to_filename="game_scores.txt")
31
+ File.open(to_filename, "w") do |file|
32
+ file.puts "#{name} Scores:"
33
+ @sorted_players.each do |player|
34
+ file.puts player.print_score
35
+ end
36
+ end
37
+ end
38
+ def add_player(player)
39
+ @players << player
40
+ end
41
+ def roll_die
42
+ value = rand(1..6)
43
+ # value = [1,1,2,5,6,6].sample -> Rigged die
44
+ audit(value)
45
+ value
46
+ end
47
+ def play(rounds)
48
+ puts "\nAvailable Treasures to find\n"
49
+ puts TreasureTrove.treasure_items
50
+
51
+ # Play the game for rounds
52
+ 1.upto(rounds) do |time|
53
+ puts "\nRound #{time} " + "*" * 30
54
+ @players.each do |player|
55
+ number_rolled = roll_die
56
+ case number_rolled
57
+ when 1..2
58
+ puts "#{player.name} got drained 😔"
59
+ player.drain
60
+ when 3..5
61
+ puts "#{player.name} got skipped"
62
+ else
63
+ puts "#{player.name} got boosted 😀"
64
+ player.boost
65
+ end
66
+ random_treasure = TreasureTrove::random_treasure
67
+ player.add_treasure(random_treasure.name, random_treasure.points)
68
+ puts "#{@name} found a #{random_treasure.name} worth #{random_treasure.points} points"
69
+ end
70
+ end
71
+ @sorted_players = @players.sort_by {|p| p.score}.reverse
72
+ end
73
+ def print_stats(max_high_scores=5)
74
+ puts "#{@name} Game Stats"
75
+ puts "-" * 50
76
+ # Print each player (sorted by score)
77
+ puts @sorted_players
78
+ # Print treasures for each player
79
+ @players.each do |player|
80
+ puts "\n#{player.name}'s treasure point totals:"
81
+ player.found_treasures.each do |name, points|
82
+ puts "#{name}: #{points}\n"
83
+ end
84
+ end
85
+
86
+ # Print high scores
87
+ puts "\nHigh Scores:"
88
+ @sorted_players.each do |player|
89
+ puts player.print_score
90
+ end
91
+ end
92
+ end
93
+ end
@@ -0,0 +1,10 @@
1
+ module StudioGame
2
+ module Playable
3
+ def boost
4
+ self.health += 15
5
+ end
6
+ def drain
7
+ self.health -= 10
8
+ end
9
+ end
10
+ end
@@ -0,0 +1,60 @@
1
+ require_relative "playable"
2
+
3
+ module StudioGame
4
+ class Player
5
+ attr_reader :found_treasures
6
+ attr_accessor :name, :health
7
+ include Playable
8
+
9
+ def initialize(name, health = 0)
10
+ # @name = name.split(" ").map { |word| word.capitalize }.join(" ")
11
+ @name = name.gsub(/\w+/) { |word| word.capitalize }
12
+ @health = health
13
+ @found_treasures = Hash.new(0)
14
+ end
15
+
16
+ # Here we are overriding the default setter method sot hat we capitalize it
17
+ def name=(new_name)
18
+ @name = new_name.gsub(/\w+/) { |word| word.capitalize }
19
+ end
20
+
21
+ def add_treasure(name, points)
22
+ @found_treasures[name] += points
23
+ end
24
+
25
+ def self.from_csv(line)
26
+ name, health = line.split(",")
27
+ health_value = Integer(health) rescue 40
28
+ Player.new(name, health_value)
29
+ rescue ArgumentError
30
+ puts "Skipping player #{name} for invalid health value"
31
+ Player.new(name)
32
+ end
33
+
34
+ def to_s = "I'm #{@name} with a health=#{@health}, points=#{@found_treasures.values.sum} and score=#{score}"
35
+
36
+
37
+ def print_score
38
+ name = @name.ljust(20, '.')
39
+ points = self.score.round.to_s.rjust(5)
40
+ "#{name}#{points}"
41
+ end
42
+ def score
43
+ treasure_points = @found_treasures.values.sum
44
+ @health + treasure_points
45
+ end
46
+ def points
47
+ @found_treasures.values.sum
48
+ end
49
+ end
50
+ end
51
+
52
+
53
+ if __FILE__ == $0
54
+ player = Player.new("Durant")
55
+ puts player.name
56
+ puts player.health
57
+ player.boost
58
+ puts player.health
59
+ player.drain
60
+ end
@@ -0,0 +1,20 @@
1
+ module StudioGame
2
+ module TreasureTrove
3
+ Treasure = Data.define(:name, :points)
4
+ TREASURES = [
5
+ Treasure.new("pie", 10),
6
+ Treasure.new("coin", 25),
7
+ Treasure.new("flute", 50),
8
+ Treasure.new("compass", 65),
9
+ Treasure.new("key", 80),
10
+ Treasure.new("crown",90),
11
+ Treasure.new("star", 100),
12
+ ]
13
+ def self.random_treasure
14
+ TREASURES.sample
15
+ end
16
+ def self.treasure_items
17
+ TREASURES.map {|item| "A #{item.name} is worth #{item.points} points"}
18
+ end
19
+ end
20
+ end
metadata ADDED
@@ -0,0 +1,61 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: studio-game-sebastian
3
+ version: !ruby/object:Gem::Version
4
+ version: 2.0.0
5
+ platform: ruby
6
+ authors:
7
+ - Sebastian Alvarado
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2025-05-15 00:00:00.000000000 Z
12
+ dependencies: []
13
+ description:
14
+ email: sebastian@mail.com
15
+ executables:
16
+ - studio_game
17
+ extensions: []
18
+ extra_rdoc_files: []
19
+ files:
20
+ - LICENSE.txt
21
+ - README.md
22
+ - bin/flicks
23
+ - bin/movies.csv
24
+ - bin/players.csv
25
+ - bin/studio_game
26
+ - lib/flicks/movie.rb
27
+ - lib/flicks/movie3d.rb
28
+ - lib/flicks/playlist.rb
29
+ - lib/flicks/rankable.rb
30
+ - lib/flicks/snackbar.rb
31
+ - lib/studio_game/auditable.rb
32
+ - lib/studio_game/berkser_player.rb
33
+ - lib/studio_game/clumsy_player.rb
34
+ - lib/studio_game/game.rb
35
+ - lib/studio_game/playable.rb
36
+ - lib/studio_game/player.rb
37
+ - lib/studio_game/treasure_trove.rb
38
+ homepage:
39
+ licenses:
40
+ - MIT
41
+ metadata: {}
42
+ post_install_message:
43
+ rdoc_options: []
44
+ require_paths:
45
+ - lib
46
+ required_ruby_version: !ruby/object:Gem::Requirement
47
+ requirements:
48
+ - - ">="
49
+ - !ruby/object:Gem::Version
50
+ version: 3.2.0
51
+ required_rubygems_version: !ruby/object:Gem::Requirement
52
+ requirements:
53
+ - - ">="
54
+ - !ruby/object:Gem::Version
55
+ version: '0'
56
+ requirements: []
57
+ rubygems_version: 3.4.10
58
+ signing_key:
59
+ specification_version: 4
60
+ summary: A CLI randomized players
61
+ test_files: []