[![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]