Class: Gambit::Tools::Scorecard

Inherits:
Object
  • Object
show all
Includes:
Viewable
Defined in:
lib/gambit/tools/scorecard.rb

Overview

A tool for managing the score of just about any game.

Instance Method Summary collapse

Methods included from Viewable

append_features, #view

Constructor Details

#initialize(*players) ⇒ Scorecard

Creates a new Scorecard object, optionally initialized with some players.



79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
# File 'lib/gambit/tools/scorecard.rb', line 79

def initialize( *players )
	@score            = Hash.new(0)
	@players          = Array.new
	
	@use_categories   = false
	@categories       = Array.new
	@totals           = Array.new
	@order            = Array.new
	@categories_score = Hash.new do |names, cat|
		names[cat] = Hash.new(0)
	end
	@win_category     = nil
	
	add_players(*players)
end

Instance Method Details

#add_player(player) ⇒ Object

Add a new player to this Scorecard.

Returns self for method chaining.



100
101
102
103
104
# File 'lib/gambit/tools/scorecard.rb', line 100

def add_player( player )
	@players << player

	self
end

#add_players(*players) ⇒ Object

Add a group of players to this Scorecard.

Returns self for method chaining.



111
112
113
114
115
# File 'lib/gambit/tools/scorecard.rb', line 111

def add_players( *players )
	players.each { |player| add_player(player) }

	self
end

#loser(&condition) ⇒ Object

Returns the losing player, as determined by the provided winning condition. If a condition block is not given, scores will be compared numerically, with the highest score considered to be the best.



123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
# File 'lib/gambit/tools/scorecard.rb', line 123

def loser( &condition )
	if @use_categories
		scores = @categories_score.map do |(name, scores)|
			if @categories.assoc(@win_category)
				@score[@win_category]
			elsif total = @totals.assoc(@win_category)
				figure_total(name, total[1], total[2])
			end
		end
		best_score = scores.min(&condition)
		@categories_score.find do |(name, score)|
			if @categories.assoc(@win_category)
				@score[@win_category] == best_score
			elsif total = @totals.assoc(@win_category)
				figure_total(name, total[1], total[2]) == best_score
			end
		end.first
	else
		best_score = @score.values.min(&condition)
		@score.find { |(player, score)| score == best_score }.first
	end
end

#require_categoriesObject

Forces this Scorecard to score by category only.

Returns self for method chaining.



151
152
153
154
155
# File 'lib/gambit/tools/scorecard.rb', line 151

def require_categories(  )
	@use_categories = true
	
	self
end

#score(player, points = 0, category = nil) ⇒ Object

Can be used to add points to the score of the given player or to fetch the score for a player, by omitting the points. If given, a score will be modified or fetched for the given category.



163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
# File 'lib/gambit/tools/scorecard.rb', line 163

def score( player, points = 0, category = nil )
	if @use_categories
		cat = @categories.assoc(category) or
			raise ArgumentError, "Invalid category."

		total = @categories_score[player][category]
		total += points

		if cat.size == 2 and cat.last.is_a? Proc
			unless cat.last[total]
				raise ArgumentError, "Invalid score for " +
				                     "#{cat.first} category."
			end
		elsif cat.size == 2 and cat.last.is_a? Array
			unless cat.last.include?(total)
				raise ArgumentError, "Invalid score for " +
				                     "#{cat.first} category."
			end
		elsif cat.size == 3
			unless cat[1] <= total and total <= cat[2]
				raise ArgumentError, "Invalid score for " +
				                     "#{cat.first} category."
			end
		end

		@categories_score[player][category] = total

		total(player, category)
	else
		@score[player] += points
		@score[player] = yield(@score[player]) if block_given?

		total(player)
	end
end

#set_total(name, *from, &validation) ⇒ Object

This method adds a “total” field to this Scorecard, by name. A total can be calculated from any other fields on the card, including other totals.

A validation block can be given, if needed. The block will be called each time the total is display and passed the sum of all from fields. The return value of the block will be the total displayed.

Returns self for method chaining.



211
212
213
214
215
216
# File 'lib/gambit/tools/scorecard.rb', line 211

def set_total( name, *from, &validation )
	@order << name
	@totals << [name, from, validation]
	
	self
end

#set_win(name) ⇒ Object

Sets the score catrgory used to determine a winner.

Returns self for method chaining.



223
224
225
226
227
# File 'lib/gambit/tools/scorecard.rb', line 223

def set_win( name )
	@win_category = name
	
	self
end

#start_at=(minimum_score) ⇒ Object

Sets a starting score for each field. WARNING: Should be called before any calls to score(), for predictable results.



233
234
235
# File 'lib/gambit/tools/scorecard.rb', line 233

def start_at=( minimum_score )
	@score.default = minimum_score
end

#total(player, category = nil) ⇒ Object

Returns the total score for the given player or for the given player in the optional category.



241
242
243
244
245
246
247
248
249
250
251
252
253
# File 'lib/gambit/tools/scorecard.rb', line 241

def total( player, category = nil )
	if category.nil?
		@score[player]
	else
		if @categories.assoc(category)
			@categories_score[player][category]
		elsif total = @totals.assoc(category)
			figure_total(player, total[1], total[2])
		else
			
		end
	end
end

#use_category(category, *details, &validation) ⇒ Object

Adds a category to this Scorecard.

Returns self for method chaining.

:call-seq:

use_category(cat) { |score| ... }            -> self
use_category(cat, ary_of_accepted_values)    -> self
use_category(cat, low, high)                 -> self


265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
# File 'lib/gambit/tools/scorecard.rb', line 265

def use_category( category, *details, &validation )
	@order << category
	
	if not validation.nil?
		@categories << [category, validation]
	elsif details.size == 1 and details[0].is_a? Array
		@categories << [category, details[0]]
	elsif details.size == 2 and details.all? { |n| n.is_a? Integer }
		@categories << [category, *details]
	else
		raise ArgumentError, "Invalid category definition."
	end
	
	self
end

#winner(&condition) ⇒ Object

Returns the winning player, as determined by the provided winning condition. If a condition block is not given, scores will be compared numerically, with the highest score considered to be the best.



287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
# File 'lib/gambit/tools/scorecard.rb', line 287

def winner( &condition )
	if @use_categories
		scores = @categories_score.map do |(name, scores)|
			if @categories.assoc(@win_category)
				@score[@win_category]
			elsif total = @totals.assoc(@win_category)
				figure_total(name, total[1], total[2])
			end
		end
		best_score = scores.max(&condition)
		@categories_score.find do |(name, score)|
			if @categories.assoc(@win_category)
				@score[@win_category] == best_score
			elsif total = @totals.assoc(@win_category)
				figure_total(name, total[1], total[2]) == best_score
			end
		end.first
	else
		best_score = @score.values.max(&condition)
		@score.find { |(player, score)| score == best_score }.first
	end
end