This is a read-only snapshot of the ComputerCraft forums, taken in April 2020.
Klausar's profile picture

Problem with Connect 4 game

Started by Klausar, 25 June 2012 - 02:57 PM
Klausar #1
Posted 25 June 2012 - 04:57 PM
So I use this code for Connect 4:


--[[
				  CONNECT-4
				  By: Negeator
]]--
--[[
  Declare Variables
--]]
--Whose turn it is
local turn
--Cursor position
local cursorPos
--Message if piece is placed in the wrong place
local errorMessage
--Whether the game is playing
local gamePlaying
--Monitor Side being used
local monSide = "none"
--The monitor
local monitor
--Monitor width and height
local monWidth, monHeight
--Make a 7x6 Grid for the board
local grid =
{
  { " "," "," "," "," "," "," " },
  { " "," "," "," "," "," "," " },
  { " "," "," "," "," "," "," " },
  { " "," "," "," "," "," "," " },
  { " "," "," "," "," "," "," " },
  { " "," "," "," "," "," "," " },
}
local menuOptions =
{
  "Local Game", "Help", "Quit"
}
--[[
  Functions
--]]
--Main Function
function main()
  cursorPos = 1
  while true do
		menuDraw()
menuInput()
  end
end
--Events for the main menu (mainly input)
function menuInput()
  event, p1, p2 = os.pullEvent()
  if event == "key" then
   --Up
		if p1 == 200 then
   cursorPos = cursorPos - 1
   if cursorPos < 1 then
		 cursorPos = 3
   end

--Down
elseif p1 == 208 then
   cursorPos = cursorPos + 1
   if cursorPos > 3 then
		 cursorPos = 1
   end

--Enter
elseif p1 == 28 then
   if cursorPos == 1 then
		 game()
   elseif cursorPos == 2 then
		 help()
   elseif cursorPos == 3 then
		 clearScreen()
  error()
   end

end
  end
end
--Draws the main menu
function menuDraw()
  clearScreen()
  drawAt(1,1,"Connect-4")
  drawAt(1,2,"------------------")
  for i = 1, 3 do
		drawAt(4,i + 2,menuOptions[i])
  end
  drawAt(1,cursorPos + 2,"[*]")
end
function help()
  clearScreen()
  drawAt(1,1,"Connect-4 - Help:")
  drawAt(1,2,"------------------")
  drawAt(1,3,"Players take turn placing their pieces")
  drawAt(1,4,"in collumns.  The piece falls until it hits")
  drawAt(1,5,"the bottom or another piece.  The first player")
  drawAt(1,6,"to get 4 in a row in any direction wins!")
  drawAt(1,7,"Use arrow keys to select the row.")
  drawAt(1,8,"Press Enter to place a piece.")
  waitAtEnd()
end
--Play the game
function game()
  --Reset some variables
  gamePlaying = true
  turn = 0
  cursorPos = 1
  errorMessage = ""
  resetBoard()
  startMonitor()
  while gamePlaying == true do
		gameDraw()
		gameEvent()
checkForWinner()
  end
  waitAtEnd()
  cursorPos = 1
end
function waitAtEnd()
  drawAt(1,18,"Press Enter to Exit.")
  while true do
		event, key = os.pullEvent()
if event == "key" then
   if key == 28 then
		 return
   end
end
  end
end
--Draw the game
function gameDraw()
  clearScreen()
  drawBoard()
  --Draw the cursor
  drawAt((cursorPos * 3) + 11,1," | ")
  drawAt((cursorPos * 3) + 11,2," V ")
  if turn == 0 then
		drawAt(1,15,"Turn: Player 1")
  else
		drawAt(1,15,"Turn: Player 2")
  end
  drawAt(1,17,errorMessage)
  if monSide ~= "none" then
		drawMonitor()
  end
end
--Manages events for the game
function gameEvent()
  event, p1, p2 = os.pullEvent()
  if event == "key" then
		--Left
		if p1 == 203 then
   cursorPos = cursorPos - 1
   if cursorPos < 1 then
		 cursorPos = 7
   end

--Right
elseif p1 == 205 then
   cursorPos = cursorPos + 1
   if cursorPos > 7 then
		 cursorPos = 1
   end

--Backspace
elseif p1 == 14 then
   gamePlaying = false
   drawAt(1,17,"Game Terminated.")
--Enter
elseif p1 == 28 then
		if place(cursorPos) == true then
		  errorMessage = ""
		else
		  errorMessage = "Piece does not fit."
		end
end
  end
end
--Draw the board
function drawBoard()
  for x = 1, 7 do
		for y = 1, 6 do
   drawAt((x * 3) + 11,y * 2 + 1,"("..grid[y][x]..")")
end
  end
end
--Place a game piece.  Returns a boolean based on whether a piece was successfully placed.
function place(x)
  local y = 6
  while y >= 1 do
		if grid[y][x] == " " then
   if turn == 0 then
		 grid[y][x] = "0"
				turn = 1
   else
		 grid[y][x] = "o"
  turn = 0
   end

   return true
end
y = y - 1
  end
  sleep(.2)
  return false
end
--Check for a winner
function checkForWinner()
  local pivotX, pivotY
  for x = 1, 7 do
		for y = 1, 6 do
   pivotX = x
   pivotY = y
   if checkAtPoint(x,y,"0") == true then
		 gameDraw()
		 drawAt(1,17,"Player 1 Wins!")
  if monSide ~= "none" then
		drawAtMonitor(2,monHeight - 1, "Player 1 Wins!")
  end
  gamePlaying = false
   elseif checkAtPoint(x,y,"o") == true then
		 gameDraw()
  if monSide ~= "none" then
		  drawAt(1,17,"Player 2 Wins!")
  end
  drawAtMonitor(2,monHeight - 1, "Player 2 Wins!")
  gamePlaying = false
   end

end
  end
end
--Checks for any connect 4's at a position.  Returns true or false based on if it finds a connect 4.
function checkAtPoint(x,y,symbol)
  local checkX = x
  local checkY = y
  for dir = 0, 7 do
		x = checkX
y = checkY
		for i = 1, 4 do
  if x < 1 or x > 7 or y < 1 or y > 6 then
		 i = 4
		 elseif grid[y][x] == symbol then
		   if i < 4 then
		  x , y = addDir(x,y,dir)
		else
				--We found 4 in a row!
				return true
		end
  else
		i = 4
  end
		end
  end
  return false
end
--returns a modifier to the x and y value given a direction.  This is used to find the next point given a direction.
function addDir(x,y,direction)
  if direction == 0 then
		return x + 0,y + -1
  elseif direction == 1 then
		return x + 1,y + -1
  elseif direction == 2 then
		return x + 1,y + 0
  elseif direction == 3 then
		return x + 1,y + -1
  elseif direction == 4 then
		return x + 0,y + -1
  elseif direction == 5 then
		return x + -1,y + -1
  elseif direction == 6 then
		return x + -1,y + -1
  elseif direction == 7 then
		return -x + 1,y + -1
  end
end
--Reset the board
function resetBoard()
  for x = 1, 7 do
		for y = 1, 6 do
		grid[y][x] = " "
end
  end
end
--Draw the monitor
function drawMonitor()
  monWidth, monHeight = monitor.getSize()
  gridWidth = 21 --This is the width of the grid
  gridHeight = 11 --This is the height of the grid
  xAdd = (monWidth/2) - (gridWidth/2) - 3
  yAdd = (monHeight/2) - (gridHeight/2) - 2
  clearMonitor()
  for x = 1, 7 do
		for y = 1, 6 do
		  drawAtMonitor( xAdd + (3 * x), yAdd + (y * 2), "("..grid[y][x]..")")
end
  end
  if turn == 0 then
   drawAtMonitor(2,monHeight - 1, "Turn: Player 1")
  else
		drawAtMonitor(2,monHeight - 1, "Turn: Player 2")
  end
end
--If there is a monitor, set it up
function startMonitor()
  for i=1,#rs.getSides() do
		if peripheral.isPresent(rs.getSides()[i]) and peripheral.getType(rs.getSides()[i]) == "monitor" then
   monSide = rs.getSides()[i]
   monitor = peripheral.wrap( monSide )
   return
end
  end
  monSide = "none"
end
--Clear the terminal screen
function clearScreen()
  term.clear()
  term.setCursorPos(1,1)
end
--Draw text at a position on the terminal screen
function drawAt(x,y,text)
  term.setCursorPos(x,y)
  term.write(text)
end
--Basic Monitor Draw Functions
function clearMonitor()
  monitor.clear()
  monitor.setCursorPos(1,1)
end
function drawAtMonitor(x,y,text)
  monitor.setCursorPos(x,y)
  monitor.write(text)
end
--[[
  Run the Program!
--]]
main()

But I keep getting this error when Player 1 wins:

:240: attempt to perform arithmetic __sub on nil and number

How can I fix it?
Lyqyd #2
Posted 25 June 2012 - 07:01 PM
I don't have any easy way to determine line numbers on my phone, but I would suspect that you may have monHeight as nil there.

Also, variables that are declared should usually be set to some sane value at time of declaration. Additionally, please double-check your logic in the function which checks for and declares wins. I think you've got player two's monitor and non-monitor draws wrong.

More details would be good also. What happens when player two wins? What size monitor are you using? What is the value of monHeight in that function?
Klausar #3
Posted 25 June 2012 - 07:22 PM
When player two wins everything it is fine, it just says "Player two wins". It isn't my code so I can't tell you the coder stuff. I don't use a monitor and I don't want to, both player play on one computer. How does the code have to look to work?
Klausar #4
Posted 30 June 2012 - 09:53 AM
Can noone help me?
Lyqyd #5
Posted 30 June 2012 - 10:20 AM
Why don't you ask the person who wrote the code? I'm much more interested in helping people fix their own code and learn something than I am in fixing something for someone that a third party wrote. I imagine others here feel the same way.
Klausar #6
Posted 30 June 2012 - 02:20 PM
I did but I think he is inactive. I already tried to fix the code for 1 hour, but I'm not this experienced.