/jonathan/js/ConnectFour_434.js

https://github.com/ingrahaj/CTArcade
JavaScript | 348 lines | 298 code | 44 blank | 6 comment | 139 complexity | 145f67bbc5914db7f6e5984e4c7a7fd3 MD5 | raw file
  1. function ConnectFour() {
  2. var X_PLAYER = "X";
  3. var Y_PLAYER = "Y";
  4. var board = null;
  5. this.turn = false;
  6. this.reset = false;
  7. this.setup = function() {
  8. this.turn = "X";
  9. this.reset=false;
  10. board = new Array();
  11. for (var i = 0; i < 7; i++) {
  12. board.push(new Array(6));
  13. }
  14. }
  15. this.validMove = function(pt) {
  16. var x = pt[0];
  17. var y = pt[1];
  18. return (!board[x][y] && y == 5) || (!board[x][y] && (y+1 < 6) && board[x][y+1]);
  19. }
  20. this.fourInARow = function(i, j, count) {
  21. if (count == 4)
  22. return true;
  23. else if (i >= 7 || j >= 6 || j< 0 || i<0)
  24. return false;
  25. else if (board[i][j] == this.turn)
  26. return this.fourInARow(i + 1, j, count + 1);
  27. else
  28. return false;
  29. }
  30. this.fourInACol = function(i, j, count) {
  31. if (count == 4)
  32. return true;
  33. else if (i >= 7 || j >= 6 || j< 0 || i<0)
  34. return false;
  35. else if (board[i][j] == this.turn)
  36. return this.fourInACol(i, j + 1, count + 1);
  37. else
  38. return false;
  39. }
  40. this.fourInADiag1 = function(i, j, count) {
  41. if (count == 4)
  42. return true;
  43. else if (i >= 7 || j >= 6 || j< 0 || i<0)
  44. return false;
  45. else if (board[i][j] == this.turn)
  46. return this.fourInADiag1(i + 1, j + 1, count + 1);
  47. else
  48. return false;
  49. }
  50. this.fourInADiag2 = function(i, j, count) {
  51. if (count == 4)
  52. return true;
  53. else if (i >= 7 || j >= 6 || j< 0 || i<0)
  54. return false;
  55. else if (board[i][j] == this.turn)
  56. return this.fourInADiag2(i - 1, j + 1, count + 1);
  57. else
  58. return false;
  59. }
  60. this.toggleTurn = function() {
  61. this.turn = (this.turn == X_PLAYER) ? Y_PLAYER : X_PLAYER;
  62. }
  63. this.getBoard = function () { return board; }
  64. /* Public */
  65. this.move = function(x) {
  66. // find first open slot
  67. var answer = false;
  68. for (var z = 0; z < 6 ; z++) {
  69. if (this.validMove([x, z])) {
  70. board[x][z] = this.turn;
  71. if (this.detectWin()) {
  72. // $("#status").text(this.turn + " wins!");
  73. answer=true;
  74. this.reset = true;
  75. }
  76. this.toggleTurn();
  77. return [x, z, answer];
  78. }
  79. }
  80. return false;
  81. }
  82. this.getStatus = function() {
  83. if (this.turn == X_PLAYER)
  84. return "X to move";
  85. else
  86. return "Y to move";
  87. }
  88. this.detectWin = function() {
  89. this.reset = true;
  90. for (var i=0; i<7;i++) {
  91. for (var j=0; j<6; j++) {
  92. if (this.fourInARow(i, j, 0))
  93. return true;
  94. if (this.fourInACol(i, j, 0))
  95. return true;
  96. if (this.fourInADiag1(i, j, 0))
  97. return true;
  98. if (this.fourInADiag2(i, j, 0))
  99. return true;
  100. }
  101. }
  102. this.reset = false;
  103. return false;
  104. }
  105. this.getTurn = function() { return this.turn };
  106. this.restart = function() { this.setup(); }
  107. // **** Strategies ****
  108. this.tryToWin = function() {
  109. for (var i=0; i<7; i++) {
  110. for (var j =0; j<7; j++) {
  111. var move = [i,j];
  112. if (!board[i][j] && this.validMove(move)) {
  113. // play this move, check for win
  114. board[i][j] = this.turn;
  115. if (this.detectWin()) {
  116. board[i][j] = null; // clear
  117. return [i,j];
  118. }
  119. board[i][j] = null; // clear
  120. }
  121. }
  122. }
  123. return false;
  124. }
  125. this.tryToBlock = function() {
  126. this.toggleTurn()
  127. var move = this.tryToWin();
  128. this.toggleTurn();
  129. return move;
  130. }
  131. this.expandVerticalLine = function(getStreak) {
  132. getStreak = getStreak || false;
  133. var bestMove = false;
  134. var bestStreak = 0;
  135. for (var i = 0; i < 7; i++) {
  136. var streak = 0;
  137. for (var j = 5; j >= 0; j--) {
  138. if (board[i][j] == this.turn)
  139. streak++;
  140. else if (!board[i][j]) {
  141. if (streak > bestStreak) {
  142. bestMove = [i,j];
  143. bestStreak = streak;
  144. }
  145. streak = 0;
  146. } else
  147. streak = 0;
  148. }
  149. }
  150. if (getStreak)
  151. return [bestStreak, bestMove];
  152. return bestMove;
  153. }
  154. this.expandHorizLine = function(getStreak) {
  155. getStreak = getStreak || false;
  156. var bestMove = false;
  157. var bestStreak = 0;
  158. for (var j = 0; j < 6; j++) {
  159. var streak = 0;
  160. for (var i = 0; i < 7; i++) {
  161. if (board[i][j] == this.turn)
  162. streak++;
  163. else if (!board[i][j] && streak >= 1) {
  164. if (streak > bestStreak && this.validMove([i,j])) {
  165. bestStreak = streak;
  166. bestMove = [i,j];
  167. }
  168. streak =0 ;
  169. } else if (!board[i][j] && i < 6 && board[i+1][j] == this.turn && streak == 0) {
  170. if (bestStreak == 0)
  171. bestMove = [i,j];
  172. } else {
  173. if (streak > bestStreak && this.validMove([i,j])) {
  174. bestStreak = streak;
  175. bestMove = [i,j];
  176. }
  177. streak = 0;
  178. }
  179. }
  180. }
  181. var x = bestMove[0];
  182. if (x >= 5 && bestStreak < 2)
  183. return false;
  184. if (getStreak)
  185. return [bestStreak, bestMove];
  186. return bestMove;
  187. }
  188. this.expandDiagonalLine = function() { // TODO: expand diag lines of length 1 -> length 2
  189. for (var i = 0; i < 7; i++) {
  190. for (var j = 0; j < 6; j++) {
  191. var move = [i,j];
  192. var line = this.coreChecker(i, j, 0, [], 2, 'DIAG1', 1);
  193. if (line && this.validMove(move))
  194. return move;
  195. line = this.coreChecker(i, j, 0, [], 2, 'DIAG2', 1);
  196. if (line && this.validMove(move))
  197. return move;
  198. }
  199. }
  200. return false;
  201. }
  202. this.coreChecker = function(i, j, count, holes, countCheck, direction) {
  203. var oppTurn = (this.turn == X_PLAYER) ? Y_PLAYER : X_PLAYER;
  204. if (i >= 7 || j >= 6 || j < 0 || i < 0)
  205. return false;
  206. else if (holes.length > 1 || board[i][j] == oppTurn)
  207. return false;
  208. else if (count == countCheck) /* 3 to check for move, 4 to validate */
  209. return holes.length ? holes[0] : [i, j]; /* N.B. "0 ? 1 : 2" returns 2 */
  210. else {
  211. if (!board[i][j])
  212. holes.push([i,j]);
  213. if (direction == 'DIAG1') {
  214. i++;
  215. j++;
  216. } else if (direction == 'DIAG2') {
  217. i--;
  218. j++;
  219. }
  220. return this.coreChecker(i, j, count + 1, holes, countCheck, direction);
  221. }
  222. }
  223. this.takeCenter = function() {
  224. for (var j = 5; j >= 0; j--) {
  225. var move = [3, j];
  226. if (this.validMove(move))
  227. return move;
  228. }
  229. return false;
  230. }
  231. this.blockHorizLine = function() {
  232. this.toggleTurn();
  233. var result = this.expandHorizLine(true);
  234. this.toggleTurn();
  235. var streak = result[0];
  236. var move = result[1];
  237. if (streak > 1)
  238. return move;
  239. return false;
  240. }
  241. this.blockVerticalLine = function() {
  242. this.toggleTurn();
  243. var result = this.expandVerticalLine(true);
  244. this.toggleTurn();
  245. var streak = result[0];
  246. var move = result[1];
  247. if (streak > 1)
  248. return move;
  249. return false;
  250. }
  251. this.blockDiagLine = function() {
  252. this.toggleTurn();
  253. var result = this.expandDiagonalLine();
  254. this.toggleTurn();
  255. return result;
  256. }
  257. this.oppCanWinNext = function(move) {
  258. var oppTurn = (this.turn == X_PLAYER) ? Y_PLAYER : X_PLAYER;
  259. var x = move[0];
  260. var y = move[1];
  261. board[x][y] = this.turn;
  262. this.toggleTurn();
  263. var result = this.tryToWin();
  264. board[x][y] = null;
  265. this.toggleTurn();
  266. return result;
  267. }
  268. this.isFull = function() {
  269. for (var i =0 ; i <7; i++) {
  270. for (var j=0; j <6;j++) {
  271. if (!board[i][j])
  272. return false;
  273. }
  274. }
  275. return true;
  276. }
  277. this.randomMove = function() {
  278. var x,y;
  279. while (true) {
  280. x=Math.floor(Math.random()*7);
  281. y=Math.floor(Math.random()*6);
  282. if (this.validMove([x,y]))
  283. return [x,y];
  284. }
  285. return false;
  286. }
  287. this.firstLegalMove = function(move) {
  288. for (var i =0 ; i <7; i++) {
  289. for (var j=0; j <6;j++) {
  290. var move = [i,j];
  291. if (this.validMove(move) && !this.oppCanWinNext(move))
  292. return move;
  293. }
  294. }
  295. //try ANY legal move
  296. for (var i =0 ; i <7; i++) {
  297. for (var j=0; j <6;j++) {
  298. var move = [i,j];
  299. if (this.validMove(move))
  300. return move;
  301. }
  302. }
  303. }
  304. }