remove the Generator hierarchy and the IGenerator interface

remove the Numbers class.

Limits are now passed to the constructor of each Lottery class.

{Generator}.Generate is now a static method.

Spin button renamed to Play button
This commit is contained in:
onyx-and-iris 2024-09-27 18:34:25 +01:00
parent 9e678865cd
commit ff4d77283c
6 changed files with 27 additions and 140 deletions

View File

@ -1,101 +1,19 @@
namespace Lottery namespace Lottery
{ {
record Limits(int Count, int Lower, int Upper); internal class Generator
/// <summary>
/// Abstract base class for generators
/// All subclasses must implement the IGenerator interface
/// Provides some default implementation
/// </summary>
class Generator : IGenerator
{ {
public virtual Numbers Generate() => throw new NotImplementedException(); public static List<int> Generate(Limits Limits)
protected static void FillNumbers(List<int> NumberList, Limits Limits)
{ {
List<int> Candidates = Enumerable.Range(Limits.Lower, Limits.Upper).ToList(); List<int> Candidates = Enumerable.Range(Limits.Lower, Limits.Upper).ToList();
List<int> Numbers = [];
for (int i = 0; i < Limits.Count; i++) for (int i = 0; i < Limits.Count; i++)
{ {
int RandomIndex = Random.Shared.Next(Candidates.Count); int RandomIndex = Random.Shared.Next(Candidates.Count);
NumberList.Add(Candidates[RandomIndex]); Numbers.Add(Candidates[RandomIndex]);
Candidates.RemoveAt(RandomIndex); Candidates.RemoveAt(RandomIndex);
} }
NumberList.Sort(); Numbers.Sort();
}
protected static void FillNumbers(
List<int> NormalList, Limits NormalLimits,
List<int> SpecialList, Limits SpecialLimits)
{
FillNumbers(NormalList, NormalLimits);
FillNumbers(SpecialList, SpecialLimits);
}
}
/// <summary>
/// Concrete UKLottoGenerator class.
/// Generates six balls from 1 to 59
/// </summary>
class UKLottoGenerator : Generator
{
private readonly Limits Limits = new(6, 1, 59);
public override Numbers Generate()
{
Numbers Numbers = new([]);
Generator.FillNumbers(Numbers.Normal, Limits);
return Numbers;
}
}
/// <summary>
/// Concrete EuroMillionsGenerator class.
/// Generates five balls from 1 to 50 and two balls from 1 to 12
/// </summary>
class EuroMillionsGenerator : Generator
{
private readonly Limits NormalLimits = new(5, 1, 50);
private readonly Limits SpecialLimits = new(2, 1, 12);
public override Numbers Generate()
{
NumbersWithSpecial Numbers = new([], []);
Generator.FillNumbers(Numbers.Normal, NormalLimits, Numbers.Special, SpecialLimits);
return Numbers;
}
}
/// <summary>
/// Concrete SetForLifeGenerator class.
/// Generates five balls from 1 to 47 and one ball from 1 to 10
/// </summary>
class SetForLifeGenerator : Generator
{
private readonly Limits NormalLimits = new(5, 1, 47);
private readonly Limits SpecialLimits = new(1, 1, 10);
public override Numbers Generate()
{
NumbersWithSpecial Numbers = new([], []);
Generator.FillNumbers(Numbers.Normal, NormalLimits, Numbers.Special, SpecialLimits);
return Numbers;
}
}
/// <summary>
/// Concrete ThunderBallGenerator class.
/// Generates fives balls from 1 to 39 and one ball from 1 to 14
/// </summary>
class ThunderBallGenerator : Generator
{
private readonly Limits NormalLimits = new(5, 1, 39);
private readonly Limits SpecialLimits = new(1, 1, 14);
public override Numbers Generate()
{
NumbersWithSpecial Numbers = new([], []);
Generator.FillNumbers(Numbers.Normal, NormalLimits, Numbers.Special, SpecialLimits);
return Numbers; return Numbers;
} }
} }

View File

@ -1,10 +0,0 @@
namespace Lottery
{
/// <summary>
/// All Generators must implement the Generate method
/// </summary>
interface IGenerator
{
Numbers Generate();
}
}

View File

@ -1,53 +1,36 @@
namespace Lottery namespace Lottery
{ {
/// <summary> internal class Lottery(Limits limits)
/// Base Lottery class, use it for lotteries that generate a single set of numbers.
/// SpecialIdentifier may be overridden for Lotteries with Special values.
/// </summary>
/// <param name="Generator">A fully formed Generator</param>
internal class Lottery(IGenerator Generator)
{ {
protected Numbers GenerateNumbers() => Generator.Generate(); protected Limits Limits => limits;
public virtual string Play() => $"Numbers: {string.Join(", ", Generator.Generate(Limits))}";
public virtual string Output()
{
var numbers = GenerateNumbers();
return $"Numbers: {string.Join(", ", numbers.Normal)}";
}
} }
/// <summary> internal class LotteryWithSpecial(Limits limits, Limits specialLimits) : Lottery(limits)
/// Abstract base class, for lotteries with special values.
/// It subclasses Lottery.
/// </summary>
/// <param name="Generator">A fully formed Generator</param>
internal class LotteryWithSpecial(IGenerator Generator) : Lottery(Generator)
{ {
protected Limits SpecialLimits => specialLimits;
protected virtual string SpecialIdentifier => throw new NotImplementedException(); protected virtual string SpecialIdentifier => throw new NotImplementedException();
public override string Output() public override string Play()
{ {
var numbers = GenerateNumbers() as NumbersWithSpecial
?? throw new LotteryException($"Unable to generate numbers for {this}");
return string.Join("\t", [ return string.Join("\t", [
$"Numbers: {string.Join(", ", numbers.Normal)}", $"Numbers: {string.Join(", ", Generator.Generate(Limits))}",
$"{SpecialIdentifier}: {string.Join(", ", numbers.Special)}", $"{SpecialIdentifier}: {string.Join(", ", Generator.Generate(SpecialLimits))}",
]); ]);
} }
} }
internal class EuroMillionsLotteryWithSpecial(IGenerator Generator) : LotteryWithSpecial(Generator) internal class EuroMillionsLottery(Limits limits, Limits specialLimits) : LotteryWithSpecial(limits, specialLimits)
{ {
protected override string SpecialIdentifier => "Lucky Stars"; protected override string SpecialIdentifier => "Lucky Stars";
} }
internal class SetForLifeLotteryWithSpecial(IGenerator Generator) : LotteryWithSpecial(Generator) internal class SetForLifeLottery(Limits limits, Limits specialLimits) : LotteryWithSpecial(limits, specialLimits)
{ {
protected override string SpecialIdentifier => "Life Ball"; protected override string SpecialIdentifier => "Life Ball";
} }
internal class ThunderballLotteryWithSpecial(IGenerator Generator) : LotteryWithSpecial(Generator) internal class ThunderballLottery(Limits limits, Limits specialLimits) : LotteryWithSpecial(limits, specialLimits)
{ {
protected override string SpecialIdentifier => "Thunderball"; protected override string SpecialIdentifier => "Thunderball";
} }

View File

@ -9,9 +9,9 @@
Spacing="25"> Spacing="25">
<Picker x:Name="LotteryPicker" Title="Pick your lottery" SelectedIndexChanged="LotteryPicker_SelectedIndexChanged" /> <Picker x:Name="LotteryPicker" Title="Pick your lottery" SelectedIndexChanged="LotteryPicker_SelectedIndexChanged" />
<Label x:Name="NumbersLabel" Text="Click Spin button to generate" HorizontalOptions="Center" FontSize="Medium" /> <Label x:Name="NumbersLabel" Text="Click Play button to generate numbers" HorizontalOptions="Center" FontSize="Medium" />
<Button x:Name="SpinButton" Text="Spin" Clicked="SpinButton_Clicked"/> <Button x:Name="PlayButton" Text="Play" Clicked="PlayButton_Clicked"/>
</VerticalStackLayout> </VerticalStackLayout>
</ScrollView> </ScrollView>

View File

@ -1,12 +1,14 @@
namespace Lottery namespace Lottery
{ {
internal record Limits(int Count, int Lower, int Upper);
public partial class MainPage : ContentPage public partial class MainPage : ContentPage
{ {
readonly List<Lottery> Lotteries = [ readonly List<Lottery> Lotteries = [
new Lottery(new UKLottoGenerator()), new Lottery(limits: new Limits(6, 1, 59)),
new EuroMillionsLotteryWithSpecial(new EuroMillionsGenerator()), new EuroMillionsLottery(limits: new Limits(5, 1, 50), specialLimits: new Limits(2, 1, 12)),
new SetForLifeLotteryWithSpecial(new SetForLifeGenerator()), new SetForLifeLottery(limits: new Limits(5, 1, 47), specialLimits: new Limits(1, 1, 10)),
new ThunderballLotteryWithSpecial(new ThunderBallGenerator()) new ThunderballLottery(limits: new Limits(5, 1, 39), specialLimits: new Limits(1, 1, 14))
]; ];
const KindOfLottery DefaultLottery = KindOfLottery.Uk; const KindOfLottery DefaultLottery = KindOfLottery.Uk;
Lottery Lottery; Lottery Lottery;
@ -22,9 +24,9 @@
Lottery = Lotteries[LotteryPicker.SelectedIndex]; Lottery = Lotteries[LotteryPicker.SelectedIndex];
} }
private void SpinButton_Clicked(object sender, EventArgs e) private void PlayButton_Clicked(object sender, EventArgs e)
{ {
NumbersLabel.Text = Lottery.Output(); NumbersLabel.Text = Lottery.Play();
SemanticScreenReader.Announce(NumbersLabel.Text); SemanticScreenReader.Announce(NumbersLabel.Text);
} }

View File

@ -1,6 +0,0 @@
namespace Lottery
{
internal record Numbers(List<int> Normal);
internal record NumbersWithSpecial(List<int> Normal, List<int> Special) : Numbers(Normal);
}