Advertisement
Guest User

n-queens in C#

a guest
Jan 3rd, 2014
88
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  1. void Main()
  2. {
  3.     var n = 8;
  4.     var solution = Solve(n);
  5.     Print(solution);
  6. }
  7.  
  8. ///Solve N-Queens
  9. public IEnumerable<Tuple<int, int>> Solve(int n)
  10. {
  11.     return SolveForRemainder(Enumerable.Empty<Tuple<int, int>>(), n);
  12. }
  13.  
  14. ///Prints a chess board with marked queen positions
  15. public void Print(IEnumerable<Tuple<int, int>> queenLocations, char emptySpot = '.', char queenSpot = 'x')
  16. {
  17.     var size = queenLocations.Count();
  18.     if(size == 0) Console.WriteLine("no solution");
  19.     var emptyLine = Enumerable.Range(0, size).Select(_ => emptySpot).ToArray();
  20.     var lines = queenLocations.OrderBy(x => x.Item1).Select(x =>
  21.         new string(emptyLine, 0, x.Item2)
  22.         + queenSpot
  23.         + new string(emptyLine, 0, size - x.Item2 - 1));
  24.     Console.WriteLine(string.Join(Environment.NewLine, lines));
  25. }
  26.  
  27. ///Depth-first search of possible queen spaces.
  28. ///Recursively places queens in legal positions, backtracking when stuck and quitting when the answer is found.
  29. private IEnumerable<Tuple<int, int>> SolveForRemainder(IEnumerable<Tuple<int, int>> existingPositions, int range)
  30. {
  31.     if(existingPositions.Count() == range) return existingPositions;
  32.     var potentialNextPositions = NextQueenPossibilities(existingPositions, range);
  33.     var explorations = potentialNextPositions.Select(position =>
  34.         SolveForRemainder(existingPositions.Concat(new[] {position}).ToArray(), range));
  35.     return explorations.FirstOrDefault(x => x.Any()) ?? Enumerable.Empty<Tuple<int, int>>();
  36. }
  37.  
  38. ///Given two lists of numbers, this returns all pairs (the cartesian product).
  39. private IEnumerable<Tuple<int, int>> AllCombinations(IEnumerable<int> a, IEnumerable<int> b)
  40. {
  41.     return a.Join(b, _ => true, _ => true, (m, n) => Tuple.Create(m, n));
  42. }
  43.  
  44. ///Determines if two points are on a diagonal
  45. ///ie: returns true if the slope between two points is 1 or -1. false otherwise.
  46. private bool PositionsAreDiagonal(Tuple<int, int> a, Tuple<int, int> b)
  47. {
  48.     var xdif = a.Item1 - b.Item1;
  49.     var ydif = a.Item2 - b.Item2;
  50.     return (xdif == ydif || xdif + ydif == 0);
  51. }
  52.  
  53. ///This returns all legal positions for the next queen.
  54. ///In other words, given a set of existing queen positions,
  55. ///this returns all points on the board except any rows, columns or diagonals already occupied by queens.
  56. private IEnumerable<Tuple<int, int>> NextQueenPossibilities(IEnumerable<Tuple<int, int>> queens, int range)
  57. {
  58.     var validCols = Enumerable.Range(0, range).Except(queens.Select(x => x.Item1));
  59.     var validRows = Enumerable.Range(0, range).Except(queens.Select(x => x.Item2));
  60.     return AllCombinations(validCols, validRows).Where(x => !queens.Any(y => PositionsAreDiagonal(x, y)));
  61. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement