:sectnums:
:nofooter:
:toc: left
:icons: font
:data-uri:
:source-highlighter: highlightjs
:stem: latexmath

= Int.05 -- Numbers

This is a simple training exercise without any interesting background story 😉

== `NumberString`

Given a string consisting of numbers and digits in any order and combination, the goal is to extract all numbers while preserving order.
This extraction is supposed to happen by means of enumeration.

[plantuml]
----
@startuml
hide empty methods
hide empty fields

class DigitEnumerator <<sealed>> {
    -string _text [readonly]
    -int _index
    +DigitEnumerator(string)
}
interface IEnumerator<int> {}
class NumberString <<sealed>> {
    -string _text [readonly]
    -int? _numericValue
    +int NumericValue [readonly]
    +int this[int] [readonly]
    +NumberString(string)
}
interface IEnumerable<int> {}
interface IComparable<NumberString> {}

IEnumerator <|.. DigitEnumerator
IEnumerable <|.. NumberString
IComparable <|.. NumberString

@enduml
----

=== `DigitEnumerator`

* Enumerates digits in a `NumberString`
** Example: `a3bc1jki45u` => `3`, `1`, `4`, `5`
* Ignores all non-digit characters (letters)
* Implements the enumerator pattern

=== `NumberString`

* A string containing both letters and digits
* Can be enumerated
** Using a `DigitEnumerator`
* Can be compared
** By directly implementing `IComparable` -- no comparer required
** Comparison is based on the `NumericValue`
* Has a `NumericValue` property which represents the number encoded in the string
** Example: `a3bc1jki45u` => `3145`
** This property is _cached_ => only calculate at first call!
* It additionally has an _indexer_
** Accesses only the _digits_
*** Utilizing the enumerator
** Example: `a1bc3jki45u`, assessing index 2 => `3`
* Make sure to implement all _equality_ members including operators & hash code

== `NumberFactory`

A kind of digital factory which is able to give us a _something_ (a `INumbers` instance) which provides numbers which comply to a certain condition and are within the specified range.

[plantuml]
----
@startuml
hide empty methods
hide empty fields

class EvenNumbers <<sealed>> {}
class OddNumbers <<sealed>> {}
class PrimeNumbers <<sealed>> {}
class SquareNumbers <<sealed>> {}
abstract class AbstractNumbers {
    -List<long> _list;
    #AbstractNumbers(long, long)
    {abstract} #bool PickupNumber(long)
    -void GenerateNumbers()
}
interface INumbers {
    +long this[int] [readonly]
    +long LowerBound [readonly]
    +long UpperBound [readonly]
    +int Length [readonly]
}
interface IEnumerable<long> {}
interface IEnumerator<long> {}
enum NumberType {
    Even
    Odd
    Square
    Prime
}
static class Factory {
    {static} +INumbers Create(NumberType, long, long)
}
class NumbersEnumerator <<sealed>> {
    -int Index
    -List<long> List [readonly]
    +NumbersEnumerator(List<long>)
}

AbstractNumbers <|-- EvenNumbers
AbstractNumbers <|-- OddNumbers
AbstractNumbers <|-- PrimeNumbers
AbstractNumbers <|-- SquareNumbers
INumbers <|.. AbstractNumbers
IEnumerable <|.. INumbers
IEnumerator <|.. NumbersEnumerator

@enduml
----

=== `NumbersEnumerator`

* A very straight forward implementation of an `IEnumerator` for (`long`) numbers
* `Current` should return `-1` if the position is invalid

=== `INumbers`

* Defines the lower and upper bound of the range the numbers are picked from
* Ensures that implementations will provide an indexer for accessing the n-th number fulfilling the specific condition in the range
* Allows to get the total amount of number which fulfill the requirements
* Implements `IEnumerable<long>`
** We are using `long` instead of `int` to allow for very big numbers as well 😉

=== `AbstractNumbers`

* A base class for all number generators providing some common, shared implementations
* The indexer should return `-1` for invalid index values
* Make use of the `NumbersEnumerator`
* `GenerateNumbers` internally calls `PickNumber` which will be implemented by subclasses to decide which numbers to pick -- this check will be done for each number in the specified range
** Picked numbers should be stored in the list
* Hint: The constructor should call `GenerateNumbers`

=== Generator Implementations

* `EvenNumbers`: selects even numbers in the given range
* `OddNumbers`: selects odd numbers in the given range
* `PrimeNumbers`: selects prime numbers in the given range
** A simple loop-based implementation (just as we have implemented in first grade) is sufficient, but don't be overly wasteful with system resources
* `SquareNumbers`: selects square numbers in the given range
** https://en.wikipedia.org/wiki/Square_number[What is a square number]

=== `Factory`

* A static factory class which is able to create instances of `INumbers` implementations
* If an unknown `NumberType` is specified, return `null`
** Hint: to do that you'll need the `!` operator which is fine in this one case 😉

== Sample Run

image::pics/sample_run.png[Sample Run]