Home > Back-end >  How to go through "ERROR: argument is of length zero"
How to go through "ERROR: argument is of length zero"

Time:12-10

Forgive me if I speak gibberish. I've recently start studying R and has been working on making Tic-Tac-Toe project to improve my coding skill.

Currently, I'm trying to make function for player to occupy a empty spot while making sure they don't override already ooccupied spot.

However, from the if statement, I have been getting the error under the line.

"Error in if (player_mark != "X" & player_mark != "O") { : argument is of length zero"

Here is the whole code for Tic-Tac-Toe

# This is the board.
environment <- data.frame(c(1, 2, 3), c(4, 5, 6), c(7, 8, 9))
colnames(environment) <- c("[1]", "[2]", "[3]")
row.names(environment) <- c("[1]", "[2]", "[3]")

# This are the victory conditions
win.condition <- list(
  (environment[1, 1] & environment[1, 2] & environment[1, 3]) |
    (environment[2, 1] & environment[2, 2] & environment[2, 3]) |
    (environment[3, 1] & environment[3, 2] & environment[3, 3]) |
    (environment[1, 1] & environment[2, 2] & environment[3, 3]) |
    (environment[3, 1] & environment[2, 2] & environment[1, 3])
)

# This will evaluate if the victory condition is met
check_victor <- function() {
  winner <- NULL
  if (player_shape %in% win.condition) {
    winner <- player
    cat("You won!")
    break
  } else if (computer_shape %in% win.condition) {
    winner <- computer
    cat("You lost!")
    break
  } else {
    winner <- NULL
  }
}

# This is the player's movement
player_movement <- function() {
  # Acquiring where the player wants to move.
  player_select_row <- readline("Choose the row: ")
  player_select_col <- readline("choose the column: ")
  player_mark <- environment[substr(player_select_row, 1, 1), substr(player_select_col, 1, 1)]

  # Checking if the next spot is already marked by player or computer
  if (player_mark != "X" & player_mark != "O") {
    # If the spot isn't taken yet, replace the spot
    environment[player_select_row, player_select_col] <<- player_shape

    # Display the change and let computer make movement
    print(environment)
    check_victor()
    computer_movement()
  } else {
    cat("Illegal movement!")
    player_movement()
  }
}

# This is computer's movement
computer_movement <- function() {
  # This will used later to ensure the computer doesn't make multiple movement at once.
  computer_movement_count <- 0
  # Generate random number to find a spot where to make a movement.
  while (computer_movement_count == 0) {
    computer_row_mark <- sample(1:3, 1)
    computer_col_mark <- sample(1:3, 1)
    computer_mark <- c(computer_row_mark, computer_col_mark)
    # Check if the next mark for computer isn't already occupied yet.
    if (environment[computer_mark] != "X" & environment[computer_mark] != "O") {
      environment[computer_mark] <<- computer_shape
      computer_movement_count <- computer_movement_count   1
      print(environment)
      check_victor()
      player_movement()
    }
  }
}

# This will change the player's shape depending on who's going first.
firstorsecond <- function() {
  Answer <- readline("Would you like to go first or second? \nType 1 if you like to go first or type 2 if you prefer to go second.")
  if (substr(Answer, 1, 1) == "1") {
    player_shape <<- "X"
    computer_shape <<- "O"
    cat("You're going first")
    cat("\n")
    print(environment)
    player_movement()
  } else if (substr(Answer, 1, 1) == "2") {
    player_shape <<- "O"
    computer_shape <<- "X"
    cat("You're going second")
    cat("\n")
    print(environment)
    computer_movement()
  } else {
    NULL
    cat("Do it again")
    firstorsecond()
  }
}

# Start the game
if (interactive()) firstorsecond()

I searched the solution in online and found adding "isTRUE(x)" could be a solution to the problem.

Here is the change I made.

# This is the player's movement
player_movement <- function() {
  # Acquiring where the player wants to move.
  player_select_row <- readline("Choose the row: ")
  player_select_col <- readline("choose the column: ")
  player_mark <- environment[substr(player_select_row, 1, 1), substr(player_select_col, 1, 1)]

  # Checking if the next spot is already marked by player or computer
  if (is.integer(player_mark) && player_mark != "X" & player_mark != "O" && is.integer(player_mark)) {
    # If the spot isn't taken yet, replace the spot
    environment[player_select_row, player_select_col] <<- player_shape

    # Display the change and let computer make movement
    print(environment)
    check_victor()
    computer_movement()
  } else {
    cat("Illegal movement!")
    player_movement()
  }
}

Now the issue is, whatever the row number and column number I type in the console, the "player_movement" function will always take the input to the else statement.

Would you like to go first or second? 
Type 1 if you like to go first or type 2 if you prefer to go second.1
You're going first
    [1] [2] [3]
[1]   1   4   7
[2]   2   5   8
[3]   3   6   9
Choose the row: 1
choose the column: 3
Illegal movement!

CodePudding user response:

readline() is returning a string, and so in the first version you are trying to use strings to index your array rather than integers. The result of this is NULL hence the error about zero length argument.

In the second version the if condition is failing at is.integer() because is.integer(NULL) is FALSE.

CodePudding user response:

I'm pretty sure there is a better way to do it but I used "as.integer" to convert the substrings to integers to solve the issue.

# This is the player's movement
player_movement <- function() {
  # Acquiring where the player wants to move.
  player_select_row <- readline("Choose the row: ")
  player_select_row_int <- as.integer(substr(player_select_row, 1, 1))
  player_select_col <- readline("choose the column: ")
  player_select_col_int <- as.integer(substr(player_select_col, 1, 1))
  player_mark <- environment[player_select_row_int, player_select_col_int]

  # Checking if the next spot is already marked by player or computer
  if (player_mark != "X" & player_mark != "O") {
    # If the spot isn't taken yet, replace the spot
    environment[player_select_row_int, player_select_col_int] <<- player_shape

    # Display the change and let computer make movement
    print(environment)
    check_victor()
    computer_movement()
  } else {
    cat("Illegal movement!")
    player_movement()
  }
}
  • Related