Bah, this is becoming a bit boring, but I really wanted to share this code with you guys. This shows how to ease up algorithmics by using an IEnumberable. (Just semantic sweetness).
[ 1 2 5 10 15 ] [ ] / L / 0
[ 2 10 15 ] [ 1 5 ] / R / 5
[ 1 2 10 15 ] [ 5 ] / L / 6
[ 10 15 ] [ 1 2 5 ] / R / 8
[ 1 10 15 ] [ 2 5 ] / L / 9
[ 1 ] [ 2 5 10 15 ] / R / 24
[ 1 2 ] [ 5 10 15 ] / L / 26
[ ] [ 1 2 5 10 15 ] / R / 28
// C# code
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace NightBridge
{
class Program
{
class Coord : IComparable<Coord>
{
public enum Position
{
LEFT,
RIGHT
}
public List<int> left;
public List<int> right;
public Position position;
public Coord()
{
left = new List<int>();
right = new List<int>();
position = Position.LEFT;
}
public override string ToString()
{
StringBuilder result = new StringBuilder();
result.Append("[ ");
foreach(var i in left)
result.Append(i + " ");
result.Append("] [ ");
foreach(var i in right)
result.Append(i + " ");
result.Append("] / ");
result.Append(position == Position.LEFT ? "L" : "R");
return result.ToString();
}
public int CompareTo(Coord other)
{
if(position != other.position)
if(position == Position.LEFT) return -1;
else return +1;
if(left.Count < other.left.Count)
return -1;
else if(left.Count > other.left.Count)
return +1;
else if(right.Count < other.right.Count)
return -1;
else if(right.Count > other.right.Count)
return +1;
for(int i = 0; i < left.Count; i++) {
if(left[i] < other.left[i])
return -1;
else if(left[i] > other.left[i])
return +1;
}
for(int i = 0; i < right.Count; i++) {
if(right[i] < other.right[i])
return -1;
else if(right[i] > other.right[i])
return +1;
}
return 0;
}
}
class State : IComparable<State>
{
public Coord previous;
public int move;
public int sum;
public Coord coord;
public State()
{
previous = null;
sum = 0;
move = 0;
coord = new Coord();
}
public int CompareTo(State other)
{
return coord.CompareTo(other.coord);
}
public override string ToString()
{
return coord.ToString() + " / " + sum; // +(previous != null ? (" - { " + previous.ToString() + " }") : "");
}
public IEnumerable<Tuple<Coord, State>> Neighbours
{
get
{
List<int> srcList = coord.position == Coord.Position.LEFT ? coord.left : coord.right;
for(int i = 0; i < srcList.Count; i++) {
State newState = new State();
newState.previous = coord;
newState.coord.left = new List<int>(coord.left);
newState.coord.right = new List<int>(coord.right);
List<int> mutateList = coord.position == Coord.Position.LEFT ? newState.coord.left : newState.coord.right;
List<int> targetList = coord.position == Coord.Position.LEFT ? newState.coord.right : newState.coord.left;
int numb = mutateList[i];
mutateList.RemoveAt(i);
targetList.Add(numb);
targetList.Sort();
if(coord.position == Coord.Position.LEFT)
newState.coord.position = Coord.Position.RIGHT;
else
newState.coord.position = Coord.Position.LEFT;
newState.move = numb;
newState.sum = this.sum + numb;
yield return new Tuple<Coord, State>(newState.coord, newState);
}
for(int i = 0; i < srcList.Count - 1; i++)
for(int j = i + 1; j < srcList.Count; j++) {
State newState = new State();
newState.previous = coord;
newState.coord.left = new List<int>(coord.left);
newState.coord.right = new List<int>(coord.right);
List<int> mutateList = coord.position == Coord.Position.LEFT ? newState.coord.left : newState.coord.right;
List<int> targetList = coord.position == Coord.Position.LEFT ? newState.coord.right : newState.coord.left;
int numb1 = mutateList[i];
mutateList.RemoveAt(i);
targetList.Add(numb1);
targetList.Sort();
int numb2 = mutateList[j - 1];
mutateList.RemoveAt(j - 1);
targetList.Add(numb2);
targetList.Sort();
if(coord.position == Coord.Position.LEFT)
newState.coord.position = Coord.Position.RIGHT;
else
newState.coord.position = Coord.Position.LEFT;
newState.move = numb2;
newState.sum = this.sum + numb2;
yield return new Tuple<Coord, State>(newState.coord, newState);
}
}
}
}
static bool IsEndState(State s)
{
return s.coord.left.Count == 0;
}
static List<State> getStatePath(State s, SortedDictionary<Coord, State> map)
{
List<State> r = new List<State>();
State c = s;
while(c != null) {
r.Add(c);
if(c.previous == null)
c = null;
else
c = map[c.previous];
}
r.Reverse();
return r;
}
static List<State> SolveBridge(List<int> time)
{
List<State> result = null;
SortedDictionary<Coord, State> map = new SortedDictionary<Coord, State>();
SortedSet<Coord> open = new SortedSet<Coord>();
SortedSet<Coord> close = new SortedSet<Coord>();
State state = new State();
state.coord.left = (List<int>)time;
state.coord.left.Sort();
map.Add(state.coord, state);
open.Add(state.coord);
while(open.Count > 0) {
var nextopen = new SortedSet<Coord>();
foreach(var c in open) {
if(close.Contains(c)) continue;
if(result == null || result.Last().sum > map[c].sum) {
var neighbours = new List<Tuple<Coord, State>>(map[c].Neighbours);
foreach(var tuple in neighbours) {
if(close.Contains(tuple.Item1)) continue;
if(IsEndState(tuple.Item2) && (result == null || tuple.Item2.sum < result.Last().sum)) {
result = getStatePath(tuple.Item2, map);
}
if(!map.ContainsKey(tuple.Item1)) {
map[tuple.Item1] = tuple.Item2;
nextopen.Add(tuple.Item1);
}
else {
if(map[tuple.Item1].sum > tuple.Item2.sum) {
map[tuple.Item1] = tuple.Item2;
nextopen.Add(tuple.Item1);
}
}
}
}
close.Add(c);
}
open = nextopen;
}
return result;
}
static void Main(string[] args)
{
List<int> x = new List<int>();
x.Add(1);
x.Add(2);
x.Add(5);
x.Add(10);
x.Add(15);
List<State> sol = SolveBridge(x);
sol.ForEach(xx => Console.WriteLine(xx));
}
}
}
The output shows the state of the left brige in brackets, the state of the right bridge, and using L or R to designate which tower has the candle light.