114 lines
No EOL
3.5 KiB
Text
114 lines
No EOL
3.5 KiB
Text
[](https://classroom.github.com/a/Z4IuCC1c)
|
|
:sectnums:
|
|
:nofooter:
|
|
:toc: left
|
|
:icons: font
|
|
:data-uri:
|
|
|
|
= OOB.02 -- Horse Race
|
|
|
|
This time you are going to read horse data from a CSV file and then simulate races between those horses, including output to the terminal.
|
|
|
|
[plantuml]
|
|
----
|
|
@startuml
|
|
|
|
class HorseRace {
|
|
+HorseRace(Horse[])
|
|
+int MaxSteps [const]
|
|
-int DelayMilliseconds [const]
|
|
-Horse[] _horses [readonly]
|
|
-bool IsFinished
|
|
|
|
+void PrintStartList()
|
|
+void PerformRace()
|
|
+void PrintResults()
|
|
-void MoveHorses()
|
|
-void DrawHorses()
|
|
-void AssignRanks()
|
|
-void SortByPosition()
|
|
}
|
|
class Horse {
|
|
+Horse(string, int, int)
|
|
+int Age [readonly]
|
|
+string Name [readonly]
|
|
+int Position [private set]
|
|
+int Rank
|
|
+int StartNumber [readonly]
|
|
|
|
+int CompareTo(Horse other)
|
|
+void Draw()
|
|
+void Move()
|
|
{static} +bool TryParse(string, int, out Horse?)
|
|
}
|
|
HorseRace "1" -r- "n" Horse: has
|
|
|
|
@enduml
|
|
----
|
|
|
|
== The `Horse` class
|
|
|
|
The `Horse` class, unsurprisingly, represents a horse.
|
|
|
|
Each horse has:
|
|
|
|
* A name
|
|
* An age
|
|
* An assigned starting number
|
|
|
|
During the race and based on the race results each horse gets assigned:
|
|
|
|
* A varying position
|
|
* A final rank
|
|
|
|
=== Method Requirements
|
|
|
|
Additional specifications for some methods -- primarily rely on the XML Doc.
|
|
|
|
* `CompareTo`
|
|
** Subtract _from_ the `other` value to get the correct `int` value
|
|
* `Move`
|
|
** The probability of moving one position ('field') forward is ~33%
|
|
*** Make sure to use the `Random` instance in `RandomProvider`
|
|
* `TryParse`
|
|
** The name cannot be empty
|
|
** The age of a horse has to be in the stem:[0 < x <= 20] range
|
|
** The starting number may not be negative
|
|
|
|
== Importing Data with the `HorseImporter` class
|
|
|
|
The `Horse` class provides a `TryParse` _factory method_, yet it still needs to be called for each CSV line which in turn needs to be read from a file.
|
|
That is the job of the `_static_` `HorseImporter` class.
|
|
|
|
Consider the usual rules for reading CSV files:
|
|
|
|
* The file has to exist
|
|
* It has to have a header and _at least one_ valid data row
|
|
* Invalid data rows are skipped
|
|
* If no data could be parsed an _empty_ array is returned
|
|
* Make sure the returned array does not contain any `null` values
|
|
|
|
NOTE: This is a `static` class providing a single, _stateless_ method
|
|
|
|
== Performing the race with the `HorseRace` class
|
|
|
|
A race can only happen when the horses are present.
|
|
Thus, it is _dependent_ on the array of horses => required to construct an instance of the `HorseRace` class.
|
|
|
|
* The `IsFinished` property is set to `true` once the first horse reaches the finish line
|
|
** Subsequent move operations are ignored
|
|
** The finish line is reached when the horse's `Position` equals `MAX_STEPS`
|
|
* `MoveHorses` applies a 'move order' to _each_ of the horses in the race
|
|
* Make sure to print in the expected format
|
|
** => see sample run below
|
|
** Remember that the `Horse` class already provides a `Draw` method!
|
|
* Ranks are assigned based on the position (at the end of the race), thus, horses with the same position also have the same rank
|
|
** Ranks start at 1 (not 0)
|
|
* When sorting make sure to use the `CompareTo` method of the `Horse` class
|
|
** Horses know how to compare to each other _themselves_!
|
|
|
|
NOTE: Do not worry about (already implemented) the delay between horse movements. We'll discuss various methods for adding delays to a program in a few months
|
|
|
|
=== Sample Run
|
|
|
|
video::pics/sample_run.mp4[width=480,opts=autoplay] |