Search code examples
rubyloopsinputtic-tac-toe

Input in Ruby being the only one ran in loop


I've been trying to program a tic-tac-toe matchbox-based learning AI in Ruby, so I created the basic game first. But each time I re-implement the game the same error happens. I'm not sure if there's a specific part that's doing the thing so I will show the whole thing. Anyways, when all the values in the done array is true then the game should be over. (Don't worry about the winning and losing stuff I'm going to implement it later.) Instead, the program simply inputs the user, on and on and on and on. It doesn't print anything, even when I put print statements as tests it didn't even print those.

game = Array.new(9, " ")
done = Array.new(9, false)
gameplay = true
while gameplay
    input = gets.to_i
    if !done.include?(false)
        puts "game over!"
        gameplay = false
        break
    end
    
    if input < 0 || input > 8
        puts "Put a number from 0 to 8!"
        next
    end
    if(!done[input])
        game[input] = "o"
        done[input] = true
    else
        puts "That spot is filled!"
        next
    end
    while true
        cmove = rand 9
        if done[cmove] == true
            next
        else
            game[cmove] = "x"
            done[cmove] = true
            puts "The computer chose #{cmove}."
            break
        end
    end
    puts "#{game[0]}|#{game[1]}|#{game[2]}"
    puts "#{game[3]}|#{game[4]}|#{game[5]}"
    puts "#{game[6]}|#{game[7]}|#{game[8]}"
end

I expect the program to say "game over", caught by the first if statement.

**What I tried: **

  • taking a break and looking at the code again
  • putting puts statements to see where the error issues.
  • using ChatGPT (it was the one to add !done.include?(false))
  • remaking the program

Solution

  • You are checking if the game is done before you make your final move.

    Lets walk through what happens on the last move.

    game = Array.new(9, " ")
    done = Array.new(9, false)
    gameplay = true
    while gameplay
      # done is 8/9 true, 1/9 false
      input = gets.to_i
      if !done.include?(false) # done still has 1 false in it, this is skipped.
        puts "game over!"
        gameplay = false
        break
      end
    
      if input < 0 || input > 8
        puts "Put a number from 0 to 8!"
        next
      end
      if(!done[input]) # You chose a valid move.
        game[input] = "o"
        done[input] = true # done is updated, now it's 100% full of true
      else
        puts "That spot is filled!"
        next
      end
      while true
        cmove = rand 9
        if done[cmove] == true # Since done is full, computer will always reach this case
          next # and repeat. It will loop here forever.
        else
          game[cmove] = "x"
          done[cmove] = true
          puts "The computer chose #{cmove}."
          break
        end
      end
      puts "#{game[0]}|#{game[1]}|#{game[2]}"
      puts "#{game[3]}|#{game[4]}|#{game[5]}"
      puts "#{game[6]}|#{game[7]}|#{game[8]}"
    end
    

    Add the check for game completion after you make your move.

    game = Array.new(9, " ")
    done = Array.new(9, false)
    gameplay = true
    while gameplay
      input = gets.to_i
    
      if input < 0 || input > 8
        puts "Put a number from 0 to 8!"
        next
      end
      if(!done[input])
        game[input] = "o"
        done[input] = true
      else
        puts "That spot is filled!"
        next
      end
      if !done.include?(false)
        puts "game over!"
        gameplay = false
        break
      end
      while true
        cmove = rand 9
        if done[cmove] == true
          next
        else
          game[cmove] = "x"
          done[cmove] = true
          puts "The computer chose #{cmove}."
          break
        end
      end
      puts "#{game[0]}|#{game[1]}|#{game[2]}"
      puts "#{game[3]}|#{game[4]}|#{game[5]}"
      puts "#{game[6]}|#{game[7]}|#{game[8]}"
    end