|
|
@@ -2,7 +2,6 @@
|
|
|
using System.Collections.Generic;
|
|
|
using System.Diagnostics;
|
|
|
using System.IO;
|
|
|
-using System.Linq;
|
|
|
|
|
|
namespace D11._1
|
|
|
{
|
|
|
@@ -71,27 +70,26 @@ namespace D11._1
|
|
|
return generators >= 0 && unpluggedMicroships == 0;
|
|
|
}
|
|
|
|
|
|
- static readonly int nelement = Enum.GetValues(typeof(EnumElement)).Length;
|
|
|
+ static readonly int NElements = Enum.GetValues(typeof(EnumElement)).Length;
|
|
|
public Floor()
|
|
|
{
|
|
|
for (int i = 0; i < Objects.Length; ++i)
|
|
|
- Objects[i] = new bool[nelement];
|
|
|
+ Objects[i] = new bool[NElements];
|
|
|
}
|
|
|
|
|
|
public object Clone()
|
|
|
{
|
|
|
var floor = new Floor();
|
|
|
+
|
|
|
for (var i = 0; i < Objects.Length; i++)
|
|
|
- for (var j = 0; j < Objects[i].Length; ++j)
|
|
|
- floor.Objects[i][j] = Objects[i][j];
|
|
|
+ Objects[i].CopyTo(floor.Objects[i], 0);
|
|
|
+
|
|
|
return floor;
|
|
|
}
|
|
|
|
|
|
public bool Set(EnumType type, EnumElement element, bool value) => Objects[(int)type][(int)element] = value;
|
|
|
public bool Add(EnumType type, EnumElement element) => Set(type, element, true);
|
|
|
|
|
|
- public override bool Equals(object obj) => obj is Floor floor && floor.GetHashCode() == GetHashCode();
|
|
|
-
|
|
|
public override int GetHashCode()
|
|
|
{
|
|
|
//int h1 = 0, h2 = 0;
|
|
|
@@ -104,6 +102,18 @@ namespace D11._1
|
|
|
|
|
|
//return h1 * 100 + h2;
|
|
|
|
|
|
+ /*
|
|
|
+ * Firts hash method takes into account wich microship and generator element is
|
|
|
+ * present on the floor.
|
|
|
+ *
|
|
|
+ * The following methods just relies on the fact that it does not matter
|
|
|
+ * which generators or microships are on the floor but that there are
|
|
|
+ * paired microship/generators (it does not matter wich ones) and unpaired
|
|
|
+ * microships and generators (still, it does not matter which ones)
|
|
|
+ *
|
|
|
+ * * ==> ENORMOUS performance gain : ~8s => 150ms
|
|
|
+ */
|
|
|
+
|
|
|
int paired = 0, unpairedGen = 0, unpairedMicroship = 0;
|
|
|
|
|
|
for (var i = 0; i < Objects[0].Length; ++i)
|
|
|
@@ -121,8 +131,6 @@ namespace D11._1
|
|
|
}
|
|
|
}
|
|
|
|
|
|
- public override bool Equals(object obj) => obj is Facility facility && facility.GetHashCode() == GetHashCode() && facility.Elevator == Elevator;
|
|
|
-
|
|
|
public override int GetHashCode()
|
|
|
{
|
|
|
int hash = 0;
|
|
|
@@ -138,22 +146,20 @@ namespace D11._1
|
|
|
Floors = new Floor[Floors.Length]
|
|
|
};
|
|
|
|
|
|
- for (var i = 0; i < Floors.Length; ++i) nf.Floors[i] = (Floor) Floors[i].Clone();
|
|
|
+ for (var i = 0; i < Floors.Length; ++i) nf.Floors[i] = (Floor)Floors[i].Clone();
|
|
|
return nf;
|
|
|
}
|
|
|
}
|
|
|
|
|
|
class Program
|
|
|
{
|
|
|
- static readonly EnumElement[] aelement = Enum.GetValues(typeof(EnumElement)) as EnumElement[];
|
|
|
+ static readonly EnumElement[] AllElements = Enum.GetValues(typeof(EnumElement)) as EnumElement[];
|
|
|
+ static readonly int[] ElevatorDirections = new[] { -1, +1 };
|
|
|
|
|
|
- static void RunFacilityTest(Facility startFacility)
|
|
|
+ static int RunFacilityTest(Facility startFacility)
|
|
|
{
|
|
|
- var upd = new [] { -1, +1 };
|
|
|
- var cmp = Comparer<(Facility, int)>.Create((a, b) => a.Item2.CompareTo(b.Item2));
|
|
|
-
|
|
|
var queue = new Queue<(Facility facility, int step)>();
|
|
|
- var tested = new HashSet<Facility>();
|
|
|
+ var tested = new HashSet<int>();
|
|
|
|
|
|
queue.Enqueue((startFacility, 0));
|
|
|
|
|
|
@@ -161,40 +167,54 @@ namespace D11._1
|
|
|
{
|
|
|
(Facility facility, int step) = queue.Dequeue();
|
|
|
|
|
|
- if (facility.IsOk())
|
|
|
- {
|
|
|
- Console.WriteLine($"The answer is : {step}");
|
|
|
- break;
|
|
|
- }
|
|
|
+ if (facility.IsOk()) return step;
|
|
|
|
|
|
- foreach (((EnumType t, EnumElement e) c1, (EnumType t, EnumElement e)? c2) in GetCandidates(facility))
|
|
|
+ foreach (((EnumType, EnumElement) first, (EnumType, EnumElement)? second) in GetCandidates(facility))
|
|
|
{
|
|
|
- foreach (var direction in upd)
|
|
|
+ foreach (var direction in ElevatorDirections)
|
|
|
{
|
|
|
if (facility.Elevator + direction < 0 || facility.Elevator + direction >= facility.Floors.Length) continue;
|
|
|
|
|
|
- Facility nfacility = BuildNewFacility(facility, c1, c2, direction);
|
|
|
- if (nfacility.CurrentFloor.IsValid() == false) continue;
|
|
|
+ Facility nfacility = BuildNewFacility(facility, first, second, direction);
|
|
|
+ if (nfacility == null) continue;
|
|
|
|
|
|
- if (tested.Contains(nfacility)) continue;
|
|
|
- tested.Add(nfacility);
|
|
|
+ int hash = nfacility.GetHashCode() ^ nfacility.Elevator;
|
|
|
+
|
|
|
+ if (tested.Contains(hash)) continue;
|
|
|
+ tested.Add(hash);
|
|
|
|
|
|
queue.Enqueue((nfacility, step + 1));
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
+
|
|
|
+ throw new Exception();
|
|
|
}
|
|
|
|
|
|
- private static Facility BuildNewFacility(Facility facility, (EnumType t, EnumElement e) c1, (EnumType t, EnumElement e)? c2, int d)
|
|
|
+ private static Facility BuildNewFacility(Facility facility, (EnumType t, EnumElement e) first, (EnumType t, EnumElement e)? second, int direction)
|
|
|
{
|
|
|
+ /* Slight optimisation
|
|
|
+ * Before cloning the entire facility, ensures that the next state for the current floor
|
|
|
+ * is valid as cloning a single floor is less consuming.
|
|
|
+ */
|
|
|
+ var clone = facility.Floors[facility.Elevator + direction].Clone() as Facility.Floor;
|
|
|
+
|
|
|
+ clone.Set(first.t, first.e, true);
|
|
|
+ if (second.HasValue) clone.Set(second.Value.t, second.Value.e, true);
|
|
|
+
|
|
|
+ if (clone.IsValid() == false) return null;
|
|
|
+
|
|
|
+ // -----------
|
|
|
+
|
|
|
var nfacility = facility.Clone() as Facility;
|
|
|
- nfacility.CurrentFloor.Objects[(int)c1.t][(int)c1.e] = false;
|
|
|
- if (c2.HasValue) nfacility.CurrentFloor.Objects[(int)c2?.t][(int)c2?.e] = false;
|
|
|
|
|
|
- nfacility.Elevator += d;
|
|
|
+ nfacility.CurrentFloor.Set(first.t, first.e, false);
|
|
|
+ if (second.HasValue) nfacility.CurrentFloor.Set(second.Value.t, second.Value.e, false);
|
|
|
+
|
|
|
+ nfacility.Elevator += direction;
|
|
|
+
|
|
|
+ nfacility.Floors[nfacility.Elevator] = clone;
|
|
|
|
|
|
- nfacility.CurrentFloor.Objects[(int)c1.t][(int)c1.e] = true;
|
|
|
- if (c2.HasValue) nfacility.CurrentFloor.Objects[(int)c2?.t][(int)c2?.e] = true;
|
|
|
return nfacility;
|
|
|
}
|
|
|
|
|
|
@@ -202,7 +222,7 @@ namespace D11._1
|
|
|
{
|
|
|
var all = new List<(EnumType, EnumElement)>();
|
|
|
|
|
|
- foreach (EnumElement element in aelement)
|
|
|
+ foreach (EnumElement element in AllElements)
|
|
|
{
|
|
|
if (facility.CurrentFloor.Objects[(int)EnumType.Generator][(int)element]) all.Add((EnumType.Generator, element));
|
|
|
if (facility.CurrentFloor.Objects[(int)EnumType.Microship][(int)element]) all.Add((EnumType.Microship, element));
|
|
|
@@ -248,7 +268,8 @@ namespace D11._1
|
|
|
|
|
|
var sw = Stopwatch.StartNew();
|
|
|
|
|
|
- RunFacilityTest(facility);
|
|
|
+ var answer = RunFacilityTest(facility);
|
|
|
+ Console.WriteLine($"The answer is : {answer}");
|
|
|
|
|
|
sw.Stop();
|
|
|
|
|
|
@@ -284,7 +305,8 @@ namespace D11._1
|
|
|
|
|
|
var sw = Stopwatch.StartNew();
|
|
|
|
|
|
- RunFacilityTest(facility);
|
|
|
+ var answer = RunFacilityTest(facility);
|
|
|
+ Console.WriteLine($"The answer is : {answer}");
|
|
|
|
|
|
sw.Stop();
|
|
|
|