JustDoesGames

chess by NF

Aug 8th, 2019
193
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Lua 46.06 KB | None | 0 0
  1.  
  2. --[[                MINECRAFT CHESS        
  3.  
  4. Written by Nitrogen Fingers
  5. Version: 0.85
  6.  
  7. Acknowledgements:
  8.     ASCII art by David Moeser (1995), Alefith (1995) and Anonyoums (1998)
  9. ]]--
  10.  
  11. version = 0.85
  12.  
  13. --[[            CHESS ENGINE REGION
  14.     The code within this region handles the logic of playing
  15.     the chess game, including the main engine itself.       ]]--
  16.  
  17. local var w,h = term.getSize()
  18. --Whether or not the player is white
  19. local var youAreWhite = true
  20. --If it's white's turn (default is yes)
  21. local var whiteTurn = true
  22. --Whether or not the player is still in the game interface
  23. local playing = true
  24. --Whether or not the player is still able to make moves (not checkmate etc.)
  25. local gameOver = true
  26. --Whether or not the black pieces are visible (flashes on and off)
  27. local blackVisible = false
  28.  
  29. --The position of the white king
  30. local whiteKing = { x = 5, y = 1 }
  31. --The position of the black king
  32. local blackKing = { x = 5, y = 8 }
  33.  
  34. --A concatenation of the letters typed during the parsing phase
  35. local lastQuery = ""
  36.  
  37. --Whether the game is playing locally or network
  38. local isLocal = true
  39. --The address of the other player (if there is one)
  40. local opponentID = 1
  41. --The list of all monitors
  42. local monitorList = {}
  43. --The side the monitor is on
  44. local side = nil
  45.  
  46. -- Board consists of 2D array of strings
  47. -- String format = <sign><piece> where sign is + for white, - for black
  48. --[[
  49. Pieces: K = KING
  50.         Q = QUEEN
  51.         B = BISHOP
  52.         N = KNIGHT
  53.         C = CASTLE
  54.         p = PAWN
  55. --]]
  56.    
  57. board = {
  58.   --        a     b     c     d     e     f     g     h
  59.   [8] = { " ",  " ",  " ",  " ",  " ",  " ",  " ",  " " },
  60.   [7] = { " ",  " ",  " ",  " ",  " ",  " ",  " ",  " " },
  61.   [6] = { " ",  " ",  " ",  " ",  " ",  " ",  " ",  " " },
  62.   [5] = { " ",  " ",  " ",  " ",  " ",  " ",  " ",  " " },
  63.   [4] = { " ",  " ",  " ",  " ",  " ",  " ",  " ",  " " },
  64.   [3] = { " ",  " ",  " ",  " ",  " ",  " ",  " ",  " " },
  65.   [2] = { " ",  " ",  " ",  " ",  " ",  " ",  " ",  " " },
  66.   [1] = { " ",  " ",  " ",  " ",  " ",  " ",  " ",  " " }
  67.   --        a     b     c     d     e     f     g     h
  68. }
  69.  
  70. --[[
  71. The following is tracked under movesMade:
  72. - player: Which player moved (+ for white, - for black)
  73. - piece: What kind of piece moved (p, Q, N, C etc)
  74. - oldx, oldy, newx, newy: Coordinates (numbers please)
  75. - capture: Whether or not the move resulted in a capture (Bf4xe5 for example)
  76. - castle: If the move was a castle - 0 for none, -1 for QS and 1 for KS
  77. - promotion: A string. Empty if no promotion, or the piece promoted to
  78. - ep: Whether or not the capture was an en passant
  79. - check: Whether or not the move resulted in a check (Bf3-g2+ for example)
  80. - mate: Whether or not the move resulted in a mate (Bf3-g2# for example)
  81. - stale: Whether or not the move resulted in a stalemate (Bf3-g2$ for example)
  82. ]]--
  83. movesMade = { }
  84.  
  85. --Prints the player's color and the current turn
  86. function printHeader()
  87.   term.setCursorPos(2, 1)
  88.   if youAreWhite then term.write("You are WHITE")
  89.   else term.write("You are BLACK") end
  90.  
  91.   term.setCursorPos(28, 1)
  92.   if whiteTurn then term.write("White to play")
  93.   else term.write("Black to play") end
  94.  
  95.   term.setCursorPos(1, 2)
  96.   term.write(string.rep("-", w))
  97. end
  98.  
  99. --Prints a list of the last 10 moves made
  100. function printMovesMade()
  101.   local var min = 1
  102.   local var max = #movesMade
  103.   if #movesMade > 9 then min = #movesMade - 9 end
  104.   for i = min,max do
  105.     term.setCursorPos(2, 3 + (i - min + 1))
  106.     term.clearLine()
  107.     --We convert the movesMade entry to a string here using long notation- B3exf2+ ect.
  108.     local entry = convertCoordinateToLetter(movesMade[i].oldx)..movesMade[i].oldy
  109.    
  110.    
  111.     if movesMade[i].castle == 0 then
  112.         --This is the standard, non-castling notation used
  113.         if movesMade[i].piece ~= "p" then entry = movesMade[i].piece..entry end
  114.         if movesMade[i].capture then entry = entry.." x "
  115.         else entry = entry.." - " end
  116.    
  117.         entry = entry..convertCoordinateToLetter(movesMade[i].newx)..movesMade[i].newy
  118.    
  119.         if movesMade[i].promotion ~= "" then entry = entry.."="..movesMade[i].promotion end
  120.         if movesMade[i].ep then entry  = entry.."e.p." end
  121.         if movesMade[i].check then entry = entry.."+"
  122.         elseif movesMade[i].mate then entry = entry.."#"
  123.         elseif movesMade[i].stale then entry = entry.."$" end
  124.        
  125.     elseif movesMade[i].castle == 1 then entry = "O-O"
  126.     elseif movesMade[i].castle == -1 then entry = "O-O-O" end
  127.    
  128.     term.write(i..": "..string.rep(" ", 3 - #tostring(i))..entry)
  129.   end
  130. end
  131.  
  132. --Prints the board.
  133. function printBoard()
  134.     for i = 1,8 do
  135.         local idx = i
  136.         if youAreWhite then idx = 9 - i end
  137.         term.setCursorPos(25, 3 + i)
  138.         term.write(idx.." |")
  139.         for j=1,8 do
  140.             local jdx = j
  141.             if not youAreWhite then jdx = 9 - j end
  142.             local str = board[idx][jdx]
  143.             if term.isColour() then
  144.                 if string.sub(str, 1, 1)== "-" then
  145.                     term.setTextColour(colours.black)
  146.                     str = string.sub(str, 2)
  147.                 elseif string.sub(str, 1, 1) == "+" then
  148.                     term.setTextColour(colours.white)
  149.                     str = string.sub(str, 2)
  150.                 end
  151.                 if idx%2 == jdx%2 then
  152.                     term.setBackgroundColour(colours.brown)
  153.                 else
  154.                     term.setBackgroundColour(colours.yellow)
  155.                 end
  156.                 term.write(" "..str)
  157.                 term.setTextColour(colours.white)
  158.                 term.setBackgroundColour(colours.black)
  159.             else
  160.                 if string.sub(str, 1, 1)== "-" and not blackVisible then str = " " end
  161.                 if str ~= " " then str = string.sub(str, 2) end
  162.                 if str == " " and idx%2 == jdx%2 then str = "*" end
  163.                 term.write(" "..str)
  164.             end
  165.         end
  166.     end
  167.     term.setCursorPos(25, 12)
  168.     term.write("   "..string.rep("-", 16))
  169.     term.setCursorPos(25, 13)
  170.     if youAreWhite then term.write("    a b c d e f g h")
  171.     else term.write("    h g f e d c b a") end
  172. end
  173.  
  174. --This method determines whether a specific move made by a player is legal
  175. --If not an error will have details (so these methods are long)
  176. --Note we use AmWhite here to test for checking
  177. function isLegal(oldx,oldy,newx,newy,amWhite)
  178.   if not coordinatesSensible(oldx, oldy, newx, newy) then return false end
  179.   local piece = string.sub(board[oldy][oldx], 2)
  180.  
  181.   local isLegal = false
  182.   if piece=="p" then isLegal = isLegalPawn(oldx,oldy,newx,newy,amWhite,false,false)
  183.   elseif piece=="C" then isLegal = isLegalCastle(oldx,oldy,newx,newy,amWhite,false)
  184.   elseif piece=="N" then isLegal = isLegalKnight(oldx,oldy,newx,newy,amWhite,false)
  185.   elseif piece=="B" then isLegal = isLegalBishop(oldx,oldy,newx,newy,amWhite,false)
  186.   elseif piece=="Q" then isLegal = isLegalQueen(oldx,oldy,newx,newy,amWhite,false)
  187.   elseif piece=="K" then isLegal = isLegalKing(oldx,oldy,newx,newy,amWhite,false,false) end
  188.  
  189.   if isLegal then
  190.     if amWhite then
  191.         if piece=="K" then isLegal = not isInCheck(newx,newy,amWhite)
  192.         else
  193.             local oldsrc = board[oldy][oldx]
  194.             local olddest = board[newy][newx]
  195.             -- I'm a bit worried about this... test!
  196.             board[newy][newx] = board[oldy][oldx]
  197.             board[oldy][oldx] = " "
  198.            
  199.             isLegal = not isInCheck(whiteKing.x,whiteKing.y,amWhite)
  200.            
  201.             board[oldy][oldx] = oldsrc
  202.             board[newy][newx] = olddest
  203.         end
  204.     else
  205.         if piece=="K" then isLegal = not isInCheck(newx,newy,amWhite)
  206.         else
  207.             local oldsrc = board[oldy][oldx]
  208.             local olddest = board[newy][newx]
  209.             -- I'm a bit worried about this... test!
  210.             board[newy][newx] = board[oldy][oldx]
  211.             board[oldy][oldx] = " "
  212.            
  213.             isLegal = not isInCheck(blackKing.x,blackKing.y,amWhite)
  214.            
  215.             board[oldy][oldx] = oldsrc
  216.             board[newy][newx] = olddest
  217.         end
  218.     end
  219.    
  220.     if not isLegal then printMessage("That move leaves your king in check.") end
  221.   end
  222.  
  223.   return isLegal
  224. end
  225.  
  226. --This loops through every position on the board, and where enemy pieces are
  227. --found, determines if any place the king in check.
  228. function isInCheck(posx,posy,amWhite)
  229.     local takeable = "+"
  230.     if amWhite then takeable = "-" end
  231.  
  232.     for i=1,8 do
  233.         for j=1,8 do
  234.             if string.sub(board[j][i], 1, 1) == takeable then
  235.                 local piece = string.sub(board[j][i], 2)
  236.                 local legal = false
  237.                 if piece=="p" then legal = isLegalPawn(i,j,posx,posy,not amWhite,true,true)
  238.                 elseif piece=="C" then legal = isLegalCastle(i,j,posx,posy,not amWhite,true)
  239.                 elseif piece=="N" then legal = isLegalKnight(i,j,posx,posy,not amWhite,true)
  240.                 elseif piece=="B" then legal = isLegalBishop(i,j,posx,posy,not amWhite,true)
  241.                 elseif piece=="Q" then legal = isLegalQueen(i,j,posx,posy,not amWhite,true)
  242.                 elseif piece=="K" then legal = isLegalKing(i,j,posx,posy,not amWhite,true,true) end
  243.                 if legal then return true end
  244.             end
  245.         end
  246.     end
  247.     return false
  248. end
  249.  
  250. --Legal for a pawn. Color dependent. Manages movement and capturing (including en passant)
  251. --The forking exception means the pawn will ONLY accept diagonals, not forwards
  252. function isLegalPawn(oldx,oldy,newx,newy,amWhite,suppress,forKing)
  253.     if amWhite then
  254.         local takeable = "-"
  255.         if newy-oldy == 1 and newx-oldx == 0 and board[newy][newx] == " " and not forKing
  256.             then return true
  257.         elseif newy-oldy == 2 and newx-oldx == 0 and board[newy][newx] == " " and
  258.           board[newy-1][newx] == " " and oldy == 2 and not forKing
  259.             then return true
  260.         elseif newy-oldy == 1 and math.abs(newx-oldx) == 1 then
  261.             if string.sub(board[newy][newx], 1, 1) == takeable or forKing then return true
  262.             elseif board[newy-1][newx] == takeable.."p" and
  263.             movesMade[#movesMade].newy == newy-1 and movesMade[#movesMade].newx == newx and
  264.               math.abs(movesMade[#movesMade].newy - movesMade[#movesMade].oldy) == 2 then
  265.                 return true
  266.             end
  267.             if not suppress then printMessage("You cannot take that space with the pawn.") end
  268.         end
  269.         if not suppress then printMessage("Your pawn can't move there.") end
  270.     else
  271.         local takeable = "+"
  272.         if newy-oldy == -1 and newx-oldx == 0 and board[newy][newx] == " " and not forKing
  273.             then return true
  274.         elseif newy-oldy == -2 and newx-oldx == 0 and board[newy][newx] == " " and
  275.           board[newy+1][newx] == " " and oldy == 7 and not forKing
  276.             then return true
  277.         elseif newy-oldy == -1 and math.abs(newx-oldx) == 1 then
  278.             if string.sub(board[newy][newx], 1, 1) == takeable or forKing then return true
  279.             elseif board[newy+1][newx] == takeable.."p" and
  280.               math.abs(movesMade[#modesMade].newy - movesMade[#movesMade].oldy) == 2 then
  281.                 return true
  282.             end
  283.             if not suppress then printMessage("You cannot take that space with the pawn.") end
  284.         end
  285.         if not suppress then printMessage("Your pawn can't move there.") end
  286.     end
  287.    
  288.     return false
  289. end
  290.  
  291. --Legal for a castle. Manages movement and capturing
  292. function isLegalCastle(oldx,oldy,newx,newy,amWhite,suppress)
  293.     local takeable = "+"
  294.     if amWhite then takeable = "-" end
  295.    
  296.     if newy == oldy then
  297.         local inc = 1
  298.         if newx < oldx then inc = -1 end
  299.         for i = oldx+inc, newx-inc, inc do
  300.             if board[newy][i] ~= " " then
  301.                 if not suppress then printMessage("The castle's path is blocked to that space.") end
  302.                 return false
  303.             end
  304.         end
  305.         piece = board[newy][newx]
  306.         if piece == " " or string.sub(piece, 1, 1) == takeable then return true end
  307.         if not suppress then printMessage("Your castle can't take that piece.") end
  308.         return false
  309.        
  310.     elseif newx == oldx then
  311.         local inc = 1
  312.         if newy < oldy then inc = -1 end
  313.         for i = oldy+inc, newy-inc, inc do
  314.             if board[i][newx] ~= " " then
  315.                 if not suppress then printMessage("The castle's path is blocked to that space.") end
  316.                 return false
  317.             end
  318.         end
  319.         piece = board[newy][newx]
  320.         if piece == " " or string.sub(piece, 1, 1) == takeable then return true end
  321.         if not suppress then printMessage("Your castle can't take that piece.") end
  322.         return false
  323.     end
  324.     if not suppress then printMessage(oldx..","..oldy.." can only move along ranks or files.") end
  325.     return false
  326. end
  327.  
  328. --Legal for a knight. Manages movement and capturing
  329. function isLegalKnight(oldx,oldy,newx,newy,amWhite,suppress)
  330.     local takeable = "+"
  331.     if amWhite then takeable = "-" end
  332.  
  333.     if (math.abs(oldx-newx) == 1 and math.abs(oldy-newy) == 2) or
  334.       (math.abs(oldx-newx) == 2 and math.abs(oldy-newy) == 1) then
  335.         if board[newy][newx] == " " or string.sub(board[newy][newx], 1, 1) == takeable then
  336.             return true
  337.         end
  338.     end
  339.    
  340.     if not suppress then printMessage("Your knight can't move there.") end
  341.     return false
  342. end
  343.  
  344. --Legal for a bishop. Manages movement and capturing
  345. function isLegalBishop(oldx,oldy,newx,newy,amWhite,suppress)
  346.     local takeable = "+"
  347.     if amWhite then takeable = "-" end
  348.    
  349.     if math.abs(oldx-newx) == math.abs(oldy-newy) then
  350.         local xmp = 1
  351.         local ymp = 1
  352.         if newx < oldx then xmp = -1 end
  353.         if newy < oldy then ymp = -1 end
  354.         for i = 1,math.abs(oldx-newx) - 1 do
  355.             if board[oldy + (i * ymp)][oldx + (i * xmp)] ~= " " then
  356.                 printMessage("The bishop's path is blocked to that space.")
  357.                 return false
  358.             end
  359.         end
  360.         piece = board[newy][newx]
  361.         if piece == " " or string.sub(piece, 1, 1) == takeable then return true end
  362.         printMessage("Your bishop can't take that piece.")
  363.         return false
  364.     end
  365.     if not suppress then printMessage("Bishops can only move along diagonals.") end
  366.     return false
  367. end
  368.  
  369. --Legal for a queen. Manages movement and capturing
  370. function isLegalQueen(oldx,oldy,newx,newy,amWhite,suppress)
  371.     local possible = isLegalBishop(oldx,oldy,newx,newy,amWhite,suppress) or
  372.       isLegalCastle(oldx,oldy,newx,newy,amWhite,suppress)
  373.     if not possible and not suppress then printMessage("Your queen can't move there.") end
  374.     return possible
  375. end
  376.  
  377. --Legal for a king. Managed movement and capturing
  378. -- The forking exception excludes the ability to castle
  379. function isLegalKing(oldx,oldy,newx,newy,amWhite,suppress,forKing)
  380.     local takeable = "+"
  381.     if amWhite then takeable = "-" end
  382.    
  383.     if newx - oldx == 2 and newy-oldy == 0 and not forKing then return isLegalCastling("king", amWhite)
  384.     elseif newx - oldx == -2 and newy-oldy == 0 and not forKing then return isLegalCastling("queen", amWhite)
  385.     elseif math.abs(oldx-newx) > 1 or math.abs(oldy-newy) > 1 then
  386.         if not suppress then printMessage("Your king can only move one tile in any direction") end
  387.         return false
  388.     end
  389.    
  390.     piece = board[newy][newx]
  391.     if piece == " " or string.sub(piece, 1, 1) == takeable then return true end
  392.     if not suppress then printMessage("Your king can't take that piece.") end
  393.     return false
  394. end
  395.  
  396. --This isLegal method is aimed specifically at castling, with the string being
  397. --passed "king" or "queen" to indicate kingside or queenside castling.
  398. function isLegalCastling(side,amWhite)
  399.     if amWhite then
  400.         if side == "king" then
  401.             if board[1][6]~= " " or board[1][7] ~= " " then
  402.                 printMessage("You cannot castle- the path is blocked")
  403.                 return false
  404.             end
  405.            
  406.             for i=1,#movesMade do
  407.                 local move = movesMade[i]
  408.                 if move.piece == "K" and move.player == "+" then
  409.                     printMessage("You cannot castle- your king has moved before.")
  410.                     return false
  411.                 elseif move.piece == "C" and move.player == "+"
  412.                   and move.oldx == 8 and move.oldy == 1 then
  413.                     printMessage("You cannot castle- your ks castle has moved before.")
  414.                     return false
  415.                 end
  416.             end
  417.             return true
  418.         elseif side == "queen" then
  419.             if board[1][2] ~= " " or board[1][3] ~= " " or board[1][4] ~= " " then
  420.                 printMessage("You cannot castle- the path is blocked")
  421.                 return false
  422.             end
  423.            
  424.             for i=1,#movesMade do
  425.                 local move = movesMade[i]
  426.                 if move.piece == "K" and move.player == "+" then
  427.                     printMessage("You cannot castle- your king has moved before.")
  428.                     return false
  429.                 elseif move.piece == "C" and move.player == "+"
  430.                   and move.oldx == 1 and move.oldy == 1 then
  431.                     printMessage("You cannot castle- your qs castle has moved before.")
  432.                     return false
  433.                 end
  434.             end
  435.             return true
  436.         end
  437.        
  438.     else
  439.    
  440.         if side == "king" then
  441.             if board[8][6]~= " " or board[8][7] ~= " " then
  442.                 printMessage("You cannot castle- the path is blocked")
  443.                 return false
  444.             end
  445.            
  446.             for i=1,#movesMade do
  447.                 local move = movesMade[i]
  448.                 if move.piece == "K" and move.player == "-" then
  449.                     printMessage("You cannot castle- your king has moved before.")
  450.                     return false
  451.                 elseif move.piece == "C" and move.player == "-" and
  452.                   move.oldx == 8 and move.oldy == 8 then
  453.                     printMessage("You cannot castle- your ks castle has moved before.")
  454.                     return false
  455.                 end
  456.             end
  457.             return true
  458.         elseif side == "queen" then
  459.             if board[8][2] ~= " " or board[8][3] ~= " " or board[8][4] ~= " " then
  460.                 printMessage("You cannot castle- the path is blocked")
  461.                 return false
  462.             end
  463.            
  464.             for i=1,#movesMade do
  465.                 local move = movesMade[i]
  466.                 if move.piece == "K" and move.player == "-" then
  467.                     printMessage("You cannot castle- your king has moved before.")
  468.                     return false
  469.                 elseif move.piece == "C" and move.player == "-" and
  470.                   move.oldx == 1 and move.oldy == 8 then
  471.                     printMessage("You cannot castle- your qs castle has moved before.")
  472.                     return false
  473.                 end
  474.             end
  475.             return true
  476.         end
  477.     end
  478. end
  479.  
  480. --Submethod of isLegal, determines whether or not the choice of piece and
  481. --destination square make sense within the game
  482. function coordinatesSensible(oldx, oldy, newx, newy)
  483.   if oldx == newx and oldy == newy then
  484.     printMessage("Each piece must move at least 1 square.")
  485.     return false
  486.   end
  487.  
  488.   if oldx < 1 or oldx > 8 or newx < 1 or newx > 8 or oldy < 1 or oldy > 8
  489.     or newy < 1 or newy > 8 then
  490.     printMessage("The coordinates you provided were invalid")
  491.     return false
  492.   end
  493.   local piece = board[oldy][oldx]
  494.   if piece == " " then
  495.     printMessage("There isn't a piece on that space")
  496.     return false
  497.   elseif (string.sub(piece, 1, 1) == "+") ~= youAreWhite then
  498.     printMessage("There's an enemy piece on that space")
  499.     return false end
  500.   return true
  501. end
  502.  
  503. --This actually acts upon the move made. It moves the piece on the board, adds
  504. --an entry to the moves list, tells the other commputer the move is made and
  505. --refreshes everything.
  506. function makeMove(oldx,oldy,newx,newy,amWhite)
  507.     local player = "+"
  508.     local foe = "-"
  509.     if not amWhite then
  510.         player = "-"
  511.         foe = "+"
  512.     end
  513.    
  514.     local capture = false
  515.     local ep = false
  516.    
  517.     if board[newy][newx] ~= " " then capture = true end
  518.     if board[newy][newx] == " " and math.abs(oldx-newx) == 1 and
  519.       board[oldy][oldx]:sub(2) == "p" and board[oldy][newx]:sub(2) == "p" then
  520.         capture = true
  521.         ep = true
  522.         board[oldy][newx] = " "
  523.     end
  524.    
  525.     board[newy][newx] = board[oldy][oldx]
  526.     board[oldy][oldx] = " "
  527.     local piece = string.sub(board[newy][newx], 2)
  528.    
  529.     --We handle updating king positions and CASTLING here
  530.     castle = 0
  531.     if board[newy][newx] == "+K" then
  532.         whiteKing = { x = newx, y = newy }
  533.         if newx - oldx == 2 then
  534.             board[1][6] = board[1][8]
  535.             board[1][8] = " "
  536.             castle = 1
  537.         elseif newx - oldx == -2 then
  538.             board[1][4] = board[1][1]
  539.             board[1][1] = " "
  540.             castle = -1
  541.         end
  542.     end
  543.     if board[newy][newx] == "-K" then
  544.         blackKing = { x = newx, y = newy }
  545.         if newx - oldx == 2 then
  546.             board[8][6] = board[8][8]
  547.             board[8][8] = " "
  548.             castle = 1
  549.         elseif newx - oldx == -2 then
  550.             board[8][4] = board[8][1]
  551.             board[8][1] = " "
  552.             castle = -1
  553.         end
  554.     end
  555.    
  556.     --Promotion is handled here
  557.     promotion = ""
  558.     if piece == "p" then
  559.         if (youAreWhite and player == "+" and newy == 8) or
  560.           (not youAreWhite and player == "-" and newy == 1) then
  561.             handlePawnPromotion(newx, newy, youAreWhite)
  562.             promotion = string.sub(board[newy][newx], 2)
  563.             if not isLocal then
  564.                 rednet.send(opponentID, "#P"..newx..newy..board[newy][newx])
  565.                 sendToMonitors("#P"..newx..newy..board[newy][newx])
  566.             end
  567.         end
  568.     end
  569.    
  570.     local check = false
  571.     --Again, needs to be debugged
  572.     if not amWhite then
  573.         check = isInCheck(whiteKing.x, whiteKing.y, true)
  574.     else
  575.         check = isInCheck(blackKing.x, blackKing.y, false)
  576.     end
  577.    
  578.    
  579.     table.insert(movesMade, {
  580.       player = player,
  581.       piece = piece,
  582.       oldx = oldx,
  583.       oldy = oldy,
  584.       newx = newx,
  585.       newy = newy,
  586.       capture = capture,
  587.       castle = castle,
  588.       promotion = promotion,
  589.       ep = ep,
  590.       check = check,
  591.       mate = false,
  592.       stale = false
  593.     })
  594. end
  595.  
  596. --A specialized function that reads input to determine a pawn promotion
  597. --This is called in makeMove, but only if it's the same player
  598. function handlePawnPromotion(x,y,amWhite)
  599.     printMessage("Promote: (Q)ueen, (C)astle, k(N)ight or (B)ishop")
  600.     term.setCursorPos(1, 16)
  601.     term.clearLine()
  602.     term.write("> ")
  603.    
  604.     local ptype = "+"
  605.     if not amWhite then ptype = "-" end
  606.    
  607.     local id,key = os.pullEvent("char")
  608.     if string.upper(key) == "C" then
  609.         board[y][x] = ptype.."C"
  610.     elseif string.upper(key) == "N" then
  611.         board[y][x] = ptype.."N"
  612.     elseif string.upper(key) == "B" then
  613.         board[y][x] = ptype.."B"
  614.     else
  615.         --We do this by default... easier this way
  616.         board[y][x] = ptype.."Q"
  617.     end
  618.    
  619.     printMessage("Pawn promoted")
  620.     --Restarts that timer we so rudely interrupted
  621.     os.startTimer(0.1)
  622. end
  623.  
  624. --This promotes a pawn from a network message
  625. function handleRemotePawnPromotion(msg)
  626.     local x = tonumber(string.sub(msg, 1, 1))
  627.     local y = tonumber(string.sub(msg, 2, 2))
  628.     local piece = string.sub(msg, 3)
  629.    
  630.     board[y][x] = piece
  631.     movesMade[#movesMade].promotion = string.sub(msg, 4)
  632. end
  633.  
  634. --Takes in an input string and converts it to a chess query.
  635. --The input method is EXTREMELY strict. This ensures it conforms
  636. --The input string must be 5 characters long- the first two are the X and Y of
  637. --the piece to move, followed by a space character and the second two coordinates.
  638. --Example of a legal input: e5-b7 a1 a6 f3xg2
  639. --Example of illegal input: 55 b3 a4  h8 f3xg2+
  640. --This will return true if the move occurred, false otherwise
  641. function parseInput(input,amWhite)
  642.     if input == "quit" or input == "exit" then
  643.         if not isLocal then
  644.             rednet.send(opponentID, "#E")
  645.         end
  646.         playing = false
  647.         return true
  648.     end
  649.     if (input == "reset" or input == "restart") and isLocal then
  650.         resetGame(true)
  651.         return true
  652.     end
  653.     if input == "draw" then
  654.         printMessage("Waiting for response...")
  655.         rednet.send(opponentID, "#D")
  656.         while true do
  657.             local id,key,msg = os.pullEvent("rednet_message")
  658.             if msg == "#Y" then
  659.                 printMessage("Game result: 1/2 - 1/2")
  660.                 os.pullEvent("key")
  661.                 playing = false
  662.                 return true
  663.             elseif msg == "#N" then
  664.                 printMessage("Draw rejected.")
  665.                 os.startTimer(0.2)
  666.                 return false
  667.             end
  668.         end
  669.     end
  670.    
  671.     if gameOver then
  672.         printMessage("Game is over- you can \'exit\' or \'restart\'.")
  673.         return false
  674.     end
  675.  
  676.     local oldx = convertLetterToCoordinate(string.sub(input, 1, 1))
  677.     local oldy = tonumber(string.sub(input, 2, 2))
  678.     if not oldy then oldy = -1 end
  679.     local newx = convertLetterToCoordinate(string.sub(input, 4, 4))
  680.     local newy = tonumber(string.sub(input, 5, 5))
  681.     if not newy then newy = -1 end
  682.  
  683.     if isLegal(oldx,oldy,newx,newy,amWhite) then
  684.         printMessage("Making move...")
  685.         makeMove(oldx,oldy,newx,newy,amWhite)
  686.         return true
  687.     end
  688.     return false
  689. end
  690.  
  691. --Runs on the OS timer and uses it to update the black pieces flashing on and off
  692. function updateBlackFlashing()
  693.   blackVisible = not blackVisible
  694.   printBoard()
  695.  
  696.   local length = 0.2
  697.   if not blackVisible then length = 0.15 end
  698.   os.startTimer(length)
  699. end
  700.  
  701. --This prints the oneline message above the command prompt
  702. function printMessage(message)
  703.   term.setCursorPos(1, 15)
  704.   term.clearLine()
  705.   term.write(message)
  706. end
  707.  
  708. --This converts a letter coordinate like a or f to a number
  709. function convertLetterToCoordinate(input)
  710.   if input=="a" then return 1
  711.   elseif input=="b" then return 2
  712.   elseif input=="c" then return 3
  713.   elseif input=="d" then return 4
  714.   elseif input=="e" then return 5
  715.   elseif input=="f" then return 6
  716.   elseif input=="g" then return 7
  717.   elseif input=="h" then return 8
  718.   else return -1 end
  719. end
  720.  
  721. --The reverse operation. Converts a number to a letter coordiante.
  722. function convertCoordinateToLetter(input)
  723.   if input==1 then return "a"
  724.   elseif input==2 then return "b"
  725.   elseif input==3 then return "c"
  726.   elseif input==4 then return "d"
  727.   elseif input==5 then return "e"
  728.   elseif input==6 then return "f"
  729.   elseif input==7 then return "g"
  730.   elseif input==8 then return "h"
  731.   else return -1 end
  732. end
  733.  
  734. --An update function for the input display- displaying the latest string
  735. function updateInputDisplay()
  736.     term.setCursorPos(1, 16)
  737.     term.clearLine()
  738.     term.write("> "..lastQuery)
  739. end
  740.  
  741. --Restores the board to it's original state, and clears all moves.
  742. function resetGame(amWhite)
  743.     term.clear()
  744.     youAreWhite = amWhite
  745.     whiteTurn = true
  746.     movesMade = {}
  747.     gameOver = false
  748.     --[[
  749.     board = {
  750.         --        a     b     c     d     e     f     g     h
  751.         [8] = { " ",  " ",  " ",  " ",  " ",  " ",  " ",  " " },
  752.         [7] = { " ",  " ",  " ",  " ",  "+p",  " ",  " ",  " " },
  753.         [6] = { " ",  " ",  " ",  " ",  " ",  " ",  " ",  " " },
  754.         [5] = { " ",  " ",  " ",  " ",  " ",  " ",  " ",  " " },
  755.         [4] = { " ",  " ",  " ",  " ",  " ",  " ",  " ",  " " },
  756.         [3] = { " ",  " ",  " ",  " ",  " ",  " ",  " ",  " " },
  757.         [2] = { " ",  " ",  " ",  " ",  "-p",  " ",  " ",  " " },
  758.         [1] = { " ",  " ",  " ",  " ",  " ",  " ",  " ",  " " }
  759.         --        a     b     c     d     e     f     g     h
  760.     }]]--
  761.     board = {
  762.         --       a     b     c     d     e     f     g     h
  763.         [8] = { "-C", "-N", "-B", "-Q", "-K", "-B", "-N", "-C"},
  764.         [7] = { "-p", "-p", "-p", "-p", "-p", "-p", "-p", "-p"},
  765.         [6] = { " ",  " ",  " ",  " ",  " ",  " ",  " ",  " " },
  766.         [5] = { " ",  " ",  " ",  " ",  " ",  " ",  " ",  " " },
  767.         [4] = { " ",  " ",  " ",  " ",  " ",  " ",  " ",  " " },
  768.         [3] = { " ",  " ",  " ",  " ",  " ",  " ",  " ",  " " },
  769.         [2] = { "+p", "+p", "+p", "+p", "+p", "+p", "+p", "+p"},
  770.         [1] = { "+C", "+N", "+B", "+Q", "+K", "+B", "+N", "+C"}
  771.         --       a     b     c     d     e     f     g     h
  772.     }
  773. end
  774.  
  775. --This manages the game logic. It runs in an infinite loop (of course)
  776. function playGame()
  777.     term.clear()
  778.     os.startTimer(0.2)
  779.     while playing do
  780.         printMovesMade()
  781.         printBoard()
  782.         printHeader()
  783.         term.setCursorPos(1, 16)
  784.         term.clearLine()
  785.         term.write("> ")
  786.        
  787.         if not isLocal and youAreWhite ~= whiteTurn then
  788.             local proMsg = nil
  789.             while true do
  790.                 local id,  key, msg = os.pullEvent()
  791.                 if id == "timer" then updateBlackFlashing()
  792.                 elseif id == "rednet_message" and key == opponentID then
  793.                     if msg == "#E" then
  794.                         playing = false
  795.                         break
  796.                     elseif msg == "#D" then
  797.                         printMessage("Draw offered- accept? (Y)es or (N)o")
  798.                         local id,key = os.pullEvent("char")
  799.                         if key == "Y" or key == "y" then
  800.                             playing = false
  801.                             printMessage("Game result: 1/2 - 1/2")
  802.                             rednet.send(opponentID, "#Y")
  803.                             os.pullEvent("key")
  804.                             break
  805.                         else
  806.                             printMessage("Draw rejected.")
  807.                             rednet.send(opponentID, "#N")
  808.                             os.startTimer(0.2)
  809.                         end
  810.                     elseif string.find(msg, "#P") == 1 then
  811.                         proMsg = string.gsub(msg, "#P", "")
  812.                     else
  813.                         local oldx = convertLetterToCoordinate(string.sub(msg, 1, 1))
  814.                         local oldy = tonumber(string.sub(msg, 2, 2))
  815.                         local newx = convertLetterToCoordinate(string.sub(msg, 4, 4))
  816.                         local newy = tonumber(string.sub(msg, 5, 5))
  817.                        
  818.                         makeMove(oldx,oldy,newx,newy,not youAreWhite)
  819.                        
  820.                         if proMsg then handleRemotePawnPromotion(proMsg) end
  821.                         break
  822.                     end
  823.                 end
  824.             end
  825.         else
  826.             local noMoves = #movesMade
  827.             while noMoves == #movesMade do
  828.                 local id,key = os.pullEvent()
  829.                 if id == "timer" then updateBlackFlashing()
  830.                 elseif id == "key" then
  831.                     if key == 14 then
  832.                         if #lastQuery > 1 then lastQuery = string.sub(lastQuery, 1, #lastQuery-1)
  833.                         else lastQuery = "" end
  834.                     elseif key == 28 then
  835.                         local occ = parseInput(lastQuery, youAreWhite)
  836.                         if occ and not isLocal then
  837.                             rednet.send(opponentID, lastQuery)
  838.                             sendToMonitors(lastQuery)
  839.                         end
  840.                        
  841.                         if (lastQuery == "reset" or lastQuery == "restart") then
  842.                             lastQuery = ""
  843.                             break
  844.                         end
  845.                         lastQuery = ""
  846.                         if not playing then break end
  847.                     end
  848.                     updateInputDisplay()
  849.                 elseif id == "char" then
  850.                     lastQuery = lastQuery..key
  851.                     updateInputDisplay()
  852.                 end
  853.             end
  854.         end
  855.        
  856.         if isLocal then youAreWhite = not youAreWhite end
  857.         whiteTurn = not whiteTurn
  858.     end
  859.     --With the menu system, we allow the player to return to the main menu
  860.     --This can be turned off to make an exit quit chess altogether
  861.     playing = true
  862.     sendToMonitors("#Q")
  863. end
  864.  
  865. --Finds the side the modem is on, and opens it
  866. function openModem()
  867.     for i=1,#rs.getSides() do
  868.         if peripheral.isPresent(rs.getSides()[i]) and peripheral.getType(rs.getSides()[i]) == "modem" then
  869.             side = rs.getSides()[i]
  870.             rednet.open(side)
  871.             return true
  872.         end
  873.     end
  874.     return false
  875. end
  876.  
  877. --Sends a message to each monitor hooked up to the network
  878. function sendToMonitors(msg)
  879.     for k,v in pairs(monitorList) do
  880.         rednet.send(v, msg)
  881.     end
  882. end
  883.  
  884. --[[                    GUI REGION
  885.         This code handles the visual interface for the
  886.         menu system and network play of the Chess system        ]]--
  887.        
  888. --The error message displayed when a network error has occurred
  889. local networkErrorMessage = ""
  890. --The currently selected menu option
  891. local menuSel = 1
  892. --Which help page is currently being viewed
  893. local helpPage = 1
  894.  
  895. --Draws the main menu
  896. function drawMainInterface()
  897.     term.clear()
  898.     drawASCIIKing(w-12,h-14)
  899.     drawASCIIRook(5, h-9)
  900.    
  901.     term.setCursorPos(4, 3)
  902.     term.write("Minecraft Chess")
  903.     term.setCursorPos(4, 4)
  904.     term.write("===============")
  905.    
  906.     printCentered("Local Game", 7)
  907.     printCentered("Network Game", 10)
  908.     printCentered("Instructions", 13)
  909.     printCentered("Quit Game", 16)
  910.    
  911.     printCentered("------------", 5 + menuSel * 3)
  912. end
  913.  
  914. --Draws the "host network game" menu interface
  915. function drawNetworkInterface()
  916.     term.clear()
  917.     drawASCIIBishop(w - 10, h - 12)
  918.     drawASCIIPawn(3, h - 7)
  919.     drawASCIIPawn(5, h - 6)
  920.    
  921.     printCentered("Network Game", 2)
  922.     printCentered("============", 3)
  923.    
  924.     printCentered("Host", 7)
  925.     printCentered("Join", 10)
  926.     printCentered("Back", 13)
  927.     printCentered("------", 5 + menuSel * 3)
  928. end
  929.  
  930. --Draws the screen that requests an computer ID
  931. function drawIDRequest()
  932.     term.clear()
  933.     drawASCIIBishop(w - 10, h - 12)
  934.     drawASCIIPawn(3, h - 7)
  935.     drawASCIIPawn(5, h - 6)
  936.    
  937.     term.setCursorPos(4, 5)
  938.     term.write("Enter the host's computer ID: ")
  939. end
  940.  
  941. --In the event players can't connet, by timeout or no modem or something this says so
  942. function drawNetworkError()
  943.     term.clear()
  944.     drawASCIIBishop(w - 10, h - 12)
  945.     drawASCIIPawn(3, h - 7)
  946.     drawASCIIPawn(5, h - 6)
  947.    
  948.     printCentered(networkErrorMessage, 5)
  949.     printCentered("Press any key to go back.", 10)
  950. end
  951.  
  952. --Draws the "wait for connection" interface
  953. function drawWaitForConnection()
  954.     term.clear()
  955.     drawASCIIBishop(w - 10, h - 12)
  956.     drawASCIIPawn(3, h - 7)
  957.     drawASCIIPawn(5, h - 6)
  958.    
  959.     printCentered("Waiting for connection...", 5)
  960.     printCentered("(Your ID is "..os.getComputerID()..")", 6)
  961.     printCentered("Press enter to cancel", 8)
  962. end
  963.  
  964. --Draws the tutorial help functions
  965. function drawHelp()
  966.     term.clear()
  967.     drawASCIIKnight(3, h - 7)
  968.     drawASCIIPawn(13, h - 6)
  969.    
  970.     local nextstr = "Next"
  971.     local prevstr = "Prev"
  972.     local offset = 0
  973.    
  974.     for i=1,#helpText[helpPage] do
  975.         term.setCursorPos(2,1 + i)
  976.         term.write(helpText[helpPage][i])
  977.     end
  978.    
  979.     if helpPage == 1 then
  980.         prevstr = string.rep(" ", 4)
  981.         offset = 12
  982.     end
  983.     if helpPage == #helpText then nextstr = string.rep(" ", 4) end
  984.    
  985.     term.setCursorPos(20, 15)
  986.     term.write(prevstr..string.rep(" ", 8).."Back"..string.rep(" ", 8)..nextstr)
  987.     term.setCursorPos(8 + offset + menuSel * 12, 16)
  988.     term.write("----")
  989.     term.setCursorPos(35, 18)
  990.     term.write("Page "..helpPage.." of "..#helpText)
  991. end
  992.  
  993. --Starts a local game
  994. function startLocalGame()
  995.     resetGame(true)
  996.     isLocal = true
  997.     playGame()
  998.     currentInterface = interfaces["main"]
  999. end
  1000.  
  1001. --Starts a network game
  1002. function startNetworkGame(amWhite)
  1003.     resetGame(amWhite)
  1004.     isLocal = false
  1005.     playGame()
  1006.     currentInterface = interfaces["main"]
  1007. end
  1008.  
  1009. --[[The following methods are tiny stubs to fix the variable no access issue]]--
  1010. --Necessary to set the interface back to main(no access from inside a list)
  1011. function returnToMainMenu()
  1012.     currentInterface = interfaces["main"]
  1013. end
  1014. --Necessary to update the help pages
  1015. function updateHelpPage(value)
  1016.     helpPage = value
  1017.     if helpPage ~= 1 then menuSel = 2 end
  1018. end
  1019.  
  1020. --Prints the provided string in the centre of the screen at the y coordinate specified 
  1021. function printCentered(str,y)
  1022.     term.setCursorPos(w/2 - #str/2, y)
  1023.     term.write(str)
  1024. end
  1025.  
  1026. --Draws an ASCII king at the desired coordinates. Dimensions are (10,14) characters
  1027. function drawASCIIKing(x,y)
  1028.     local kingList = {
  1029.         "   _||_   ",
  1030.         "   _||_   ",
  1031.         " _/____\\_ ",
  1032.        " \\      / ",
  1033.        "  \\____/  ",
  1034.         "  (____)  ",
  1035.         "   |  |   ",
  1036.         "   |  |   ",
  1037.         "   |  |   ",
  1038.         "   |  |   ",
  1039.         "   |__|   ",
  1040.         "  /    \\  ",
  1041.         " (______) ",
  1042.         "(________)",
  1043.     }
  1044.    
  1045.     for i=1,#kingList do
  1046.         term.setCursorPos(x, y + i - 1)
  1047.         term.write(kingList[i])
  1048.     end
  1049. end
  1050.  
  1051. --Draws an ASCII rook at the desired coordinates. Dimensions are (8,9) characters
  1052. function drawASCIIRook(x,y)
  1053.     local rookList = {
  1054.         " |'-'-'|",
  1055.         "  \\   / ",
  1056.         "  |   |  ",
  1057.         "  |   |  ",
  1058.         "  |   |  ",
  1059.         "  |   |  ",
  1060.         "  |___|  ",
  1061.         " /_____\\ ",
  1062.         "(_______)"
  1063.     }
  1064.    
  1065.     for i=1,#rookList do
  1066.         term.setCursorPos(x, y + i - 1)
  1067.         term.write(rookList[i])
  1068.     end
  1069. end
  1070.  
  1071. --Draws an ASCII pawn at the desired coordinates. Dimensions are (6,6) characters
  1072. function drawASCIIPawn(x,y)
  1073.     local pawnList = {
  1074.         "  __  ",
  1075.         " (  ) ",
  1076.         "  ||  ",
  1077.         "  ||  ",
  1078.         " /__\\ ",
  1079.         "(____)"
  1080.     }
  1081.    
  1082.     for i=1,#pawnList do
  1083.         term.setCursorPos(x, y + i - 1)
  1084.         term.write(pawnList[i])
  1085.     end
  1086. end
  1087.  
  1088. --Draws an ASCII knight at the desired coordinates. Dimensions are (7,9) characters
  1089. function drawASCIIKnight(x,y)
  1090.     local knightList = {
  1091.         " __/\"\"\"\\     ",
  1092.         "]___ O  }",
  1093.         "    /   }",
  1094.         "  /~    }",
  1095.        "  \\____/ ",
  1096.         "  /____\\ ",
  1097.         " (______)"
  1098.     }
  1099.    
  1100.     for i=1,#knightList do
  1101.         term.setCursorPos(x, y + i - 1)
  1102.         term.write(knightList[i])
  1103.     end
  1104. end
  1105.  
  1106. --Draws an ASCII bishop at the desired coordinates. Dimensions are (8,11) characters
  1107. function drawASCIIBishop(x,y)
  1108.     local bishopList = {
  1109.         "   _<>  ",
  1110.         " /\\\\  \\",
  1111.         " \\ \\) /",
  1112.        "  \\__/  ",
  1113.         " (____) ",
  1114.         "  |  |  ",
  1115.         "  |  |  ",
  1116.         "  |  |  ",
  1117.         "  |__|  ",
  1118.         " /____\\ ",
  1119.         "(______)"
  1120.     }
  1121.    
  1122.     for i=1,#bishopList do
  1123.         term.setCursorPos(x, y + i - 1)
  1124.         term.write(bishopList[i])
  1125.     end
  1126. end
  1127.  
  1128.  
  1129. --Requests an ID for the enemy computer
  1130. function inputOpponentID()
  1131.     opponentID = tonumber(io.read())
  1132.     if not opponentID then
  1133.         networkErrorMessage = "The ID you entered is invalid"
  1134.         currentInterface = interfaces["networkerror"]
  1135.     else
  1136.         currentInterface = interfaces["join"]
  1137.     end
  1138. end
  1139.  
  1140.  
  1141. --[WOLVAN, your code goes here]--
  1142.  
  1143. --Attempts to join a hosted game
  1144. function waitForHost()
  1145.     currentInterface = interfaces["main"]
  1146.     if not openModem() then
  1147.         networkErrorMessage = "Your computer doesn't have a modem!"
  1148.         currentInterface = interfaces["networkerror"]
  1149.         return
  1150.     end
  1151.  
  1152.     rednet.send(opponentID, "#C")
  1153.     while true do
  1154.         local id,msg = rednet.receive(5)
  1155.         currentInterface = interfaces["main"]
  1156.         if id == opponentID and msg == "#C" then
  1157.             currentInterface = interfaces["waittostart"]
  1158.             return
  1159.         end
  1160.         if id == nil then break end
  1161.     end
  1162.     networkErrorMessage = "The connection timed out."
  1163.     currentInterface = interfaces["networkerror"]
  1164. end
  1165.  
  1166. --Waits on a user to join the game
  1167. function waitForClient()
  1168.     if not openModem() then
  1169.         networkErrorMessage = "Your computer doesn't have a modem!"
  1170.         currentInterface = interfaces["networkerror"]
  1171.         return
  1172.     end
  1173.    
  1174.     while true do
  1175.         local evt,id,msg = os.pullEvent()
  1176.         if evt == "rednet_message" and msg == "#C" then
  1177.             opponentID = id
  1178.             rednet.send(opponentID, "#C")
  1179.             currentInterface = interfaces["addmonitors"]
  1180.             return
  1181.         elseif evt == "key" and id == 28 then
  1182.             currentInterface = interfaces["main"]
  1183.             return
  1184.         end
  1185.     end
  1186.     networkErrorMessage = "The connection timed out."
  1187.     currentInterface = interfaces["networkerror"]
  1188. end
  1189.  
  1190. --Draws the request to add more monitors or just move on
  1191. function drawAddMonitors()
  1192.     term.clear()
  1193.     drawASCIIBishop(w - 10, h - 12)
  1194.     drawASCIIPawn(3, h - 7)
  1195.     drawASCIIPawn(5, h - 6)
  1196.    
  1197.     printCentered("Connection established- add monitors now", 5)
  1198.     printCentered("(Your ID is "..os.getComputerID()..")", 6)
  1199.     printCentered("Press any key to start the game", 8)
  1200. end
  1201.  
  1202. --Waits for any monitors to connect to the network, and starts a new game when ready
  1203. function addMonitors()
  1204.     while true do
  1205.         local id,key,value = os.pullEvent()
  1206.         if id == "rednet_message" and value=="#M" then
  1207.             table.insert(monitorList, key)
  1208.             rednet.send(opponentID, "#M"..key)
  1209.             rednet.send(key, "#Y")
  1210.         elseif id == "key" and key == 28 then
  1211.             rednet.send(opponentID, "#S")
  1212.             startNetworkGame(true)
  1213.             currentInterface = interfaces["main"]
  1214.             return
  1215.         end
  1216.     end
  1217. end
  1218.  
  1219. --Displays a simple "waiting to start"  message
  1220. function drawWaitingToStart()
  1221.     term.clear()
  1222.     drawASCIIBishop(w - 10, h - 12)
  1223.     drawASCIIPawn(3, h - 7)
  1224.     drawASCIIPawn(5, h - 6)
  1225.    
  1226.     printCentered("Connection Established!", 5)
  1227.     printCentered("Waiting for host...", 6)
  1228.     printCentered("The game will start shortly", 8)
  1229. end
  1230.  
  1231. --Listens for any monitors that may be received and when #S appears the game starts
  1232. function waitToStart()
  1233.     while true do
  1234.         local id, key, value = os.pullEvent("rednet_message")
  1235.         if key == opponentID then
  1236.             if string.find(value, "#M") == 1 then
  1237.                 value = string.sub(value, 3)
  1238.                 if tonumber(value) then table.insert(monitorList, (tonumber(value))) end
  1239.             elseif value == "#S" then
  1240.                 startNetworkGame(false)
  1241.                 currentInterface = interfaces["main"]
  1242.                 return
  1243.             end
  1244.         end
  1245.     end
  1246.  end
  1247.  
  1248. --[[
  1249.     Construction of an interface menu has the following requirements:
  1250.     the index should be the string identifying that menu element
  1251.     options - A list of all menu options in order of selection
  1252.     draw - a function that draws the menu
  1253.     setup - a function that organizes the setup (this may include starting a new game)
  1254.     nextKeyCode - the key the user must strike to move to the next menu option
  1255.     prevKeyCode - the key the user must strike to move to the previous menu option
  1256.     input - overrides the standard key handler, if the interface has one.
  1257. ]]--
  1258. interfaces = {
  1259.     ["main"] = {
  1260.         options = {"local", "network", "page1", "quit"},
  1261.         draw = drawMainInterface,
  1262.         nextKeyCode = 208,
  1263.         prevKeyCode = 200
  1264.     },
  1265.     ["local"] = {
  1266.         setup = startLocalGame
  1267.     },
  1268.     ["network"] = {
  1269.         options = {"host", "hostidinput", "main"},
  1270.         draw = drawNetworkInterface,
  1271.         nextKeyCode = 208,
  1272.         prevKeyCode = 200
  1273.     },
  1274.     ["host"] = {
  1275.         draw = drawWaitForConnection,
  1276.         input = waitForClient
  1277.     },
  1278.     ["hostidinput"] = {
  1279.         draw = drawIDRequest,
  1280.         input = inputOpponentID
  1281.     },
  1282.     ["addmonitors"] = {
  1283.         draw = drawAddMonitors,
  1284.         input = addMonitors
  1285.     },
  1286.     ["waittostart"] = {
  1287.         draw = drawWaitingToStart,
  1288.         input = waitToStart
  1289.     },
  1290.     ["join"] = {
  1291.         draw = drawWaitForConnection,
  1292.         input = waitForHost
  1293.     },
  1294.     ["networkerror"] = {
  1295.         draw = drawNetworkError,
  1296.         input = function()
  1297.             os.pullEvent("key")
  1298.             returnToMainMenu()
  1299.         end
  1300.     },
  1301.     ["unimplemented"] = {
  1302.         draw = drawUnimplementedInterface,
  1303.         input = function()
  1304.             os.pullEvent("key")
  1305.             returnToMainMenu()
  1306.         end
  1307.     },
  1308.     ["timeout"] = {
  1309.         draw = drawTimeout
  1310.     },
  1311.     --The help pages
  1312.     ["page1"] = {
  1313.         setup = function() updateHelpPage(1) end,
  1314.         options = {"main", "page2"},
  1315.         draw = drawHelp,
  1316.         nextKeyCode = 205,
  1317.         prevKeyCode = 203
  1318.     },
  1319.     ["page2"] = {
  1320.         setup = function() updateHelpPage(2) end,
  1321.         options = {"page1", "main", "page3"},
  1322.         draw = drawHelp,
  1323.         nextKeyCode = 205,
  1324.         prevKeyCode = 203
  1325.     },
  1326.     ["page3"] = {
  1327.         setup = function() updateHelpPage(3) end,
  1328.         options = {"page2", "main", "page4"},
  1329.         draw = drawHelp,
  1330.         nextKeyCode = 205,
  1331.         prevKeyCode = 203
  1332.     },
  1333.     ["page4"] = {
  1334.         setup = function() updateHelpPage(4) end,
  1335.         options = {"page3", "main", "page5"},
  1336.         draw = drawHelp,
  1337.         nextKeyCode = 205,
  1338.         prevKeyCode = 203
  1339.     },
  1340.     ["page5"] = {
  1341.         setup = function() updateHelpPage(5) end,
  1342.         options = {"page4", "main", "page6"},
  1343.         draw = drawHelp,
  1344.         nextKeyCode = 205,
  1345.         prevKeyCode = 203
  1346.     },
  1347.     ["page6"] = {
  1348.         setup = function() updateHelpPage(6) end,
  1349.         options = {"page5", "main", "page7"},
  1350.         draw = drawHelp,
  1351.         nextKeyCode = 205,
  1352.         prevKeyCode = 203
  1353.     },
  1354.     ["page7"] = {
  1355.         setup = function() updateHelpPage(7) end,
  1356.         options = {"page6", "main", "page8"},
  1357.         draw = drawHelp,
  1358.         nextKeyCode = 205,
  1359.         prevKeyCode = 203
  1360.     },
  1361.     ["page8"] = {
  1362.         setup = function() updateHelpPage(8) end,
  1363.         options = {"page7", "main", "page9"},
  1364.         draw = drawHelp,
  1365.         nextKeyCode = 205,
  1366.         prevKeyCode = 203
  1367.     },
  1368.     ["page9"] = {
  1369.         setup = function() updateHelpPage(9) end,
  1370.         options = {"page8", "main", "page10"},
  1371.         draw = drawHelp,
  1372.         nextKeyCode = 205,
  1373.         prevKeyCode = 203
  1374.     },
  1375.     ["page10"] = {
  1376.         setup = function() updateHelpPage(10) end,
  1377.         options = {"page9", "main", "page11"},
  1378.         draw = drawHelp,
  1379.         nextKeyCode = 205,
  1380.         prevKeyCode = 203
  1381.        
  1382.     },
  1383.     ["page11"] = {
  1384.         setup = function() updateHelpPage(11) end,
  1385.         options = {"page10", "main", "page12"},
  1386.         draw = drawHelp,
  1387.         nextKeyCode = 205,
  1388.         prevKeyCode = 203
  1389.        
  1390.     },
  1391.     ["page12"] = {
  1392.         setup = function() updateHelpPage(12) end,
  1393.         options = {"page11", "main", "page13"},
  1394.         draw = drawHelp,
  1395.         nextKeyCode = 205,
  1396.         prevKeyCode = 203
  1397.        
  1398.     },
  1399.     ["page13"] = {
  1400.         setup = function() updateHelpPage(13) end,
  1401.         options = {"page12", "main"},
  1402.         draw = drawHelp,
  1403.         nextKeyCode = 205,
  1404.         prevKeyCode = 203
  1405.        
  1406.     },
  1407.     ["quit"] = {
  1408.         draw = function() print("Do nothing") end,
  1409.         setup = function ()
  1410.             if side then rednet.close(side) end
  1411.             playing = false
  1412.             term.clear()
  1413.             term.setCursorPos(1,1)
  1414.         end
  1415.     }
  1416. }
  1417.  
  1418. helpText = {
  1419.     [1] = {                                                   --E"
  1420.         "Moving on the board:",
  1421.         "",
  1422.         "Chess is taken in turns between black and white, with",
  1423.         "white always starting first. To move your piece, enter",
  1424.         "the desired space with the following notation:",
  1425.         "",
  1426.         "   <file><rank>-<file><rank>"
  1427.     }, [2] = {
  1428.         "Example 1:",
  1429.         "The following move :",
  1430.         "",
  1431.         "                           4 |   *   ",
  1432.         "                           3 | *   * ",
  1433.         "                           2 | p p p ",
  1434.         "                           1 | Q K B ",
  1435.         "                              -------",
  1436.         "            > e2-e4        ... d e f "
  1437.     }, [3] = {
  1438.         "Example 1:",
  1439.         "Will move white's pawn forward 2 squares.",
  1440.         "",
  1441.         " 1. e2 - e4                4 |   p   ",
  1442.         "                           3 | *   * ",
  1443.         "                           2 | p * p ",
  1444.         "                           1 | Q K B ",
  1445.         "                              -------",
  1446.         "            > e2-e4        ... d e f "
  1447.     }, [4] = {
  1448.         "Moving on the board (CONT):",
  1449.         "",
  1450.         "Unlike standard chess notation, you do not need",
  1451.         "to specify the piece that is being moved.",
  1452.         "Taking pieces works in the same way as moving,",
  1453.         "with a few exceptions."
  1454.     }, [5] = {
  1455.         "En Passant:",
  1456.         "",
  1457.         "In taking a pawn en passant, the game assumes the",
  1458.         "pawn has only moved one square- hence the player",
  1459.         "should move his pawn as though it is on the",
  1460.         "diagonal square rather than the horizontal."
  1461.     }, [6] = {
  1462.         "Example 2:",
  1463.         "The following move (c5 is a white pawn):",
  1464.         "",
  1465.         " ...                       7 | p * K * p ",
  1466.         " 11. c4 - c5               6 | *   *   * ",
  1467.         " 12. d7 - d5               5 | p p   *   ",
  1468.         "                           4 | *   *   Q ",
  1469.         "                              -----------",
  1470.         "            > c5-d6        ... c d e f g "
  1471.     }, [7] = {
  1472.         "Example 2:",
  1473.         "Will capture d5 en passant and check e7.",
  1474.         "",
  1475.         " ...                       7 | p   K * p ",
  1476.         " 11. c4 - c5               6 | * p *   * ",
  1477.         " 12. d7 - d5               5 |   *   *   ",
  1478.         " 13. c5 x d6 e.p.+         4 | *   *   Q ",
  1479.         "                              -----------",
  1480.         "            > c5-d6        ... c d e f g "
  1481.     }, [8] = {
  1482.         "Castling:",
  1483.         "",
  1484.         "To castle your king, simply move him to the left",
  1485.         "two spaces (to castle queenside), or two spaces",
  1486.         "right (to castle kingside). This will move your",
  1487.         "castle automatically."
  1488.     }, [9] = {
  1489.         "Example 3:",
  1490.         "The following move:",
  1491.         "",
  1492.         " ...                       4 |   *   *   ",
  1493.         " 7. Bc1 - a3               3 | B p N   * ",
  1494.         " 8. d5 - d7                2 | p * p p   ",
  1495.         "                           1 | C   *   K ",
  1496.         "                              -----------",
  1497.         "            > e1-c1        ... a b c d e "
  1498.     }, [10] = {
  1499.         "Example 3:",
  1500.         "Will castle white queenside.",
  1501.         "",
  1502.         " ...                       4 |   *   *   ",
  1503.         " 7. Bc1 - a3               3 | B p N   * ",
  1504.         " 8. d5 - d7                2 | p * p p   ",
  1505.         " 9. O-O-O                  1 | * K C   * ",
  1506.         "                              -----------",
  1507.         "            > e1-c1        ... a b c d e "
  1508.     }, [11] = {
  1509.         "Other commands:",
  1510.         "",
  1511.         "exit: will leave the current game",
  1512.         "reset: starts a fresh game (local only)",
  1513.         "draw: offer your opponent a draw (network only)"
  1514.     }, [12] = {
  1515.         "Monitor Display:",
  1516.         "",
  1517.         "For network play, hook a computer up to a 6x6",
  1518.         "monitor and run monitorchess.lua. You can add",
  1519.         "the monitor just before starting, for a bigscreen",
  1520.         "display!"
  1521.     }, [13] = {
  1522.         "Acknowledgements:",
  1523.         "",
  1524.         "Written by Nitrogen Fingers",
  1525.         "Art: Moeser(1995), Alefith (1995) and NN(1998)",
  1526.         "Rednet Support: Wolvan"
  1527.     }
  1528. }
  1529. --The board, for tutorials
  1530. --[[
  1531.         "",
  1532.         "                           7 |   *   *   ",
  1533.         "                           6 | *   *   * ",
  1534.         "                           5 |   *   *   ",
  1535.         "                           4 | *   *   * ",
  1536.         "                              -----------",
  1537.         "            > e2-e4        ... c d e f g "
  1538. ]]--
  1539.  
  1540. --The currently active interface
  1541. currentInterface = interfaces["main"]
  1542.  
  1543. --The core GUI logic- this runs the main menu and has a default method for passing
  1544. --through the interface. It also runs setup and draw methods of each interface.
  1545. function runMenu()
  1546.     --currentInterface = interfaces["main"]
  1547.     while playing do
  1548.         currentInterface.draw()
  1549.         if currentInterface.input then currentInterface.input()
  1550.         else
  1551.             local id,key = os.pullEvent("key")
  1552.             if key == currentInterface.prevKeyCode and menuSel > 1 then
  1553.                 menuSel = menuSel - 1
  1554.             elseif key == currentInterface.nextKeyCode and
  1555.               menuSel < #currentInterface.options then
  1556.                 menuSel = menuSel + 1
  1557.             elseif key == 28 then
  1558.                 local setupname = currentInterface.options[menuSel]
  1559.                 currentInterface = interfaces[currentInterface.options[menuSel]]
  1560.                 menuSel = 1
  1561.                 if currentInterface.setup then
  1562.                     currentInterface.setup()
  1563.                 end
  1564.             end
  1565.         end
  1566.     end
  1567. end
  1568.  
  1569. gameOver = true
  1570. runMenu()
  1571.  
  1572. --gameOver = false
  1573. --playGame()
Add Comment
Please, Sign In to add comment