Advertisement
Guest User

chess.js

a guest
Jul 12th, 2018
91
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  1.  
  2. var PAWN = {
  3.     move(src, dst, game, simulate) {
  4.         var board = game.board;
  5.         var black = board.getPiece(src).black;
  6.         var dir = black ? -1 : 1;
  7.         if ((dst.y == 0 || dst.y == 7) && game.promotePiece === null)
  8.             return false;
  9.         if (dst.y != src.y + dir) {
  10.             if (dst.x != src.x)
  11.                 return false;
  12.             if (dst.y != src.y + dir * 2)
  13.                 return false;
  14.             if (src.y != (black ? 6 : 1))
  15.                 return false;
  16.             if (board.getPiece(src.add(0, dir)) !== null || board.getPiece(dst) !== null)
  17.                 return false;
  18.             if (!simulate)
  19.                 game.enPassantSquare = dst;
  20.         } else if (dst.x == src.x) {
  21.             if (board.getPiece(src.add(0, dir)) !== null)
  22.                 return false;
  23.             if (!simulate)
  24.                 game.enPassantSquare = null;
  25.         } else {
  26.             if (Math.abs(dst.x - src.x) != 1)
  27.                 return false;
  28.             if (board.getPiece(dst) === null) {
  29.                 var eps = dst.add(0, -dir);
  30.                 if (game.enPassantSquare === null || game.enPassantSquare.x != eps.x || game.enPassantSquare.y != eps.y)
  31.                     return false;
  32.                 if (!simulate)
  33.                     board.setPiece(eps, null);
  34.             } else {
  35.                 if (board.getPiece(dst).black == black)
  36.                     return false;
  37.             }
  38.             if (!simulate)
  39.                 game.enPassantSquare = null;
  40.         }
  41.         if (!simulate) {
  42.             var piece = board.getPiece(src);
  43.             if (y == 0 || y == 7)
  44.                 piece.type = game.promotePiece;
  45.             board.setPiece(dst, piece);
  46.             board.setPiece(src, null);
  47.         }
  48.         return true;
  49.     }
  50. };
  51.  
  52. var ROOK = {
  53.     move(src, dst, game, simulate) {
  54.         var board = game.board;
  55.         if (src.x == dst.x) {
  56.             var minX = Math.min(src.x, dst.x);
  57.             var maxX = Math.max(src.x, dst.x);
  58.             for (var x = minX + 1; x < maxX; x++) {
  59.                 if (board.getPiece(new Coord(x, src.y)) !== null)
  60.                     return false;
  61.             }
  62.         } else if (src.y == dst.y) {
  63.             var minY = Math.min(src.y, dst.y);
  64.             var maxY = Math.max(src.y, dst.y);
  65.             for (var y = minY + 1; y < maxY; y++) {
  66.                 if (board.getPiece(new Coord(src.x, y)) !== null)
  67.                     return false;
  68.             }
  69.         } else {
  70.             return false;
  71.         }
  72.         if (board.getPiece(dst) !== null && board.getPiece(dst).black == board.getPiece(src).black)
  73.             return false;
  74.         if (!simulate) {
  75.             board.setPiece(dst, board.getPiece(src));
  76.             board.setPiece(src, null);
  77.             if (src.x == 0) {
  78.                 if (src.y == 0)
  79.                     game.castleState[0].queenside = false;
  80.                 else if (src.y == 7)
  81.                     game.castleState[1].queenside = false;
  82.             } else if (src.x == 7) {
  83.                 if (src.y == 0)
  84.                     game.castleState[0].kingside = false;
  85.                 else if (src.y == 7)
  86.                     game.castleState[1].kingside = false;
  87.             }
  88.             game.enPassantSquare = null;
  89.         }
  90.         return true;
  91.     }
  92. };
  93.  
  94. var KNIGHT = {
  95.     move(src, dst, game, simulate) {
  96.         var board = game.board;
  97.         if (src.x == dst.x || src.y == dst.y)
  98.             return false;
  99.         if (Math.abs(dst.x - src.x) + Math.abs(dst.y - src.y) != 3)
  100.             return false;
  101.         if (board.getPiece(dst) !== null && board.getPiece(dst).black == board.getPiece(src).black)
  102.             return false;
  103.         if (!simulate) {
  104.             board.setPiece(dst, board.getPiece(src));
  105.             board.setPiece(src, null);
  106.             game.enPassantSquare = null;
  107.         }
  108.         return true;
  109.     }
  110. };
  111.  
  112. var BISHOP = {
  113.     move(src, dst, game, simulate) {
  114.         var board = game.board;
  115.         var black = board.getPiece(src).black;
  116.         var dx = dst.x - src.x;
  117.         var dy = dst.y - src.y;
  118.         if (Math.abs(dx) != Math.abs(dy))
  119.             return false;
  120.         var dirX = Math.sign(dx);
  121.         var dirY = Math.sign(dy);
  122.         for (var x = src.x + dirX, y = src.y + dirY; x != dst.x; x += dirX, y += dirY) {
  123.             if (board.getPiece(new Coord(x, y)) !== null)
  124.                 return false;
  125.         }
  126.         if (board.getPiece(dst) !== null && board.getPiece(dst).black == black)
  127.             return false;
  128.         if (!simulate) {
  129.             board.getPiece(dst, board.getPiece(src));
  130.             board.setPiece(src, null);
  131.             game.enPassantSquare = null;
  132.         }
  133.         return true;
  134.     }
  135. };
  136.  
  137. var QUEEN = {
  138.     move(src, dst, game, simulate) {
  139.         var board = game.board;
  140.         var black = board.getPiece(src).black;
  141.         var dx = dst.x - src.x;
  142.         var dy = dst.y - src.y;
  143.         if (Math.abs(dx) != Math.abs(dy) && dx != 0 && dy != 0)
  144.             return false;
  145.         var dirX = Math.sign(dx);
  146.         var dirY = Math.sign(dy);
  147.         for (var x = src.x + dirX, y = src.y + dirY; x != dst.x || y != dst.y; x += dirX, y += dirY) {
  148.             if (board.getPiece(new Coord(x, y)) !== null)
  149.                 return false;
  150.         }
  151.         if (board.getPiece(dst) !== null && board.getPiece(dst).black == black)
  152.             return false;
  153.         if (!simulate) {
  154.             board.getPiece(dst, board.getPiece(src));
  155.             board.setPiece(src, null);
  156.             game.enPassantSquare = null;
  157.         }
  158.         return true;
  159.     }
  160. };
  161.  
  162. var KING = {
  163.     move(src, dst, game, simulate) {
  164.         var board = game.board;
  165.         var black = board.getPiece(src).black;
  166.         var dx = dst.x - src.x;
  167.         var dy = dst.y - src.y;
  168.         if (Math.abs(dy) > 1)
  169.             return false;
  170.         if (Math.abs(dx) > 2)
  171.             return false;
  172.         if (board.getPiece(dst) !== null && board.getPiece(dst).black == black)
  173.             return false;
  174.         if (Math.abs(dx) == 2) {
  175.             if (dy != 0)
  176.                 return false;
  177.             if (dx < 0) {
  178.                 if (!game.castleState[black ? 1 : 0].queenside)
  179.                     return false;
  180.                 if (board.getPiece(new Coord(1, src.y)) !== null)
  181.                     return false;
  182.             } else {
  183.                 if (!game.castleState[black ? 1 : 0].kingside)
  184.                     return false;
  185.             }
  186.             if (board.getPiece(dst) !== null)
  187.                 return false;
  188.             if (board.getPiece(src.add(dx / 2, 0)) !== null)
  189.                 return false;
  190.             if (game.isPieceAttacked(src))
  191.                 return false;
  192.             var piece = board.getPiece(src);
  193.             board.setPiece(src.add(dx / 2, 0), piece);
  194.             board.setPiece(src, null);
  195.             if (game.isPieceAttacked(src.add(dx / 2, 0))) {
  196.                 board.setPiece(src.add(dx / 2, 0), null);
  197.                 board.setPiece(src, piece);
  198.                 return false;
  199.             }
  200.             if (!simulate) {
  201.                 board.setPiece(new Coord(dx < 0 ? 0 : 7, src.y), null);
  202.                 board.setPiece(src.add(dx / 2, 0), new PieceInstance("r", black));
  203.             }
  204.         }
  205.         if (!simulate) {
  206.             board.setPiece(dst, board.getPiece(src));
  207.             board.setPiece(src, null);
  208.             game.castleState[black ? 1 : 0].queenside = false;
  209.             game.castleState[black ? 1 : 0].kingside = false;
  210.             game.enPassantSquare = null;
  211.         }
  212.         return true;
  213.     }
  214. };
  215.  
  216. var pieceClasses = {
  217.     "p": PAWN,
  218.     "r": ROOK,
  219.     "n": KNIGHT,
  220.     "b": BISHOP,
  221.     "q": QUEEN,
  222.     "k": KING
  223. };
  224.  
  225. class PieceInstance {
  226.     constructor(type, black) {
  227.         this.type = type;
  228.         this.black = black;
  229.     }
  230. }
  231.  
  232. class Coord {
  233.     constructor(x, y) {
  234.         this.x = x;
  235.         this.y = y;
  236.     }
  237.    
  238.     add(x, y) {
  239.         return new Coord(this.x + x, this.y + y);
  240.     }
  241. }
  242.  
  243. class Board {
  244.     constructor() {
  245.         this.tiles = [];
  246.         for (int x = 0; x < 8; x++) {
  247.             this.tiles[x] = [];
  248.             for (int y = 0; y < 8; y++)
  249.                 this.tiles[x][y] = null;
  250.         }
  251.     }
  252.    
  253.     checkBounds(pos) {
  254.         if (pos.x < 0 || pos.y < 0 || pos.x >= 8 || pos.y >= 8)
  255.             throw (pos.x + ", " + pos.y + " out of bounds");
  256.     }
  257.    
  258.     getPiece(pos) {
  259.         checkBounds(pos);
  260.         return this.tiles[pos.x][pos.y];
  261.     }
  262.    
  263.     setPiece(pos, piece) {
  264.         checkBounds(pos.x, pos.y);
  265.         this.tiles[pos.x][pos.y] = piece;
  266.     }
  267. }
  268.  
  269. class Game {
  270.     constructor(userWhite, userBlack) {
  271.         this.userWhite = userWhite;
  272.         this.userBlack = userBlack;
  273.         this.blackToMove = false;
  274.         this.castleState = [{queenside: true, kingside: true}, {queenside: true, kingside: true}]
  275.         this.enPassantSquare = null;
  276.         this.board = new Board();
  277.         var majors = ["r", "n", "b", "q", "k", "b", "n", "r"];
  278.         for (int x = 0; x < 8; x++) {
  279.             this.board.setPiece(new Coord(x, 0), new PieceInstance(majors[x], false));
  280.             this.board.setPiece(new Coord(x, 1), new PieceInstance("p", false));
  281.             this.board.setPiece(new Coord(x, 6), new PieceInstance("p", true));
  282.             this.board.setPiece(new Coord(x, 7), new PieceInstance(majors[x], true));
  283.         }
  284.         this.promotePiece = null;
  285.     }
  286.    
  287.     isPieceAttacked(pos) {
  288.         if (this.board.getPiece(pos) === null)
  289.             return false;
  290.         var black = this.board.getPiece(pos).black;
  291.         for (x = 0; x < 8; x++) {
  292.             for (y = 0; y < 8; y++) {
  293.                 var piece = this.board.getPiece(pos);
  294.                 if (piece !== null && piece.black != black) {
  295.                     if (pieceClasses[piece.type].move(new Coord(x, y), pos, this, true))
  296.                         return true;
  297.                 }
  298.             }
  299.         }
  300.         return false;
  301.     }
  302. }
  303.  
  304. var games = storage.get("chessGames");
  305. if (games === null)
  306.     games = [];
  307. else
  308.     games = JSON.parse(games);
  309.  
  310. function saveGames() {
  311.     storage.set("chessGames", JSON.stringify(games));
  312. }
  313.  
  314. function userName(user) {
  315.     var userObj = guild.getUser(user);
  316.     if (userObj.getNickname() === null)
  317.         return userObj.getName();
  318.     else
  319.         return userObj.getNickname();
  320. }
  321.  
  322. function parseMove(moveStr, game) {
  323.     var regex = /^((((?<pieceType>[prnqkPRNBQK]|(b(?![xX])))?((?<fromX>[a-hA-H])|(?<fromY>(?<![bB])[1-8]))?((?<!^)[xX])?(?<toX>[a-hA-H])(?<toY>[1-8])))|(((?<simpleFromX>[a-hA-H])(?<simpleFromY>[1-8])[-xX]?(?<simpleToX>[a-hA-H])(?<simpleToY>[1-8])))|(?<kingsideCastle>0-0)|(?<queensideCastle>0-0-0))[\+#]*(=(?<promotePiece>[rnbqRNBQ]))?[\+#]*$/;
  324.     var match = regex.exec(moveStr);
  325.     if (match === null)
  326.         return {error: "Invalid syntax"};
  327.    
  328.     var ret = {};
  329.     if ("promotePiece" in match) {
  330.         ret.promotePiece = match.promotePiece.toLowerCase();
  331.     }
  332.     if ("queensideCastle" in match) {
  333.         if (!game.castleState[game.blackToMove ? 1 : 0].queenside) {
  334.             return {error: "Illegal move"};
  335.         }
  336.         ret.fromX = 4;
  337.         ret.fromY = game.blackToMove ? 7 : 0;
  338.         ret.toX = 6;
  339.         ret.toY = ret.fromY;
  340.     } else if ("kingsideCastle" in match) {
  341.         if (!game.castleState[game.blackToMove ? 1 : 0].kingside) {
  342.             return {error: "Illegal move"};
  343.         }
  344.         ret.fromX = 4;
  345.         ret.fromY = game.blackToMove ? 7 : 0;
  346.         ret.toX = 2;
  347.         ret.toY = ret.fromY;
  348.     } else if ("simpleFromX" in match) {
  349.         ret.fromX = match.simpleFromX.toLowerCase().charCodeAt(0) - 97;
  350.         ret.fromY = parseInt(match.simpleFromY) - 1;
  351.         ret.toX = match.simpleToX.toLowerCase().charCodeAt(0) - 97;
  352.         ret.toY = parseInt(match.simpleToY) - 1;
  353.     } else {
  354.         var pieceType = ("pieceType" in match) ? match.pieceType.toLowerCase() : "p";
  355.         ret.toX = match.toX.toLowerCase().charCodeAt(0) - 97;
  356.         ret.toY = parseInt(match.toY) - 1;
  357.         var dst = new Coord(ret.toX, ret.toY);
  358.         var fromX = ("fromX" in match) ? match.fromX.toLowerCase().charCodeAt(0) - 97 : -1;
  359.         var fromY = ("fromY" in match) ? parseInt(match.fromY) - 1 : -1;
  360.        
  361.         var foundPiece = false;
  362.         for (int x = 0; x < 8; x++) {
  363.             if (fromX == -1 || x == fromX) {
  364.                 for (int y = 0; y < 8; y++) {
  365.                     if (fromY == -1 || y == fromY) {
  366.                         var pos = new Coord(x, y);
  367.                         var piece = game.board.getPiece(pos);
  368.                         if (piece !== null && piece.black == game.blackToMove && piece.type == pieceType) {
  369.                             if (pieceClasses[pieceType].move(pos, dst, game, true)) {
  370.                                 if (foundPiece) {
  371.                                     return {error: "Ambiguous move"};
  372.                                 }
  373.                                 foundPiece = true;
  374.                                 ret.fromX = fromX;
  375.                                 ret.fromY = fromY;
  376.                             }
  377.                         }
  378.                     }
  379.                 }
  380.             }
  381.         }
  382.         if (!foundPiece)
  383.             return {error: "Invalid move"};
  384.        
  385.         return ret;
  386.     }
  387. }
  388.  
  389. function getGame(user) {
  390.     for (int i = 0; i < games.length; i++) {
  391.         var game = games[i];
  392.         if (game.userWhite == user || game.userBlack == user)
  393.             return game;
  394.     }
  395.     return null;
  396. }
  397.  
  398. function startGame(userA, userB) {
  399.     if (userA == userB) {
  400.         channel.message("You cannot play yourself!");
  401.         return;
  402.     }
  403.     if (getGame(userA) !== null) {
  404.         channel.message(userName(userA) + " is already in a game");
  405.         return;
  406.     }
  407.     if (getGame(userB) !== null) {
  408.         channel.message(userName(userB) + " is already in a game");
  409.         return;
  410.     }
  411.    
  412.     var game;
  413.     if (Math.random() < 0.5)
  414.         game = new Game(userA, userB);
  415.     else
  416.         game = new Game(userB, userA);
  417.     games.push(game);
  418.     saveGames();
  419.     printBoard(game);
  420. }
  421.  
  422. function resignGame(resigner) {
  423.     var game = getGame(resigner);
  424.     if (game === null) {
  425.         channel.message("You aren't in a game");
  426.         return;
  427.     }
  428.    
  429.     var opponent;
  430.     if (resigner == game.userWhite)
  431.         opponent = game.userBlack;
  432.     else
  433.         opponent = game.userWhite;
  434.     games.splice(games.indexOf(game), 1);
  435.     saveGames();
  436.     channel.message("<@" + resigner + "> resigned, <@" + opponent + "> wins!");
  437. }
  438.  
  439. function doMove(user, arg) {
  440.     var game = getGame(user);
  441.     if (game === null) {
  442.         channel.message("You aren't in a game");
  443.         return;
  444.     }
  445.    
  446.     var black;
  447.     if (user == game.userWhite)
  448.         black = false;
  449.     else
  450.         black = true;
  451.     if (black != game.blackToMove) {
  452.         channel.message("It's not your turn");
  453.         return;
  454.     }
  455.    
  456.     var move = parseMove(arg, game);
  457.     if ("error" in move) {
  458.         channel.message(move.error);
  459.         return;
  460.     }
  461.    
  462.     if ("promotePiece" in move) {
  463.         game.promotePiece = move.promotePiece;
  464.     } else {
  465.         game.promotePiece = null;
  466.     }
  467.    
  468.     var src = new Coord(move.fromX, move.fromY);
  469.     var dst = new Coord(move.toX, move.toZ);
  470.     var piece = game.board.getPiece(src);
  471.     if (piece === null || piece.black != black) {
  472.         channel.message("Invalid piece");
  473.         return;
  474.     }
  475.     if (!pieceClasses[piece.type].move(src, dst, game, false)) {
  476.         channel.message("Invalid move");
  477.         return;
  478.     }
  479.    
  480.     var kingPos;
  481.     for (var x = 0; x < 8; x++) {
  482.         for (var y = 0; y < 8; y++) {
  483.             kingPos = new Coord(x, y);
  484.             var piece = game.board.getPiece(kingPos);
  485.             if (piece !== null && piece.black == black && piece.type == "k") {
  486.                 break;
  487.             }
  488.         }
  489.     }
  490.     if (game.isPieceAttacked(kingPos)) {
  491.         channel.message("Illegal move");
  492.         return;
  493.     }
  494.    
  495.     game.blackToMove = !game.blackToMove;
  496.    
  497.     printBoard(game);
  498.     saveGames();
  499.    
  500. }
  501.  
  502. function printBoard(game) {
  503.     var msg = "```";
  504.     for (int y = 7; y >= 0; y--) {
  505.         msg += "\n+-+-+-+-+-+-+-+-+";
  506.         for (int x = 0; x < 8; x++) {
  507.             msg += "|";
  508.             var piece = game.board.getPiece(new Coord(x, y));
  509.             if (piece === null)
  510.                 msg += " ";
  511.             else if (piece.black)
  512.                 msg += piece.type;
  513.             else
  514.                 msg += piece.type.toUpperCase();
  515.         }
  516.         msg += "|";
  517.     }
  518.     msg += "\n+-+-+-+-+-+-+-+-+"
  519.     msg += "\n```"
  520.     channel.message(msg);
  521.    
  522.     if (game.blackToMove)
  523.         channel.message("Black to move <@" + game.userBlack + ">");
  524.     else
  525.         channel.message("White to move <@" + game.userWhite + ">");
  526. }
  527.  
  528. function printUsage() {
  529.     var usage = "```\n"
  530.     + "//chess start <@opponent>\n"
  531.     + "//chess <move>\n"
  532.     + "//chess resign\n"
  533.     + "//chess board\n"
  534.     + "//chess help\n"
  535.     + "```";
  536. }
  537.  
  538. var arg = message.getContent();
  539. arg = arg.replace(/^\s*\S+\s*/, "");
  540. var args = arg.split(/s+/);
  541. if (args.length == 0) {
  542.     printUsage();
  543. } else {
  544.     arg = args[0];
  545.     if (arg == "start") {
  546.         if (args.length != 2) {
  547.             printUsage();
  548.         } else {
  549.             var regex = /^<@(\d+)>$/
  550.             var match = regex.match(args[1]);
  551.             if (match === null) {
  552.                 printUsage();
  553.             } else {
  554.                 startGame(message.getUser().getID(), parseInt(match[1]));
  555.             }
  556.         }
  557.     } else if (arg == "resign") {
  558.         resignGame(message.getUser().getID());
  559.     } else if (arg == "help" || arg == "?") {
  560.         printUsage();
  561.     } else if (arg == "board") {
  562.         var game = getGame(message.getUser().getID());
  563.         if (game === null) {
  564.             channel.message("You aren't in a game");
  565.         } else {
  566.             printBoard(game);
  567.         }
  568.     } else {
  569.         if (args.length != 2)
  570.             printUsage();
  571.         else
  572.             doMove(message.getUser().getID(), args[1]);
  573.     }
  574. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement