splendor_game 0.1.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
+ SHA1:
3
+ metadata.gz: 547dab96b270b9680b85697dcfdebf09fac4f8db
4
+ data.tar.gz: 9fbdd1e06feb465f45e47b43018fc0b497a913b0
5
+ SHA512:
6
+ metadata.gz: e63c1ad7284bafc6844d171967b9eeada48d1cc973b0de224531e31a4a9981f14cf22db2d06a16bcc36f190304440b840bdd1b437952432d2fa368b61f8c29a7
7
+ data.tar.gz: 2675112afc9482cb891145bb3a88e32ef96dfe26de643d4ecaba1fd1cb179ae6e3163fbaf9c1091cdf8524268baa23b95d58110234797d2dbe37f74b00e761e1
data/.codeclimate.yml ADDED
@@ -0,0 +1,27 @@
1
+ ---
2
+ engines:
3
+ duplication:
4
+ enabled: true
5
+ config:
6
+ languages:
7
+ ruby:
8
+ mass_threshold: 22
9
+ javascript:
10
+ python:
11
+ php:
12
+ fixme:
13
+ enabled: true
14
+ rubocop:
15
+ enabled: true
16
+ ratings:
17
+ paths:
18
+ - "**.inc"
19
+ - "**.js"
20
+ - "**.jsx"
21
+ - "**.module"
22
+ - "**.php"
23
+ - "**.py"
24
+ - "**.rb"
25
+ exclude_paths:
26
+ - spec/
27
+ - lib/splendor_game/load_cards.rb
data/.gitignore ADDED
@@ -0,0 +1,9 @@
1
+ /.bundle/
2
+ /.yardoc
3
+ /Gemfile.lock
4
+ /_yardoc/
5
+ /coverage/
6
+ /doc/
7
+ /pkg/
8
+ /spec/reports/
9
+ /tmp/
data/.rspec ADDED
@@ -0,0 +1,2 @@
1
+ --format documentation
2
+ --color
data/.travis.yml ADDED
@@ -0,0 +1,5 @@
1
+ sudo: false
2
+ language: ruby
3
+ rvm:
4
+ - 2.2.5
5
+ before_install: gem install bundler -v 1.13.6
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in splendor_game.gemspec
4
+ gemspec
data/LICENSE.txt ADDED
@@ -0,0 +1,21 @@
1
+ The MIT License (MIT)
2
+
3
+ Copyright (c) 2017 reedstonefood
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
13
+ all 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
21
+ THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,35 @@
1
+ # Splendor_game
2
+
3
+ [![Code Climate](https://codeclimate.com/github/reedstonefood/splendor_game/badges/gpa.svg)](https://codeclimate.com/github/reedstonefood/splendor_game)
4
+
5
+ A Ruby implementation of the board game Splendor.
6
+
7
+ Find out more about the game at [BoardGameGeek](https://boardgamegeek.com/boardgame/148228/splendor).
8
+
9
+ ## Installation
10
+
11
+ Not yet ready for use - still in development.
12
+
13
+ ## Usage
14
+
15
+ There is a simple CLI you can use. Simply run the following in irb or put in a .rb file and run it.
16
+
17
+ ```ruby
18
+ require 'splendor_game'
19
+ SplendorGame::CLI.new
20
+ ```
21
+
22
+ Or, hook this up to any front end you might desire to use.
23
+
24
+ ## Contributing
25
+
26
+ Bug reports and pull requests are welcome on GitHub at https://github.com/reedstonefood/splendor_game.
27
+
28
+ ## With thanks...
29
+
30
+ Whoever typed up a list of all the cards in the board game into this spreadsheet... https://drive.google.com/file/d/0B4yyYVH10iE5VlBFME9QelBVUnc/edit
31
+
32
+ ## License
33
+
34
+ The gem is available as open source under the terms of the [MIT License](http://opensource.org/licenses/MIT).
35
+
data/Rakefile ADDED
@@ -0,0 +1,6 @@
1
+ require "bundler/gem_tasks"
2
+ require "rspec/core/rake_task"
3
+
4
+ RSpec::Core::RakeTask.new(:spec)
5
+
6
+ task :default => :spec
data/bin/console ADDED
@@ -0,0 +1,14 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require "bundler/setup"
4
+ require "splendor_game"
5
+
6
+ # You can add fixtures and/or initialization code here to make experimenting
7
+ # with your gem easier. You can also use a different console, if you like.
8
+
9
+ # (If you use this, don't forget to add pry to your Gemfile!)
10
+ # require "pry"
11
+ # Pry.start
12
+
13
+ require "irb"
14
+ IRB.start
data/bin/setup ADDED
@@ -0,0 +1,8 @@
1
+ #!/usr/bin/env bash
2
+ set -euo pipefail
3
+ IFS=$'\n\t'
4
+ set -vx
5
+
6
+ bundle install
7
+
8
+ # Do any other automated setup that you need to do here
@@ -0,0 +1,23 @@
1
+ require "splendor_game/version"
2
+ require "splendor_game/options"
3
+ require "splendor_game/coloured_object"
4
+ require "splendor_game/card"
5
+ require "splendor_game/noble"
6
+ require "splendor_game/tableau"
7
+ require "splendor_game/player"
8
+ require "splendor_game/turn"
9
+ require "splendor_game/load_cards"
10
+ require "splendor_game/game"
11
+ require "splendor_game/cli"
12
+
13
+ module SplendorGame
14
+ # This is to validate when loading cards
15
+ VALID_COLOUR_LIST = ["RED", "BLUE", "BLACK", "GREEN", "WHITE"]
16
+ # This is used to validate certain calls
17
+ VALID_COLOUR_SYMBOLS = VALID_COLOUR_LIST.map { |x| x.downcase.to_sym }
18
+ # Note gold is a special colour so shouldn't be in VALID_COLOUR_LIST
19
+ VALID_COLOUR_SYMBOLS << :gold
20
+
21
+ MAX_PLAYER_COUNT = 4
22
+ MIN_PLAYER_COUNT = 2
23
+ end
@@ -0,0 +1,24 @@
1
+ module SplendorGame
2
+
3
+ class Card < ColouredObject
4
+ attr_reader :level, :points, :colour, :cost
5
+
6
+ def initialize(level, colour, cost, points = 0)
7
+ @level = level
8
+ @points = points
9
+ @colour = colour
10
+ @cost, @cost_error = Hash.new(), Hash.new()
11
+ # if the colour is valid, load it, if not, put it in an error hash
12
+ cost.each do |key, value|
13
+ new_key_name = validate_colour(key)
14
+ if new_key_name==false
15
+ @cost_error[key] = value
16
+ else
17
+ @cost[new_key_name] = value
18
+ end
19
+ end
20
+ end
21
+
22
+ end
23
+
24
+ end
@@ -0,0 +1,255 @@
1
+ require 'highline'
2
+
3
+ module SplendorGame
4
+
5
+ class CLI
6
+ @@cli = HighLine.new
7
+ attr_reader :level, :points, :colour, :cost
8
+
9
+ def initialize
10
+ @g = SplendorGame::Game.new Hash[*ARGV]
11
+ choose_players
12
+ main
13
+ end
14
+
15
+ def choose_players
16
+ count = 1
17
+ @@cli.say "Name all the players. Input 'done' when you are done."
18
+ loop do
19
+ pname = @@cli.ask("Enter name of player #{count} > ") do |q|
20
+ q.validate = lambda { |a| a.length >= 1 && a.length <= 19 }
21
+ end
22
+ if pname.downcase == 'done'
23
+ break if count > MIN_PLAYER_COUNT
24
+ @@cli.say "You need to input at least 2 players!"
25
+ elsif @g.add_player(pname)== true
26
+ count += 1
27
+ @@cli.say "*** #{pname} successfully added"
28
+ else
29
+ @@cli.say "*** Sorry, there was a problem adding player #{pname}"
30
+ end
31
+ break if count > MAX_PLAYER_COUNT
32
+ end
33
+ @@cli.say "Succesfully added #{count-1} players. Game is ready to start."
34
+ end
35
+
36
+ def puts_help
37
+ @@cli.say "************************ HELP! ************************"
38
+ @@cli.say "<%= color('(b)uy', BOLD) %> = Buy a card"
39
+ @@cli.say "<%= color('(r)eserve', BOLD) %> = Reserve a card"
40
+ @@cli.say "<%= color('(t)okens', BOLD) %> = Pick up tokens from the bank"
41
+ @@cli.say "<%= color('(n)obles', BOLD) %> = Look at the available nobles"
42
+ @@cli.say "<%= color('(h)elp', BOLD) %> = This help page"
43
+ @@cli.say "<%= color('e(x)it', BOLD) %> = Exit the program"
44
+ end
45
+
46
+ def full_display
47
+ @g.display.each do |row, deck|
48
+ @@cli.say "ROW #{row}"
49
+ deck.each do |card|
50
+ @@cli.say card_display(card)
51
+ end
52
+ end
53
+ end
54
+
55
+ #practicing using args rather than fixed list of parameters
56
+ def purchase_card(args)
57
+ #if args[:turn].player.tableau.reserved_cards.include?(args[:card])
58
+ # args[:turn].reserve_card
59
+ if args[:turn].purchase_card(args[:card])
60
+ true
61
+ else
62
+ @@cli.say "Oops, you can't afford that"
63
+ end
64
+ end
65
+
66
+ def reserve_card(args)
67
+ if args[:card].is_a?(SplendorGame::Card) && args[:turn].reserve_displayed_card(args[:card])
68
+ true
69
+ elsif args[:card].is_a?(Integer) && args[:turn].reserve_random_card(args[:card])
70
+ true
71
+ else
72
+ @@cli.say "Sorry, you can't reserve that (maybe you have reserved too many cards)"
73
+ end
74
+ end
75
+
76
+ def do_turn(turn)
77
+ while turn.action_done == false
78
+ output_all_player_details(turn.player)
79
+ input = @@cli.ask "What do you want to do, <%= color('#{turn.player.name}', BOLD) %>? "
80
+ command_result = process_command(input.downcase, turn)
81
+ if !command_result
82
+ @@cli.say "Sorry, I did not understand that. Press h for help"
83
+ elsif command_result==:exit
84
+ break
85
+ end
86
+ end
87
+ consider_nobles(turn)
88
+ turn.end_turn
89
+ @@cli.say "*** END OF TURN***"
90
+ command_result==:exit ? false : true
91
+ end
92
+
93
+ def process_command(input, turn)
94
+ case
95
+ when input[0]=='b'
96
+ card = choose_card(:buy, turn.player)
97
+ purchase_card(:card => card, :turn => turn) if card
98
+ when input[0]=='r'
99
+ card = choose_card(:reserve, turn.player)
100
+ reserve_card(:card => card, :turn => turn) if card
101
+ when input[0]=='h'
102
+ puts_help
103
+ when input[0]=='n'
104
+ display_nobles
105
+ when input[0]=='t'
106
+ @@cli.say bank_details + " "
107
+ take_tokens(turn)
108
+ when input[0]=='x'
109
+ return :exit
110
+ else
111
+ return false
112
+ end
113
+ true
114
+ end
115
+
116
+
117
+ def card_display(card)
118
+ text = "#{card.points}pts "
119
+ text << "(#{card.colour}) => " if card.instance_variable_defined?(:@colour)
120
+ card.cost.each do |k,v|
121
+ text << "#{v} x #{k}, "
122
+ end
123
+ text[0..-3]
124
+ end
125
+
126
+ def output_all_player_details(highlighted_player=nil)
127
+ @g.players.each do |p|
128
+ if p==highlighted_player
129
+ str = "<%= color('"
130
+ str << player_details(p)
131
+ str << "', BOLD) %>"
132
+ else
133
+ str = player_details(p)
134
+ end
135
+ @@cli.say str
136
+ end
137
+ end
138
+
139
+ def player_details(player)
140
+ str = "#{player.name.ljust(19)}: #{player.points.to_s.ljust(2)}pts. "
141
+ reserved_card_count = player.tableau.reserved_cards.count
142
+ str << "(#{reserved_card_count}R) " if reserved_card_count > 0
143
+ str << "Cards (#{player.tableau.cards.count}): "
144
+ player.tableau.all_colours_on_cards.sort.to_h.each do |colour, count|
145
+ str << "#{colour}=#{count} " if count > 0
146
+ end
147
+ str << "Tokens: "
148
+ player.tableau.tokens.sort.to_h.each do |colour,count|
149
+ str << "#{colour}=#{count} " if count > 0
150
+ end
151
+ str[0..-2]
152
+ end
153
+
154
+ def bank_details
155
+ str = "Bank tokens = "
156
+ @g.bank.tokens.sort.to_h.each do |colour, count|
157
+ str << "#{colour}=#{count} " if count > 0
158
+ end
159
+ str
160
+ end
161
+
162
+ def choose_card(mode, player = nil)
163
+ displayed_cards_list = @g.all_displayed_cards.collect { |c| [card_display(c),c] }.to_h
164
+ if mode==:reserve
165
+ (1..3).each { |i| displayed_cards_list["Reserve mystery level #{i} card"]= i }
166
+ end
167
+ if mode==:buy
168
+ player.tableau.reserved_cards.each_with_index do |card, index|
169
+ displayed_cards_list["R#{index+1} - #{card_display(card)}"]= card
170
+ end
171
+ end
172
+ @@cli.choose do |menu|
173
+ menu.prompt = "Which card do you want to #{mode}? "
174
+ menu.choices(*displayed_cards_list.keys) do |chosen|
175
+ @@cli.say "Nice, you chose #{chosen}."
176
+ displayed_cards_list[chosen]
177
+ end
178
+ menu.choice(:cancel) { return false }
179
+ end
180
+ end
181
+
182
+ #def validate_token_choice(t)
183
+ # return false if [2,3].include?(t.count)
184
+ # t.each { |c| return false if !VALID_COLOUR_SYMBOLS.include?(c.upcase) || c==:gold}
185
+ # return false if t.count==2 && t[0] != t[1]
186
+ # true
187
+ #end
188
+
189
+ def take_tokens(turn)
190
+ input = @@cli.ask "Which tokens would you like (CSV format)? "
191
+ requested_tokens = input.split(",")
192
+ #return false if !validate_token_choice(requested_tokens)
193
+ if requested_tokens.count==2
194
+ response = turn.take_two_tokens_same_colour(requested_tokens[0])
195
+ elsif requested_tokens.count==3
196
+ response = turn.take_different_tokens(requested_tokens)
197
+ end
198
+ @@cli.say "Oops, that's not a valid selection" if !response
199
+ end
200
+
201
+ def consider_nobles(turn)
202
+ possibles = turn.claimable_nobles
203
+ return false if possibles.empty?
204
+ return assign_only_valid_noble(turn, possibles) if possibles.count==1
205
+ displayed_nobles_list = possibles.collect { |c| [card_display(c),c] }.to_h
206
+ @@cli.choose do |menu|
207
+ menu.prompt = "You qualify for multiple nobles! Pick one... "
208
+ menu.choices(*displayed_nobles_list.keys) do |chosen|
209
+ turn.claim_noble(displayed_nobles_list[chosen])
210
+ @@cli.say "Nice, you chose #{chosen}."
211
+ end
212
+ end
213
+
214
+ end
215
+
216
+ def display_nobles
217
+ @g.nobles.each do |noble|
218
+ @@cli.say "NOBLE - #{card_display(noble)}"
219
+ end
220
+ end
221
+
222
+ def end_game_detail
223
+ @@cli.say "The game consisted of #{@g.turns.count} turns"
224
+ @@cli.ask "It's the end of the game. Press enter to end the program."
225
+ @@cli.say "Goodbye!"
226
+ end
227
+
228
+
229
+ def main
230
+ @g.start_game
231
+ catch :exit do
232
+ loop do
233
+ turn = @g.next_turn
234
+ throw :exit if turn===false # or @exit_flag==true ??
235
+ throw :exit if !do_turn(turn)
236
+ end #end of the game - only reachable by throwing an :exit
237
+ end
238
+ end_game_detail
239
+ end
240
+
241
+ private
242
+ def assign_only_valid_noble(turn,noble_array)
243
+ the_noble = noble_array.first
244
+ if !turn.claim_noble(the_noble)
245
+ @@cli.say "Looks like you qualify for a noble, but it didn't work"
246
+ return false
247
+ else
248
+ @@cli.say "You have been given a noble! #{the_noble.points} points"
249
+ return true
250
+ end
251
+ end
252
+
253
+ end
254
+
255
+ end
@@ -0,0 +1,17 @@
1
+ module SplendorGame
2
+
3
+ class ColouredObject
4
+ private
5
+ # format any inputted colours to the downcase symbol version
6
+ # return false if an invalid input is passed in
7
+ def validate_colour(input)
8
+ if VALID_COLOUR_LIST.include?(input.to_s.upcase)
9
+ input.downcase.to_sym
10
+ else
11
+ false
12
+ end
13
+ end
14
+
15
+ end
16
+
17
+ end
@@ -0,0 +1,64 @@
1
+ class Object
2
+ def is_natural_number?
3
+ return false if !self.is_a?(Numeric)
4
+ return false if self < 0
5
+ return false if self != self.abs
6
+ true
7
+ end
8
+ end
9
+
10
+ module SplendorGame
11
+
12
+
13
+ class Game
14
+ attr_reader :deck, :bank, :players, :nobles, :options, :display, :turns
15
+ def initialize(user_options = nil)
16
+ @options = Options.new(user_options).give_options
17
+ load_cards # puts all the cards into shuffled decks... a hash of arrays of cards. @deck[level]
18
+ @bank = Tableau.new(0) # 0 means no limit on token capacity
19
+ @players = Array.new()
20
+ @turns = Array.new()
21
+ end
22
+
23
+ def add_player(player_name)
24
+ return false if @players.count >= MAX_PLAYER_COUNT
25
+ @players << Player.new(player_name, @players.count+1,@options[:player_token_limit])
26
+ true
27
+ end
28
+
29
+ def next_player
30
+ if !@turns.empty?
31
+ @players.rotate!
32
+ return @players.first
33
+ end
34
+ @players.shuffle!
35
+ @starting_player = @players.first
36
+ end
37
+
38
+ def game_over?
39
+ return false if @players.map { |p| p.points }.max < @options[:winning_score]
40
+ return true if @players[1] == @starting_player
41
+ false
42
+ end
43
+
44
+ def start_game
45
+ @bank.seed_bank({:options=> @options, :player_count => @players.count})
46
+ @nobles = noble_sample(@options[:nobles_available][@players.count])
47
+ @display = Hash.new()
48
+ @deck.each { |level, subdeck| @display[level] = subdeck.pop(@options[:display_cards_per_row]) }
49
+ end
50
+
51
+ def next_turn
52
+ return false if game_over? || !defined? @display
53
+ t = SplendorGame::Turn.new(self, next_player)
54
+ @turns << t
55
+ t
56
+ end
57
+
58
+ def all_displayed_cards
59
+ @display.values.flatten
60
+ end
61
+
62
+ end
63
+
64
+ end
@@ -0,0 +1,126 @@
1
+ module SplendorGame
2
+ class Game
3
+ #Could read from an external file eventually, but this works just fine :)
4
+ def load_cards
5
+ all_cards = Array.new()
6
+ all_cards << Card.new(1, :white, {:blue => 3})
7
+ all_cards << Card.new(1, :white, {:red => 2, :black => 1})
8
+ all_cards << Card.new(1, :white, {:blue => 1, :green => 1, :red => 1, :black => 1})
9
+ all_cards << Card.new(1, :white, {:blue => 2, :black => 2})
10
+ all_cards << Card.new(1, :white, {:green => 4}, 1)
11
+ all_cards << Card.new(1, :white, {:blue => 1, :green => 2, :red => 1, :black => 1})
12
+ all_cards << Card.new(1, :white, {:blue => 2, :green => 2, :black => 1})
13
+ all_cards << Card.new(1, :white, {:white => 3, :blue => 1, :black => 1})
14
+ all_cards << Card.new(1, :blue, {:white => 1, :black => 2})
15
+ all_cards << Card.new(1, :blue, {:black => 3})
16
+ all_cards << Card.new(1, :blue, {:white => 1, :green => 1, :red => 1, :black => 1})
17
+ all_cards << Card.new(1, :blue, {:green => 2, :black => 2})
18
+ all_cards << Card.new(1, :blue, {:red => 4}, 1)
19
+ all_cards << Card.new(1, :blue, {:white => 1, :green => 1, :red => 2, :black => 1})
20
+ all_cards << Card.new(1, :blue, {:white => 1, :green => 2, :red => 2})
21
+ all_cards << Card.new(1, :blue, {:blue => 1, :green => 3, :red => 1})
22
+ all_cards << Card.new(1, :green, {:white => 2, :blue => 1})
23
+ all_cards << Card.new(1, :green, {:red => 3})
24
+ all_cards << Card.new(1, :green, {:white => 1, :blue => 1, :red => 1, :black => 1})
25
+ all_cards << Card.new(1, :green, {:blue => 2, :red => 2})
26
+ all_cards << Card.new(1, :green, {:black => 4}, 1)
27
+ all_cards << Card.new(1, :green, {:white => 1, :blue => 1, :red => 1, :black => 2})
28
+ all_cards << Card.new(1, :green, {:blue => 1, :red => 2, :black => 2})
29
+ all_cards << Card.new(1, :green, {:white => 1, :blue => 3, :green => 1})
30
+ all_cards << Card.new(1, :red, {:blue => 2, :green => 1})
31
+ all_cards << Card.new(1, :red, {:white => 3})
32
+ all_cards << Card.new(1, :red, {:white => 1, :blue => 1, :green => 1, :black => 1})
33
+ all_cards << Card.new(1, :red, {:white => 2, :red => 2})
34
+ all_cards << Card.new(1, :red, {:white => 4}, 1)
35
+ all_cards << Card.new(1, :red, {:white => 2, :blue => 1, :green => 1, :black => 1})
36
+ all_cards << Card.new(1, :red, {:white => 2, :green => 1, :black => 2})
37
+ all_cards << Card.new(1, :red, {:white => 1, :red => 1, :black => 3})
38
+ all_cards << Card.new(1, :black, {:green => 2, :red => 1})
39
+ all_cards << Card.new(1, :black, {:green => 3})
40
+ all_cards << Card.new(1, :black, {:white => 1, :blue => 1, :green => 1, :red => 1})
41
+ all_cards << Card.new(1, :black, {:white => 2, :green => 2})
42
+ all_cards << Card.new(1, :black, {:blue => 4}, 1)
43
+ all_cards << Card.new(1, :black, {:white => 1, :blue => 2, :green => 1, :red => 1})
44
+ all_cards << Card.new(1, :black, {:white => 2, :blue => 2, :red => 1})
45
+ all_cards << Card.new(1, :black, {:green => 1, :red => 3, :black => 1})
46
+
47
+ all_cards << Card.new(2, :white, {:red => 5}, 2)
48
+ all_cards << Card.new(2, :white, {:white => 6}, 3)
49
+ all_cards << Card.new(2, :white, {:green => 3, :red => 2, :black => 2}, 1)
50
+ all_cards << Card.new(2, :white, {:green => 1, :red => 4, :black => 2}, 2)
51
+ all_cards << Card.new(2, :white, {:white => 2, :blue => 3, :red => 3}, 1)
52
+ all_cards << Card.new(2, :white, {:red => 5, :black => 3}, 2)
53
+ all_cards << Card.new(2, :blue, {:blue => 5}, 2)
54
+ all_cards << Card.new(2, :blue, {:blue => 6}, 3)
55
+ all_cards << Card.new(2, :blue, {:blue => 2, :green => 2, :red => 3}, 1)
56
+ all_cards << Card.new(2, :blue, {:white => 2, :red => 1, :black => 4}, 2)
57
+ all_cards << Card.new(2, :blue, {:blue => 2, :green => 3, :black => 3}, 1)
58
+ all_cards << Card.new(2, :blue, {:white => 5, :blue => 3}, 2)
59
+ all_cards << Card.new(2, :green, {:green => 5}, 2)
60
+ all_cards << Card.new(2, :green, {:green => 6}, 3)
61
+ all_cards << Card.new(2, :green, {:white => 2, :blue => 3, :black => 2}, 1)
62
+ all_cards << Card.new(2, :green, {:white => 3, :green => 2, :red => 3}, 1)
63
+ all_cards << Card.new(2, :green, {:white => 4, :blue => 2, :black => 1}, 2)
64
+ all_cards << Card.new(2, :green, {:blue => 5, :green => 3}, 2)
65
+ all_cards << Card.new(2, :red, {:black => 5}, 2)
66
+ all_cards << Card.new(2, :red, {:red => 6}, 3)
67
+ all_cards << Card.new(2, :red, {:white => 2, :red => 2, :black => 3}, 1)
68
+ all_cards << Card.new(2, :red, {:white => 1, :blue => 4, :green => 2}, 2)
69
+ all_cards << Card.new(2, :red, {:blue => 3, :red => 2, :black => 3}, 1)
70
+ all_cards << Card.new(2, :red, {:white => 3, :black => 5}, 2)
71
+ all_cards << Card.new(2, :black, {:white => 5}, 2)
72
+ all_cards << Card.new(2, :black, {:black => 6}, 3)
73
+ all_cards << Card.new(2, :black, {:white => 3, :blue => 2, :green => 2}, 1)
74
+ all_cards << Card.new(2, :black, {:blue => 1, :green => 4, :red => 2}, 2)
75
+ all_cards << Card.new(2, :black, {:white => 3, :green => 3, :black => 2}, 1)
76
+ all_cards << Card.new(2, :black, {:green => 5, :red => 3}, 2)
77
+
78
+ all_cards << Card.new(3, :white, {:black => 7}, 4)
79
+ all_cards << Card.new(3, :white, {:white => 3, :black => 7}, 5)
80
+ all_cards << Card.new(3, :white, {:white => 3, :red => 3, :black => 6}, 4)
81
+ all_cards << Card.new(3, :white, {:blue => 3, :green => 3, :red => 5, :black => 3}, 3)
82
+ all_cards << Card.new(3, :blue, {:white => 7}, 4)
83
+ all_cards << Card.new(3, :blue, {:white => 7, :blue => 3}, 5)
84
+ all_cards << Card.new(3, :blue, {:white => 6, :blue => 3, :black => 3}, 4)
85
+ all_cards << Card.new(3, :blue, {:white => 3, :green => 3, :red => 3, :black => 5}, 3)
86
+ all_cards << Card.new(3, :green, {:blue => 7}, 4)
87
+ all_cards << Card.new(3, :green, {:blue => 7, :green => 3}, 5)
88
+ all_cards << Card.new(3, :green, {:white => 3, :blue => 6, :green => 3}, 4)
89
+ all_cards << Card.new(3, :green, {:white => 5, :blue => 3, :red => 3, :black => 3}, 3)
90
+ all_cards << Card.new(3, :red, {:green => 7}, 4)
91
+ all_cards << Card.new(3, :red, {:green => 7, :red => 3}, 5)
92
+ all_cards << Card.new(3, :red, {:blue => 3, :green => 6, :red => 3}, 4)
93
+ all_cards << Card.new(3, :red, {:white => 3, :blue => 5, :green => 3, :black => 3}, 3)
94
+ all_cards << Card.new(3, :black, {:red => 7}, 4)
95
+ all_cards << Card.new(3, :black, {:red => 7, :black => 3}, 5)
96
+ all_cards << Card.new(3, :black, {:green => 3, :red => 6, :black => 3}, 4)
97
+ all_cards << Card.new(3, :black, {:white => 3, :blue => 3, :green => 5, :red => 3}, 3)
98
+
99
+
100
+
101
+ # Now all cards are in all_cards, distribute them into all_cards
102
+ @deck = Hash.new()
103
+ all_cards.each do |card|
104
+ @deck[card.level] = Array.new() if !@deck.include?(card.level)
105
+ @deck[card.level] << card
106
+ end
107
+ # shuffle them
108
+ @deck.each { |_deck_num, smaller_deck| smaller_deck.shuffle! }
109
+ end
110
+
111
+ def noble_sample(number_of_cards_to_load)
112
+ all_nobles = Array.new()
113
+ all_nobles << Noble.new({:white => 3, :blue => 3, :black => 3}, 3)
114
+ all_nobles << Noble.new({:blue => 3, :green => 3, :red => 3}, 3)
115
+ all_nobles << Noble.new({:white => 3, :red => 3, :black => 3}, 3)
116
+ all_nobles << Noble.new({:white => 3, :blue => 3, :green => 3}, 3)
117
+ all_nobles << Noble.new({:green => 3, :red => 3, :black => 3}, 3)
118
+ all_nobles << Noble.new({:green => 4, :red => 4}, 3)
119
+ all_nobles << Noble.new({:blue => 4, :green => 4}, 3)
120
+ all_nobles << Noble.new({:red => 4, :black => 4}, 3)
121
+ all_nobles << Noble.new({:white => 4, :black => 4}, 3)
122
+ all_nobles << Noble.new({:white => 4, :blue => 4}, 3)
123
+ all_nobles.shuffle!.first(number_of_cards_to_load)
124
+ end
125
+ end
126
+ end
@@ -0,0 +1,22 @@
1
+ module SplendorGame
2
+
3
+ #Players become eligible for Nobles when they have cards that meet the cost (NOT tokens)
4
+ class Noble < ColouredObject
5
+ attr_reader :cost, :points
6
+
7
+ def initialize(cost, points = 0)
8
+ @points = points
9
+ @cost, @cost_error = Hash.new(), Hash.new()
10
+ # if the colour is valid, load it, if not, put it in an error hash
11
+ cost.each do |key, value|
12
+ new_key_name = validate_colour(key)
13
+ if new_key_name==false
14
+ @cost_error[key] = value
15
+ else
16
+ @cost[new_key_name] = value
17
+ end
18
+ end
19
+ end
20
+ end
21
+
22
+ end
@@ -0,0 +1,48 @@
1
+ module SplendorGame
2
+
3
+ class Options
4
+ NOBLES_AVAILABLE = { 2 => 3, 3 => 4, 4 => 5}
5
+ STARTING_GOLD_TOKENS = 5
6
+ STARTING_NON_GOLD_TOKENS = { 2 => 4, 3 => 5, 4 => 7}
7
+ DISPLAY_CARDS_PER_ROW = 4
8
+ WINNING_SCORE = 15
9
+ MIN_TO_TAKE_TWO = 4
10
+ PLAYER_TOKEN_LIMIT = 10
11
+ attr_reader :deck, :bank, :players, :nobles, :options, :display
12
+ def initialize(user_options = nil)
13
+ if user_options.is_a?(Hash)
14
+ @user_options = user_options
15
+ else
16
+ @user_options = Hash.new()
17
+ end
18
+ end
19
+
20
+ def clean_user_options
21
+ [:starting_non_gold_tokens, :nobles_available].each do |key|
22
+ if @user_options[key].respond_to?(:keys)
23
+ @user_options.delete(key) if !([2,3,4] - @user_options[key].keys).empty?
24
+ end
25
+ end
26
+ end
27
+
28
+ def default_options
29
+ output = Hash.new()
30
+ output[:display_cards_per_row] = DISPLAY_CARDS_PER_ROW
31
+ output[:winning_score] = WINNING_SCORE
32
+ output[:min_to_take_two] = MIN_TO_TAKE_TWO
33
+ output[:starting_gold_tokens] = STARTING_GOLD_TOKENS
34
+ output[:starting_non_gold_tokens] = STARTING_NON_GOLD_TOKENS
35
+ output[:nobles_available] = NOBLES_AVAILABLE
36
+ output[:player_token_limit] = PLAYER_TOKEN_LIMIT
37
+ output
38
+ end
39
+
40
+ #Take the user values if they are valid, else use defaults
41
+ def give_options
42
+ clean_user_options
43
+ @user_options.merge(default_options)
44
+ end
45
+
46
+ end
47
+
48
+ end
@@ -0,0 +1,33 @@
1
+ module SplendorGame
2
+
3
+ class Player
4
+
5
+ attr_reader :name, :turn_order, :tableau, :nobles
6
+
7
+ def initialize(name, turn_order, token_limit)
8
+ @name = name
9
+ @turn_order = turn_order
10
+ @tableau = Tableau.new(token_limit)
11
+ @nobles = Array.new()
12
+ end
13
+
14
+ def points
15
+ card_points = @tableau.cards.inject(0) { |sum,c| sum + c.points }
16
+ card_points + @nobles.inject(0) { |sum,c| sum + c.points }
17
+ end
18
+
19
+ def can_afford_noble?(noble)
20
+ noble.cost.each do |k, v|
21
+ return false if @tableau.colours_on_cards(k) < v
22
+ end
23
+ true
24
+ end
25
+
26
+ def claim_noble(noble)
27
+ return false if !can_afford_noble?(noble)
28
+ @nobles << noble
29
+ true
30
+ end
31
+ end
32
+
33
+ end
@@ -0,0 +1,128 @@
1
+ module SplendorGame
2
+
3
+
4
+ class Tableau
5
+ @@max_reserved_cards = 3
6
+ attr_reader :cards, :tokens, :reserved_cards
7
+
8
+ def initialize(token_limit)
9
+ @cards = Array.new()
10
+ @tokens = Hash.new(0)
11
+ @unlimited = token_limit <= 0 ? true : false
12
+ @token_limit = token_limit
13
+ @reserved_cards = Array.new()
14
+ end
15
+
16
+ def seed_bank(args)
17
+ seed_bank_non_gold(args[:options][:starting_non_gold_tokens][args[:player_count]])
18
+ seed_bank_gold(args[:options][:starting_gold_tokens])
19
+ end
20
+
21
+ ### add tokens, remove tokens, counting tokens
22
+
23
+ def add_token(token_colour)
24
+ return false if !VALID_COLOUR_SYMBOLS.include?(token_colour)
25
+ return false if !@unlimited && token_count >= @token_limit
26
+ if @tokens.include?(token_colour)
27
+ @tokens[token_colour] += 1
28
+ else
29
+ @tokens[token_colour] = 1
30
+ end
31
+ true
32
+ end
33
+
34
+ def remove_token(token_colour)
35
+ return false if !@tokens.key?(token_colour)
36
+ return false if @tokens[token_colour] <= 0
37
+ @tokens[token_colour] -= 1
38
+ true
39
+ end
40
+
41
+ def token_count
42
+ @tokens.inject(0) { |sum,(_k,v)| sum + v }
43
+ end
44
+
45
+ def token_space_remaining
46
+ return nil if @unlimited == true #meaning, undefined
47
+ @token_limit - token_count
48
+ end
49
+
50
+ def distinct_token_colour_count
51
+ @tokens.count { |_k,v| v >0 }
52
+ end
53
+
54
+ #### reserving cards
55
+
56
+ def can_reserve_card?
57
+ return false if @reserved_cards.size >= @@max_reserved_cards
58
+ true
59
+ end
60
+
61
+ def reserve_card(card)
62
+ return false if !can_reserve_card?
63
+ @reserved_cards << card
64
+ end
65
+
66
+ def play_reserved_card(card)
67
+ return false if tokens_required(card) == false
68
+ return false unless @reserved_cards.include?(card)
69
+ @cards << card
70
+ @reserved_cards.delete(card)
71
+ end
72
+
73
+ ### related to purchasing cards
74
+
75
+ def purchase_card(card)
76
+ return false if tokens_required(card) == false
77
+ @cards << card
78
+ end
79
+
80
+ # Returns a Hash of the tokens required to buy the card
81
+ # If the tableau does not have sufficient cards/tokens, it returns false
82
+ def tokens_required(card)
83
+ answer = Hash.new(0)
84
+ card.cost.each do |colour, col_cost|
85
+ theoretical_tokens = col_cost - colours_on_cards(colour)
86
+ if theoretical_tokens <= @tokens[colour]
87
+ answer[colour] = theoretical_tokens if theoretical_tokens > 0
88
+ else
89
+ answer[colour] = @tokens[colour]
90
+ answer[:gold] += theoretical_tokens - @tokens[colour]
91
+ end
92
+ end
93
+ return false if answer[:gold] > @tokens[:gold]
94
+ answer
95
+ end
96
+
97
+ def all_colours_on_cards
98
+ output = Hash.new()
99
+ VALID_COLOUR_SYMBOLS.each { |c| output[c] = colours_on_cards(c) if colours_on_cards(c) > 0 }
100
+ output
101
+ end
102
+
103
+ def colours_on_cards(colour)
104
+ @cards.inject(0) { |sum,card| card.colour == colour ? sum+1 : sum }.to_i
105
+ end
106
+
107
+ ### Other
108
+
109
+ def is_empty?
110
+ @cards.size==0 && @tokens.size==0 ? true : false
111
+ end
112
+
113
+ ### setup
114
+ private
115
+
116
+ def seed_bank_non_gold(token_count)
117
+ VALID_COLOUR_SYMBOLS.each do |colour|
118
+ @tokens[colour] = token_count if colour != :gold
119
+ end
120
+ end
121
+
122
+ def seed_bank_gold(token_count)
123
+ @tokens[:gold] = token_count
124
+ end
125
+
126
+ end
127
+
128
+ end
@@ -0,0 +1,144 @@
1
+ module SplendorGame
2
+
3
+ class Turn
4
+ attr_reader :player, :action_done
5
+
6
+ def initialize(game, player)
7
+ @game = game
8
+ @player = player
9
+ @action_done = false
10
+ @noble_claimed = false
11
+ end
12
+
13
+ #from the 12 cards on display plus up to 3 reserved ones, return the ones affordable, in an Array
14
+ def affordable_cards
15
+ answer = Array.new()
16
+ (@game.all_displayed_cards + @player.tableau.reserved_cards).each do |card|
17
+ @cost = @player.tableau.tokens_required(card)
18
+ answer << card if !@cost==false
19
+ end
20
+ answer
21
+ end
22
+
23
+ def purchase_card(card) # do the requisite card/token changes, if the card is in affordable_cards
24
+ return false if @action_done
25
+ return false if !affordable_cards.include?(card)
26
+ cost_to_player = @player.tableau.tokens_required(card)
27
+ if @player.tableau.reserved_cards.include?(card)
28
+ @player.tableau.play_reserved_card(card)
29
+ else
30
+ @player.tableau.purchase_card(card)
31
+ end
32
+ cost_to_player.each do |colour, val|
33
+ val.times { @player.tableau.remove_token(colour) }
34
+ val.times { @game.bank.add_token(colour) }
35
+ end
36
+ display_row = @game.display[card.level]
37
+ display_row.delete_at(display_row.index(card) || display_row.length)
38
+ @action_done = true
39
+ end
40
+
41
+ def reserve_card_checks?
42
+ return false if @action_done
43
+ return false if !@player.tableau.can_reserve_card?
44
+ true
45
+ end
46
+
47
+ def give_gold_token
48
+ if @game.bank.tokens[:gold] > 0 && @player.tableau.token_space_remaining > 0
49
+ @game.bank.remove_token(:gold)
50
+ @player.tableau.add_token(:gold)
51
+ end
52
+ end
53
+
54
+ def reserve_displayed_card(card) # put cards in to player's reserved set. Remove card from display
55
+ return false if !reserve_card_checks?
56
+ return false if !@game.display.flatten(2).include?(card)
57
+ @player.tableau.reserve_card(card)
58
+ display_row = @game.display[card.level]
59
+ display_row.delete_at(display_row.index(card) || display_row.length)
60
+ give_gold_token
61
+ @action_done = true
62
+ end
63
+
64
+ def reserve_random_card(deck_number)
65
+ return false if !reserve_card_checks?
66
+ return false if @game.deck[deck_number].nil?
67
+ return false if @game.deck[deck_number].count==0
68
+ card = @game.deck[deck_number].pop
69
+ @player.tableau.reserve_card(card)
70
+ give_gold_token
71
+ @action_done = true
72
+ end
73
+
74
+ def validate_token_pickup?(colour)
75
+ return false if @action_done
76
+ return false if Array(colour).include?(:gold)
77
+ true
78
+ end
79
+
80
+ def take_two_tokens_same_colour(colour)
81
+ colour = colour.to_sym
82
+ return false if !validate_token_pickup?(colour)
83
+ return false if @game.bank.tokens[colour] < @game.options[:min_to_take_two]
84
+ return false if @player.tableau.token_space_remaining < 2
85
+ 2.times { @player.tableau.add_token(colour) }
86
+ 2.times { @game.bank.remove_token(colour) }
87
+ @action_done = true
88
+ end
89
+
90
+ def take_different_tokens(colours)
91
+ colours.map!{|c| c.to_sym}
92
+ return false if !validate_token_pickup?(colours)
93
+ return false if colours.count != 3
94
+ return false if colours.uniq.length != colours.length
95
+ return false if colours.select { |c| @game.bank.tokens[c]==0}.length > 0
96
+ return false if @player.tableau.token_space_remaining < 3
97
+ colours.each do |c|
98
+ @player.tableau.add_token(c)
99
+ @game.bank.remove_token(c)
100
+ end
101
+ @action_done = true
102
+ end
103
+
104
+ # in order to claim tokens you may need to return tokens, eg pick up a gold when
105
+ # you have 10, or you have 8 and want to take 3 different.
106
+
107
+ def action_return_token(colour)
108
+ return false if !@player.tableau.tokens.include?(colour)
109
+ return false if @player.tableau.tokens[colour] <= 0
110
+ @player.tableau.remove_token(colour)
111
+ @game.bank.add_token(colour)
112
+ end
113
+
114
+ def claim_noble(noble) # Move noble from bank to player, assuming it's affordable
115
+ return false if @noble_claimed # you can only claim 1 per turn
116
+ return false if !noble_affordable?(noble)
117
+ @game.nobles.delete_at(@game.nobles.index(noble) || display_row.length)
118
+ @player.nobles << noble
119
+ @noble_claimed = true
120
+ end
121
+
122
+ def claimable_nobles
123
+ @game.nobles.find_all { |noble| noble_affordable?(noble) }
124
+ end
125
+
126
+ def noble_affordable?(noble)
127
+ noble.cost.each do |colour, cost|
128
+ return false if @player.tableau.colours_on_cards(colour) < cost
129
+ end
130
+ true
131
+ end
132
+
133
+ def end_turn # make sure there are 4 cards showing from each deck, assuming there are any left
134
+ #assumption : max 1 card is missing from each row
135
+ nonfull_rows = @game.display.select { |_level, subdeck| subdeck.count < @game.options[:display_cards_per_row] }
136
+ nonfull_rows.each do |row_num, display_row|
137
+ relevant_deck = @game.deck[row_num]
138
+ display_row << relevant_deck.pop if relevant_deck.count > 0
139
+ end
140
+ end
141
+
142
+ end
143
+
144
+ end
@@ -0,0 +1,3 @@
1
+ module SplendorGame
2
+ VERSION = "0.1.0"
3
+ end
@@ -0,0 +1,28 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'splendor_game/version'
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = "splendor_game"
8
+ spec.version = SplendorGame::VERSION
9
+ spec.authors = ["reedstonefood"]
10
+ spec.email = ["reedstonefood@users.noreply.github.com"]
11
+
12
+ spec.summary = %q{An implementation of the board game, Splendor.}
13
+ spec.homepage = "https://github.com/reedstonefood/splendor_game"
14
+ spec.license = "MIT"
15
+
16
+ spec.files = `git ls-files -z`.split("\x0").reject do |f|
17
+ f.match(%r{^(test|spec|features)/})
18
+ end
19
+ spec.bindir = "exe"
20
+ spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
21
+ spec.require_paths = ["lib"]
22
+
23
+ spec.add_development_dependency "bundler", "~> 1.13"
24
+ spec.add_development_dependency "rake", "~> 10.0"
25
+ spec.add_development_dependency "rspec", "~> 3.0"
26
+
27
+ spec.add_dependency "highline", "~> 1.7"
28
+ end
metadata ADDED
@@ -0,0 +1,123 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: splendor_game
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - reedstonefood
8
+ autorequire:
9
+ bindir: exe
10
+ cert_chain: []
11
+ date: 2017-08-23 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: bundler
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '1.13'
20
+ type: :development
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: '1.13'
27
+ - !ruby/object:Gem::Dependency
28
+ name: rake
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: '10.0'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: '10.0'
41
+ - !ruby/object:Gem::Dependency
42
+ name: rspec
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - "~>"
46
+ - !ruby/object:Gem::Version
47
+ version: '3.0'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - "~>"
53
+ - !ruby/object:Gem::Version
54
+ version: '3.0'
55
+ - !ruby/object:Gem::Dependency
56
+ name: highline
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - "~>"
60
+ - !ruby/object:Gem::Version
61
+ version: '1.7'
62
+ type: :runtime
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - "~>"
67
+ - !ruby/object:Gem::Version
68
+ version: '1.7'
69
+ description:
70
+ email:
71
+ - reedstonefood@users.noreply.github.com
72
+ executables: []
73
+ extensions: []
74
+ extra_rdoc_files: []
75
+ files:
76
+ - ".codeclimate.yml"
77
+ - ".gitignore"
78
+ - ".rspec"
79
+ - ".travis.yml"
80
+ - Gemfile
81
+ - LICENSE.txt
82
+ - README.md
83
+ - Rakefile
84
+ - bin/console
85
+ - bin/setup
86
+ - lib/splendor_game.rb
87
+ - lib/splendor_game/card.rb
88
+ - lib/splendor_game/cli.rb
89
+ - lib/splendor_game/coloured_object.rb
90
+ - lib/splendor_game/game.rb
91
+ - lib/splendor_game/load_cards.rb
92
+ - lib/splendor_game/noble.rb
93
+ - lib/splendor_game/options.rb
94
+ - lib/splendor_game/player.rb
95
+ - lib/splendor_game/tableau.rb
96
+ - lib/splendor_game/turn.rb
97
+ - lib/splendor_game/version.rb
98
+ - splendor_game.gemspec
99
+ homepage: https://github.com/reedstonefood/splendor_game
100
+ licenses:
101
+ - MIT
102
+ metadata: {}
103
+ post_install_message:
104
+ rdoc_options: []
105
+ require_paths:
106
+ - lib
107
+ required_ruby_version: !ruby/object:Gem::Requirement
108
+ requirements:
109
+ - - ">="
110
+ - !ruby/object:Gem::Version
111
+ version: '0'
112
+ required_rubygems_version: !ruby/object:Gem::Requirement
113
+ requirements:
114
+ - - ">="
115
+ - !ruby/object:Gem::Version
116
+ version: '0'
117
+ requirements: []
118
+ rubyforge_project:
119
+ rubygems_version: 2.6.6
120
+ signing_key:
121
+ specification_version: 4
122
+ summary: An implementation of the board game, Splendor.
123
+ test_files: []