tictactoe.js 2.2 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495
  1. class TicTacToe {
  2. constructor(playerX = 'x', playerO = 'o') {
  3. this.playerX = playerX;
  4. this.playerO = playerO;
  5. this._currentTurn = false;
  6. this._x = 0;
  7. this._o = 0;
  8. this.turns = 0;
  9. }
  10. get board() {
  11. return this._x | this._o;
  12. }
  13. get currentTurn() {
  14. return this._currentTurn ? this.playerO : this.playerX;
  15. }
  16. get enemyTurn() {
  17. return this._currentTurn ? this.playerX : this.playerO;
  18. }
  19. static check(state) {
  20. for (const combo of [7, 56, 73, 84, 146, 273, 292, 448]) {
  21. if ((state & combo) === combo) {
  22. return !0;
  23. }
  24. }
  25. return !1;
  26. }
  27. /**
  28. * ```js
  29. * TicTacToe.toBinary(1, 2) // 0b010000000
  30. * ```
  31. */
  32. static toBinary(x = 0, y = 0) {
  33. if (x < 0 || x > 2 || y < 0 || y > 2) throw new Error('invalid position');
  34. return 1 << x + (3 * y);
  35. }
  36. /**
  37. * @param player `0` is `X`, `1` is `O`
  38. *
  39. * - `-3` `Game Ended`
  40. * - `-2` `Invalid`
  41. * - `-1` `Invalid Position`
  42. * - ` 0` `Position Occupied`
  43. * - ` 1` `Sucess`
  44. * @return {-3|-2|-1|0|1}
  45. */
  46. turn(player = 0, x = 0, y) {
  47. if (this.board === 511) return -3;
  48. let pos = 0;
  49. if (y == null) {
  50. if (x < 0 || x > 8) return -1;
  51. pos = 1 << x;
  52. } else {
  53. if (x < 0 || x > 2 || y < 0 || y > 2) return -1;
  54. pos = TicTacToe.toBinary(x, y);
  55. }
  56. if (this._currentTurn ^ player) return -2;
  57. if (this.board & pos) return 0;
  58. this[this._currentTurn ? '_o' : '_x'] |= pos;
  59. this._currentTurn = !this._currentTurn;
  60. this.turns++;
  61. return 1;
  62. }
  63. /**
  64. * @return {('X'|'O'|1|2|3|4|5|6|7|8|9)[]}
  65. */
  66. static render(boardX = 0, boardO = 0) {
  67. const x = parseInt(boardX.toString(2), 4);
  68. const y = parseInt(boardO.toString(2), 4) * 2;
  69. return [...(x + y).toString(4).padStart(9, '0')].reverse().map((value, index) => value == 1 ? 'X' : value == 2 ? 'O' : ++index);
  70. }
  71. /**
  72. * @return {('X'|'O'|1|2|3|4|5|6|7|8|9)[]}
  73. */
  74. render() {
  75. return TicTacToe.render(this._x, this._o);
  76. }
  77. get winner() {
  78. const x = TicTacToe.check(this._x);
  79. const o = TicTacToe.check(this._o);
  80. return x ? this.playerX : o ? this.playerO : false;
  81. }
  82. }
  83. new TicTacToe().turn;
  84. export default TicTacToe;