cool_soccer 0.2.1 → 0.3.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/bin/cool_soccer +20 -8
- data/lib/cool_soccer/soccer_helpers.rb +23 -46
- data/lib/cool_soccer.rb +11 -16
- metadata +24 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: f9c5dd5b67b28fb8a8cb8e6eeced481d22f2a83d8848bd64c0c0ea4a59e91d7e
|
4
|
+
data.tar.gz: 8f7d990484715db577b1da34959bfdade276d66440c2122ed2221b11d8ef8539
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 15e7bf21c7578cf1af656c2279916a48100b56e3ae7bae65456d3fa05ff1d6f5f15a6989192ddd594752e3e5aaecab2f413a08a51530d8c2e221896e25d9c4c8
|
7
|
+
data.tar.gz: f34e9ae6c2f8991a5e7d6fdb289f78a39722daf7f7590727269f95fce52c01b22541c53f61fde2543e75aa44add585e0061b383c15f0b92ed3535eadcc208a0c
|
data/bin/cool_soccer
CHANGED
@@ -3,19 +3,31 @@
|
|
3
3
|
|
4
4
|
require_relative '../lib/cool_soccer'
|
5
5
|
|
6
|
+
# If there are more than one arguments, exit with an error message.
|
7
|
+
if ARGV.length > 1
|
8
|
+
puts 'Too many arguments. Expected to be passed a stream, or a path to a single file'
|
9
|
+
exit 1
|
10
|
+
end
|
11
|
+
|
12
|
+
# If the file at ARGV[0] does not exist, exit with an error message.
|
13
|
+
if ARGV[0] && !File.exist?(ARGV[0])
|
14
|
+
puts "The file #{ARGV[0]} does not exist"
|
15
|
+
exit 1
|
16
|
+
end
|
17
|
+
|
6
18
|
app = CoolSoccer.new
|
7
19
|
|
8
|
-
if
|
9
|
-
|
10
|
-
File.foreach(file_path) do |line|
|
20
|
+
if ARGV.empty?
|
21
|
+
$stdin.each_line do |line|
|
11
22
|
app.execute(line: line)
|
12
23
|
end
|
13
24
|
else
|
14
|
-
|
25
|
+
file_path = ARGV[0]
|
26
|
+
File.foreach(file_path) do |line|
|
15
27
|
app.execute(line: line)
|
16
28
|
end
|
17
|
-
|
18
|
-
# If we haven't reset the games_today to 0, we stopped before the end of a match day,
|
19
|
-
# so we need to print out the current top three
|
20
29
|
end
|
21
|
-
|
30
|
+
|
31
|
+
# If the input stops, we should print the final standings as the last match day,
|
32
|
+
# since it will be incomplete.
|
33
|
+
puts app.format_match_day(day: app.match_day, leaderboard: app.leaderboard)
|
@@ -16,22 +16,12 @@ module SoccerHelpers
|
|
16
16
|
# Valid: "San Jose Earthquakes 3, Santa Cruz Slugs 3",
|
17
17
|
# Invalid: "San Jose Earthquakes 3", "San Jose Earthquakes, Santa Cruz Slugs",
|
18
18
|
#
|
19
|
+
# We validate the input string with a regular expression, /([a-z-A-Z ]+)(\d+), ([a-zA-Z ]+)(\d+)/
|
20
|
+
#
|
19
21
|
# @param result [String] the string to validate
|
20
22
|
# @return [Boolean] is the input string a valid game result string?
|
21
23
|
def valid_game_result?(result:)
|
22
|
-
|
23
|
-
parts = result.split(',')
|
24
|
-
return false if parts.length != 2
|
25
|
-
|
26
|
-
# For each part, make sure it contains some numeric value, the value is an integer,
|
27
|
-
# and we have a team name that consists of alphabetic characters.
|
28
|
-
parts.each do |part|
|
29
|
-
return false if part.count('0-9').zero?
|
30
|
-
return false if part.count('a-zA-Z').zero?
|
31
|
-
end
|
32
|
-
|
33
|
-
# If we have passed all of the above checks, then the string is a valid game result
|
34
|
-
true
|
24
|
+
result.match?(/^([a-zA-Z ]+)(\d+), ([a-zA-Z ]+)(\d+)$/)
|
35
25
|
end
|
36
26
|
|
37
27
|
# extract_team_and_score answers the question:
|
@@ -68,7 +58,7 @@ module SoccerHelpers
|
|
68
58
|
end
|
69
59
|
|
70
60
|
# Zip the team names and scores together into a hash
|
71
|
-
|
61
|
+
team_names.zip(scores).to_h
|
72
62
|
end
|
73
63
|
|
74
64
|
# top_three answers the question: "What are the top three teams in the league?"
|
@@ -78,13 +68,17 @@ module SoccerHelpers
|
|
78
68
|
# param scores [Hash] a hash of team names and scores
|
79
69
|
# @return [Array] an array of the top three teams, in the format [team, score]
|
80
70
|
def top_three(scores:)
|
81
|
-
#
|
82
|
-
|
71
|
+
# Each item in scores has a key that corresponds to the team name,
|
72
|
+
# and a value that corresponds to the score.
|
73
|
+
# We want to sort the scores in descending order,
|
74
|
+
# and then take the top three scores.
|
75
|
+
#
|
76
|
+
# If there are any ties in the score, we want to return the tied teams in alphabetical order.
|
83
77
|
|
84
|
-
#
|
85
|
-
sorted_scores = scores.sort_by { |
|
78
|
+
# sort_by allows us to do a keyed sort over a hash, with multiple criteria
|
79
|
+
sorted_scores = scores.sort_by { |name, score| [-score, name] }
|
86
80
|
|
87
|
-
#
|
81
|
+
# Just return the top three from the sorted order
|
88
82
|
sorted_scores[0..2]
|
89
83
|
end
|
90
84
|
|
@@ -138,35 +132,18 @@ module SoccerHelpers
|
|
138
132
|
end
|
139
133
|
|
140
134
|
# match_day_over answers the question: "Is the match day over?"
|
141
|
-
#
|
142
|
-
#
|
143
|
-
# 2. It is any match day past 1, and the number of games today is equal to num_teams / 2
|
135
|
+
# It takes two Sets, teams_in_day, which represents the teams we've seen in a current day,
|
136
|
+
# and teams_in_match, which represents the teams from a match string
|
144
137
|
#
|
145
|
-
#
|
146
|
-
# but I prefer to call one function, rather than have two similar functions,
|
147
|
-
# (one for match day 1, and one for match day 2 and beyond).
|
138
|
+
# Then it returns whether or not any of the teams in teams_in_match already exist in teams_in_day.
|
148
139
|
#
|
149
|
-
#
|
150
|
-
#
|
140
|
+
# There is a different, slightly faster, but less readable solve for this.
|
141
|
+
# You can see a different approach in the diffs at https://gitlab.com/coolsoftwaretyler/coding-challenge-soccer/-/merge_requests/1
|
151
142
|
#
|
152
|
-
# param
|
153
|
-
# param
|
154
|
-
#
|
155
|
-
|
156
|
-
|
157
|
-
# @return [Boolean] is the current match day over?
|
158
|
-
def match_day_over?(leaderboard:, scores:, match_day:, num_teams:, games_today:)
|
159
|
-
# If this is the first match day, and the leaderboard already has a key that matches one of the input scores teams,
|
160
|
-
# then the match day is over
|
161
|
-
return true if match_day == 1 && leaderboard.key?(scores.keys.first)
|
162
|
-
|
163
|
-
return true if match_day == 1 && leaderboard.key?(scores.keys.last)
|
164
|
-
|
165
|
-
# If this is any match day past 1, and the number of games today is equal to num_leagues / 2,
|
166
|
-
# then the match day is over
|
167
|
-
return true if match_day > 1 && games_today == num_teams / 2
|
168
|
-
|
169
|
-
# Otherwise, the match day is not over yet.
|
170
|
-
false
|
143
|
+
# @param teams [Set] the teams in the current match
|
144
|
+
# @param teams_in_match [Set] the teams in the current match
|
145
|
+
# @return [Boolean] is the match day over?
|
146
|
+
def match_day_over?(teams_in_day:, teams_in_match:)
|
147
|
+
teams_in_day.intersection(teams_in_match).any?
|
171
148
|
end
|
172
149
|
end
|
data/lib/cool_soccer.rb
CHANGED
@@ -1,6 +1,7 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
require_relative 'cool_soccer/soccer_helpers'
|
4
|
+
require 'set'
|
4
5
|
|
5
6
|
# CoolSoccer is an "imperative shell"
|
6
7
|
# that allows the CLI to read a stream of game results from a soccer league,
|
@@ -15,39 +16,33 @@ class CoolSoccer
|
|
15
16
|
@leaderboard = {}
|
16
17
|
# We'll also keep track of the current match day, initialized at 1
|
17
18
|
@match_day = 1
|
18
|
-
#
|
19
|
-
|
20
|
-
@num_teams = 0
|
21
|
-
# Finally, we'll want to know how many games we've seen today,
|
22
|
-
# which we'll initialize at 0.
|
23
|
-
@games_today = 0
|
19
|
+
# We'll also have a Set that keeps tracks of the teams in a given day
|
20
|
+
@teams_in_day = Set.new
|
24
21
|
end
|
25
22
|
|
26
23
|
def execute(line:)
|
27
24
|
# If the line is invalid, skip it
|
28
25
|
return unless valid_game_result?(result: line)
|
29
26
|
|
30
|
-
# Increment the number of games we've played today
|
31
|
-
@games_today += 1
|
32
|
-
|
33
|
-
# If it's still match day 1, increment the number of teams by 2
|
34
|
-
@num_teams += 2 if @match_day == 1
|
35
|
-
|
36
27
|
# Extract the team names and scores from the line
|
37
28
|
scores = extract_team_and_score(result: line)
|
38
29
|
|
30
|
+
# From the scores, create a new set of team names in the given match
|
31
|
+
teams_in_match = Set.new(scores.keys)
|
32
|
+
|
39
33
|
# Check if the match day is over
|
40
|
-
if match_day_over?(
|
41
|
-
games_today: @games_today)
|
34
|
+
if match_day_over?(teams_in_day: @teams_in_day, teams_in_match: teams_in_match)
|
42
35
|
|
43
36
|
# Print out the current top three
|
44
37
|
puts "#{format_match_day(day: @match_day, leaderboard: @leaderboard)}\n"
|
45
38
|
|
46
|
-
# If so, increment the match day and reset the
|
39
|
+
# If so, increment the match day and reset the teams_in_day set
|
47
40
|
@match_day += 1
|
48
|
-
@
|
41
|
+
@teams_in_day = Set.new
|
49
42
|
end
|
50
43
|
|
44
|
+
# Add the teams_in_match to the teams_in_day set
|
45
|
+
@teams_in_day.merge(teams_in_match)
|
51
46
|
# Add the scores to the leaderboard
|
52
47
|
@leaderboard = update_leaderboard(leaderboard: @leaderboard, changes: scores)
|
53
48
|
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: cool_soccer
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.3.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Tyler Williams
|
@@ -44,6 +44,26 @@ dependencies:
|
|
44
44
|
- - ">="
|
45
45
|
- !ruby/object:Gem::Version
|
46
46
|
version: 1.29.1
|
47
|
+
- !ruby/object:Gem::Dependency
|
48
|
+
name: rubocop-rspec
|
49
|
+
requirement: !ruby/object:Gem::Requirement
|
50
|
+
requirements:
|
51
|
+
- - "~>"
|
52
|
+
- !ruby/object:Gem::Version
|
53
|
+
version: '2.11'
|
54
|
+
- - ">="
|
55
|
+
- !ruby/object:Gem::Version
|
56
|
+
version: 2.11.1
|
57
|
+
type: :development
|
58
|
+
prerelease: false
|
59
|
+
version_requirements: !ruby/object:Gem::Requirement
|
60
|
+
requirements:
|
61
|
+
- - "~>"
|
62
|
+
- !ruby/object:Gem::Version
|
63
|
+
version: '2.11'
|
64
|
+
- - ">="
|
65
|
+
- !ruby/object:Gem::Version
|
66
|
+
version: 2.11.1
|
47
67
|
- !ruby/object:Gem::Dependency
|
48
68
|
name: yard
|
49
69
|
requirement: !ruby/object:Gem::Requirement
|
@@ -73,7 +93,8 @@ files:
|
|
73
93
|
homepage: https://rubygems.org/gems/cool_soccer
|
74
94
|
licenses:
|
75
95
|
- MIT
|
76
|
-
metadata:
|
96
|
+
metadata:
|
97
|
+
rubygems_mfa_required: 'true'
|
77
98
|
post_install_message:
|
78
99
|
rdoc_options: []
|
79
100
|
require_paths:
|
@@ -82,7 +103,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
82
103
|
requirements:
|
83
104
|
- - ">="
|
84
105
|
- !ruby/object:Gem::Version
|
85
|
-
version:
|
106
|
+
version: 3.0.0
|
86
107
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
87
108
|
requirements:
|
88
109
|
- - ">="
|