[![Review Assignment Due Date](https://classroom.github.com/assets/deadline-readme-button-22041afd0340ce965d47ae6ef1cefeee28c7c493a6346c4f15d667ab976d596c.svg)](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]