mirror of
https://github.com/coding-horror/basic-computer-games.git
synced 2025-12-29 06:05:36 -08:00
Simplify Tower (C#) folder structure
This commit is contained in:
33
90_Tower/csharp/Models/Needle.cs
Normal file
33
90_Tower/csharp/Models/Needle.cs
Normal file
@@ -0,0 +1,33 @@
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
|
||||
namespace Tower.Models
|
||||
{
|
||||
internal class Needle : IEnumerable<int>
|
||||
{
|
||||
private readonly Stack<int> _disks = new Stack<int>();
|
||||
|
||||
public bool IsEmpty => _disks.Count == 0;
|
||||
|
||||
public int Top => _disks.TryPeek(out var disk) ? disk : default;
|
||||
|
||||
public bool TryPut(int disk)
|
||||
{
|
||||
if (_disks.Count == 0 || disk < _disks.Peek())
|
||||
{
|
||||
_disks.Push(disk);
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public bool TryGetTopDisk(out int disk) => _disks.TryPop(out disk);
|
||||
|
||||
public IEnumerator<int> GetEnumerator() =>
|
||||
Enumerable.Repeat(0, 7 - _disks.Count).Concat(_disks).GetEnumerator();
|
||||
|
||||
IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();
|
||||
}
|
||||
}
|
||||
87
90_Tower/csharp/Models/Towers.cs
Normal file
87
90_Tower/csharp/Models/Towers.cs
Normal file
@@ -0,0 +1,87 @@
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Tower.Resources;
|
||||
|
||||
namespace Tower.Models
|
||||
{
|
||||
internal class Towers : IEnumerable<(int, int, int)>
|
||||
{
|
||||
private static int[] _availableDisks = new[] { 15, 13, 11, 9, 7, 5, 3 };
|
||||
|
||||
private readonly Needle[] _needles = new[] { new Needle(), new Needle(), new Needle() };
|
||||
private readonly int _smallestDisk;
|
||||
|
||||
public Towers(int diskCount)
|
||||
{
|
||||
foreach (int disk in _availableDisks.Take(diskCount))
|
||||
{
|
||||
this[1].TryPut(disk);
|
||||
_smallestDisk = disk;
|
||||
}
|
||||
}
|
||||
|
||||
private Needle this[int i] => _needles[i-1];
|
||||
|
||||
public bool Finished => this[1].IsEmpty && this[2].IsEmpty;
|
||||
|
||||
public bool TryFindDisk(int disk, out int needle, out string message)
|
||||
{
|
||||
needle = default;
|
||||
message = default;
|
||||
|
||||
if (disk < _smallestDisk)
|
||||
{
|
||||
message = Strings.DiskNotInPlay;
|
||||
return false;
|
||||
}
|
||||
|
||||
for (needle = 1; needle <= 3; needle++)
|
||||
{
|
||||
if (this[needle].Top == disk) { return true; }
|
||||
}
|
||||
|
||||
message = Strings.DiskUnavailable;
|
||||
return false;
|
||||
}
|
||||
|
||||
public bool TryMoveDisk(int from, int to)
|
||||
{
|
||||
if (!this[from].TryGetTopDisk(out var disk))
|
||||
{
|
||||
throw new InvalidOperationException($"Needle {from} is empty");
|
||||
}
|
||||
|
||||
if (this[to].TryPut(disk)) { return true; }
|
||||
|
||||
this[from].TryPut(disk);
|
||||
return false;
|
||||
}
|
||||
|
||||
public IEnumerator<(int, int, int)> GetEnumerator() => new TowersEnumerator(_needles);
|
||||
|
||||
IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();
|
||||
|
||||
private class TowersEnumerator : IEnumerator<(int, int, int)>
|
||||
{
|
||||
private readonly List<IEnumerator<int>> _enumerators;
|
||||
|
||||
public TowersEnumerator(Needle[] needles)
|
||||
{
|
||||
_enumerators = needles.Select(n => n.GetEnumerator()).ToList();
|
||||
}
|
||||
|
||||
public (int, int, int) Current =>
|
||||
(_enumerators[0].Current, _enumerators[1].Current, _enumerators[2].Current);
|
||||
|
||||
object IEnumerator.Current => Current;
|
||||
|
||||
public void Dispose() => _enumerators.ForEach(e => e.Dispose());
|
||||
|
||||
public bool MoveNext() => _enumerators.All(e => e.MoveNext());
|
||||
|
||||
public void Reset() => _enumerators.ForEach(e => e.Reset());
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user