Do you know what it is?
Yes, this is a log-or-something text file, but more importantly – this is something that I had in mind when starting this project. It’s a legit football game generated by Football Manager, presented in a debug form. Pretty cool if you have been wanting it for the last 3 months, believe me.
Why it’s cool
From this point, it’s really easy to add to the game generation. As mentioned before, a game generates actions (dubbed #1
, #2
, etc.), and actions generate phases ([Snap]
, [Run]
, [Tackle]
etc).
There is some logic related to generating phases (eg. which run ends with a tackle and which one ends with a touchdown), but more general computations (eg. which attempt is it going to be) are calculated on the action or game level. Therefore, If I want to add a new phase to the game or change an existing one, I should be able to do this inside only that phase generator.
Why so late
This time it took 28 commits across 2 weeks, really. Some commits are big, being solid, but much needed refactoring, outcomes of many-hour sittings.
The part that took much time was “progress” with the ball on the pitch. Namely, the progress can mean moving the ball to the left, or to the right. This depends on which team is facing where at any given moment, and that in turn changes constantly during the game. And it’s important to do it right because core functionalities like touchdown or first-down decisions depend on it.
The problem couldn’t have been postponed, because during kickoff – the first phase of each game – the ball is received and already now progress is being flipped. So very early in the game, we should be ready for flipping progress. And bear in mind that the progress flips with every turnover.
I’m fairly happy about the solution to this problem. It has been delegated to Markers and Progress (and Pseudomarkers) classes, each of them existing in two formats – Countup (where progress means more yards) and Countdown (where progress means fewer yards). For example:
lib/football_manager/metrics/marker_countdown.rb
class MarkerCountdown
def initialize(first_down_yards:)
@first_down_yards = first_down_yards
@target = first_down_yards.from_left - 10
end
attr_reader :first_down_yards, :target
def crossed?(yards)
yards.from_left < target
end
def starting_progress
ProgressCountdown.new
end
end
lib/football_manager/metrics/progress_countdown.rb
class ProgressCountdown
def to_yards(progress_num)
Yards.new(-progress_num)
end
def to_range(first, last, yards)
YardsFromRange.new(-last, -first, -yards)
end
def flip
ProgressCountup.new
end
def touchdown?(yards_in_pitch)
yards_in_pitch <= 0
end
def ==(o)
self.class == o.class
end
end
Tests
Tests do pay off. I did a lot of redesign like extracting MatchState
out of MatchGenerator
class. That would be virtually impossible without rewriting from scratch both of them if I didn’t have tests.
My tests have gaps, but most importantly – I can trust them. Whenever I feel I might need more of the safety net, I do add tests, simple as that.
Some interesting pieces of my current testing env:
- Factory for default fixtures written from scratch
- Test for generating a match for the purpose of this blog (I think I prefer to comment out this whole file rather than using
xit
– due to an annoying yellow warning in the console every time I run tests)
Stay tunes, it’s exciting time for all the (American) football fans!
Leave a Reply