/solver/State.cs

https://github.com/bearw08/Sudoku_resolver · C# · 326 lines · 215 code · 53 blank · 58 comment · 47 complexity · 712048de95e543152323b69a6df539da MD5 · raw file

  1. using System;
  2. using System.IO;
  3. using System.Collections;
  4. using System.Collections.Generic;
  5. using System.Linq;
  6. using System.Diagnostics;
  7. using Logging;
  8. namespace solver
  9. {
  10. public class State
  11. {
  12. //
  13. public List<int> defaults = Enumerable.Range(1, 9).ToList<int>();
  14. public int[,] field = new int[9,9];
  15. public int[,] status = new int[9,9];
  16. public List<int>[,] candidates = new List<int>[9,9];
  17. public State ()
  18. {
  19. resetAllCandidates();
  20. resetAllValues();
  21. }
  22. /// <summary>
  23. /// Resets all candidates to default range(1-9)
  24. /// </summary>
  25. public void resetAllCandidates()
  26. {
  27. for(int i =0; i < 9; i++)
  28. for (int j = 0; j < 9; j++)
  29. {
  30. candidates[i, j] = new List<int>(defaults);
  31. }
  32. }
  33. /// <summary>
  34. /// Returns array with the current column values
  35. /// </summary>
  36. /// <param name="x">Receives column number</param>
  37. /// <returns></returns>
  38. private int[] getColumnValues(int x)
  39. {
  40. int[] colVals = new int[9];
  41. for (int i = 0; i < 9; i++)
  42. {
  43. colVals[i] = field[x, i];
  44. }
  45. return colVals;
  46. }
  47. /// <summary>
  48. /// Returns array with the current row values
  49. /// </summary>
  50. /// <param name="x">Receives row number</param>
  51. /// <returns></returns>
  52. private int[] getRowValues(int x)
  53. {
  54. int[] rowVals = new int[9];
  55. for (int i = 0; i < 9; i++)
  56. {
  57. rowVals[i] = field[i,x];
  58. }
  59. return rowVals;
  60. }
  61. /// <summary>
  62. /// Returns array with the current cell neighbours
  63. /// </summary>
  64. /// <param name="x">X position</param>
  65. /// <param name="y">Y position</param>
  66. /// <returns></returns>
  67. public int[] getSquareNeighbours(int x, int y)
  68. {
  69. int[] squareNeighs = new int[9];
  70. int minx = (x / 3) * 3;
  71. int miny = (y / 3) * 3;
  72. int maxy = miny + 3;
  73. int maxx = minx + 3;
  74. int counter = 0;
  75. for (int i = minx; i < maxx; i++)
  76. {
  77. for (int j = miny; j < maxy; j++)
  78. {
  79. squareNeighs[counter] = field[i, j];
  80. counter++;
  81. }
  82. }
  83. return squareNeighs;
  84. }
  85. /// <summary>
  86. /// Sets possible candidates for each square
  87. /// </summary>
  88. public void checkSquareCandidates()
  89. {
  90. int i = 0, j = 0;
  91. while (i<9)
  92. {
  93. bool isChanged = false;
  94. if (isCorrect() == false)
  95. {
  96. Log.Error(String.Format("isCorrect() returned false on {0},{1}",i,j), "State.cs,checkSquareCandidates()");
  97. return;
  98. }
  99. if (field[i, j] == 0 && candidates[i, j].Count == 1)
  100. {
  101. field[i, j] = candidates[i, j].First();
  102. candidates[i, j].Clear();
  103. isChanged = true;
  104. }
  105. else if (field[i, j] == 0)
  106. {
  107. int[] rowVals = getRowValues(j);
  108. int[] colVals = getColumnValues(i);
  109. int[] squareNeighbours = getSquareNeighbours(i, j);
  110. foreach (var k in rowVals)
  111. {
  112. if (candidates[i, j].Contains(k) ==true)
  113. {
  114. isChanged = true;
  115. candidates[i, j].Remove(k);
  116. }
  117. }
  118. foreach (var k in colVals)
  119. {
  120. if (candidates[i, j].Contains(k) ==true)
  121. {
  122. isChanged = true;
  123. candidates[i, j].Remove(k);
  124. }
  125. }
  126. foreach (var k in squareNeighbours)
  127. {
  128. if (candidates[i, j].Contains(k) == true)
  129. {
  130. isChanged = true;
  131. candidates[i, j].Remove(k);
  132. }
  133. }
  134. //for (int k = 0; k < rowVals.Length; k++)
  135. // candidates[i, j].Remove(rowVals[k]);
  136. //for(int k =0; k < colVals.Length;k++)
  137. // candidates[i, j].Remove(colVals[k]);
  138. //for(int k =0; k < squareNeighbours.Length;k++)
  139. // candidates[i, j].Remove(squareNeighbours[k]);
  140. }
  141. else if (field[i, j] != 0 && candidates[i,j].Count >0)
  142. {
  143. candidates[i, j].Clear();
  144. isChanged = true;
  145. }
  146. j++;
  147. if (isChanged == true)
  148. { i = 0; j = 0; }
  149. if (j > 8)
  150. { i++; j = 0; }
  151. }
  152. }
  153. /// <summary>
  154. /// Resets all values in field[,] to 0
  155. /// </summary>
  156. public void resetAllValues()
  157. {
  158. for (int i = 0; i < 9; i++)
  159. for (int j = 0; j < 9; j++)
  160. field[i, j] = 0;
  161. }
  162. /// <summary>
  163. /// Reads Puzzle from File
  164. /// </summary>
  165. /// <param name="filename">File name with Puzzle</param>
  166. public void readFromFile(string filename)
  167. {
  168. using (TextReader reader = File.OpenText("test.txt"))
  169. {
  170. int counter = 0;
  171. string text = reader.ReadToEnd();
  172. text = text.Replace(Environment.NewLine, "").TrimEnd(',', ' ', '\n', '\r', '.');
  173. //text = text.TrimEnd
  174. Log.Info(String.Format("Puzzle Loaded From {0} file", filename),"ReadFromFile()");
  175. Log.Info(String.Format("Contains {0} numbers",text.Length),"ReadfromFile");
  176. //int charNum = 0;
  177. //while (charNum < 81)
  178. //{
  179. // charNum++;
  180. // if (charNum % 9 == 0)
  181. // Log.Info("", "");
  182. //}
  183. Console.WriteLine(text);
  184. Console.WriteLine(text.Length);
  185. int i = 0, j =0;
  186. while(counter<81)
  187. {
  188. int num = 0;
  189. if (Char.IsDigit(text[counter]))
  190. {
  191. Int32.TryParse(text[counter].ToString(), out num);
  192. candidates[i, j] = new List<int>(defaults);
  193. status[i, j] = 1;
  194. }
  195. field[i, j] = num;
  196. j++;
  197. if (j > 8)
  198. { j = 0; i++; }
  199. counter++;
  200. }
  201. }
  202. }
  203. /// <summary>
  204. /// Prints current field arrays
  205. /// </summary>
  206. public void showField()
  207. {
  208. for (int i = 0; i < 9; i++)
  209. {
  210. for (int j = 0; j < 9; j++)
  211. {
  212. Console.Write("{0} ", field[i, j]);
  213. }
  214. Console.WriteLine();
  215. }
  216. Console.WriteLine("");
  217. }
  218. /// <summary>
  219. /// Check if puzzle is correct at current state
  220. /// </summary>
  221. /// <returns>False if is not correct, True if is correct</returns>
  222. public bool isCorrect()
  223. {
  224. for (int i = 0; i < 9; i++)
  225. {
  226. for (int j = 0; j < 9; j++)
  227. {
  228. if (field[i, j] == 0 && candidates[i, j].Count == 0)
  229. {
  230. Log.Error(String.Format("Cell {0}x{1} has no candidates and currently is not set", i, j), "State.cs,isCorrect()");
  231. return false;
  232. }
  233. }
  234. }
  235. return true;
  236. }
  237. /// <summary>
  238. /// Checks if puzzle is completed and correct
  239. /// </summary>
  240. /// <returns>False if is not completed, True if is completed</returns>
  241. public bool isCompleted()
  242. {
  243. if (isCorrect() != true)
  244. {
  245. return false;
  246. }
  247. else
  248. {
  249. for(int i =0; i< 9; i++)
  250. for (int j = 0; j < 9; j++)
  251. {
  252. if (field[i, j] == 0)
  253. return false;
  254. }
  255. }
  256. return true;
  257. }
  258. /// <summary>
  259. /// Shows each positon's candidates
  260. /// </summary>
  261. private void showCandidates()
  262. {
  263. for (int i = 0; i < 9; i++)
  264. for (int j = 0; j < 9; j++)
  265. {
  266. Console.Write(":{0}:", this.field[i, j]);
  267. foreach (var k in this.candidates[i, j])
  268. Console.Write("{0} ", k);
  269. Console.WriteLine();
  270. }
  271. }
  272. }
  273. }