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); }