static bool solve(PuzzleState puzzleState) { //Make links with logic solveLogic(puzzleState); //Make links with guess HashSet <Tuple <Point, Point> > links = new HashSet <Tuple <Point, Point> >(); List <Point> nodes = puzzleState.Nodes.Keys.ToList(); foreach (Point n in nodes) { foreach (Point neighbour in Neighbours[n]) { if (puzzleState.CanLink(n, neighbour) > 0) { Tuple <Point, Point> canonical = PuzzleState.Canonical(n, neighbour); if (!links.Contains(canonical)) { links.Add(canonical); } } } } //Hack - try the shortest links first List <Tuple <Point, Point> > sortedLinks = links.ToList().OrderBy(l => Math.Abs(l.Item1.X - l.Item2.X) + Math.Abs(l.Item1.Y - l.Item2.Y)).ToList(); //Choose a random link foreach (Tuple <Point, Point> link in sortedLinks) { //Duplicate the state PuzzleState duplicate = new PuzzleState(puzzleState); //Make the link level++; Console.Error.WriteLine(new string(' ', level * 2) + "test linking (" + link.Item1.X + "," + link.Item1.Y + ")->(" + link.Item2.X + "," + link.Item2.Y + ")"); duplicate.AddLink(link.Item1, link.Item2); //If exhausted, check for connectedness if (duplicate.Nodes[link.Item1] == 0 && duplicate.Nodes[link.Item2] == 0) { int degree1 = 0; foreach (Point neighbour in Neighbours[link.Item1]) { if (duplicate.LinkValue(link.Item1, neighbour) > 0) { degree1++; } } int degree2 = 0; foreach (Point neighbour in Neighbours[link.Item2]) { if (duplicate.LinkValue(link.Item2, neighbour) > 0) { degree2++; } } // if (degree1 == 1 && degree2 == 1) { level--; continue; } } //Solve it bool result = solve(duplicate); level--; if (result) { puzzleState.Nodes = new Dictionary <Point, int>(duplicate.Nodes); puzzleState.Links = new Dictionary <Tuple <Point, Point>, int>(duplicate.Links); puzzleState.Intersections = new HashSet <Point>(duplicate.Intersections); break; } } //Solved, check for completness if (puzzleState.Nodes.Count(d => d.Value > 0) > 0) { return(false); } if (!puzzleState.IsConnected()) { return(false); } // return(true); }
static void solveLogic(PuzzleState puzzleState) { bool makeLinks = true; int iterations = 0; while (makeLinks) { makeLinks = false; List <Point> nodes = puzzleState.Nodes.Keys.ToList(); foreach (Point n in nodes) { //Skip a saturated node int remaining = puzzleState.Nodes[n]; if (remaining == 0) { continue; } //Calculate links int requiredLinks = remaining; int availableLinks = puzzleState.GetNodeLinksAvailable(n); if (requiredLinks == availableLinks) { //Populate links if required links equals available links //Console.Error.WriteLine("LinkAll n=(" + n.X + "," + n.Y + ") links=" + requiredLinks); makeLinks = true; puzzleState.LinkNeighbours(n); puzzleState.LinkNeighbours(n); continue; } //Calculate requirements int requiredDegrees = PuzzleState.GetNodeDegreesRequired(remaining); int availableDegrees = puzzleState.GetNodeDegreesAvailable(n); if (requiredDegrees == availableDegrees) { //Populate links if the available degrees of freedom equals required //Console.Error.WriteLine("LinkNeighbours n=(" + n.X + "," + n.Y + ") links=" + requiredLinks + "," + availableLinks + " degrees=" + requiredDegrees); makeLinks = true; puzzleState.LinkNeighbours(n); } else if (availableDegrees - requiredDegrees == 1) { //Special case for 2->1, 4->1, 6->1 if (puzzleState.Nodes[n] % 2 == 0) { foreach (Point neighbour in Neighbours[n]) { if (puzzleState.CanLink(n, neighbour) == 1) { //Console.Error.WriteLine("LinkNeighbours -1 n=(" + n.X + "," + n.Y + ") links=" + requiredLinks + "," + availableLinks + " degrees=" + requiredDegrees); //Link others except neighbour foreach (Point candidate in Neighbours[n]) { if (!candidate.Equals(neighbour) && (puzzleState.CanLink(n, candidate) > 0)) { makeLinks = true; puzzleState.AddLink(n, candidate); } } //One iteration break; } } } } } iterations++; //Console.Error.WriteLine(new string(' ', level) + " Finished " + iterations + " iterations"); } }