Минимаксная теория, включая альфа-бета-обрезку для кода R - PullRequest
1 голос
/ 24 мая 2019

Нужна помощь в разработке минимаксного алгоритма сокращения альфа-бета-версии в R. В настоящее время я реализовал минимаксный алгоритм, но его можно использовать только для платы 3х3. Платы 4x4 не работают -> в течение длительного времени

Я скопировал код с платы 3х3, но я понимаю, что не могу предоставить глубину. Поэтому я предполагаю, что это работает для всех примеров доски 4х4. Что мне нужно изменить для реализации альфа-бета-отсечения в разделе минимаксного кода. Поскольку я довольно новичок в этой области, я пытаюсь изменить существующий код, чтобы понять, что делает каждая часть.

# draw the board for tic tac toe
draw_board <- function(board) {
  xo <- c("X", " ", "O") # symbols
  par(mar = rep(0, 4))
  plot.new()
  plot.window(xlim = c(0, 40), ylim = c(0, 40))
  abline(h = c(10, 20, 30), col = "darkgrey", lwd = 4)
  abline(v = c(10, 20, 30), col = "darkgrey", lwd = 4)
  pieces <- xo[board + 2]
  text(rep(c(5, 15, 25, 35), 4), c(rep(35, 4), rep(25, 4), rep(15, 4), rep(5, 4)), pieces, cex = 6)
  # identify location of any three in a row
  square <- t(matrix(board, nrow = 4))
  hor <- abs(rowSums(square))
  if(any(hor == 4))
    hor <- (5 - which(hor == 4)) * 10 - 5
  else
    hor <- 0
  ver <- abs(colSums(square))
  if(any(ver == 4))
    ver <- which(ver == 4) * 10 - 5
  else
    ver <- 0
  diag1 <- sum(diag(square))
  diag2 <- sum(diag(t(apply(square, 2, rev))))
  # draw winning lines
  if(hor > 0) lines(c(0, 40), rep(hor, 2), lwd = 10, col = "red")
  if(ver > 0) lines(rep(ver, 2), c(0, 40), lwd = 10, col = "red")
  if(abs(diag1) == 4) lines(c(2, 38), c(38, 2), lwd = 10, col = "red")
  if(abs(diag2) == 4) lines(c(2, 38), c(2, 38), lwd = 10, col = "red")
}



# Human player enters a move
move_human <- function(game) {
  text(4, 0, "Click on screen to move", col = "grey", cex=.7)
  empty <- which(game == 0)
  move <- 0
  while (!move %in% empty) {
    coords <- locator(n = 1) # add lines
    coords$x <- floor(abs(coords$x) / 10) + 1
    coords$y <- floor(abs(coords$y) / 10) + 1
    move <- coords$x + 4 * (4 - coords$y) # 4 is the number of rows/columns --> needs to be a square
  }
  return (move)
}



# Evaluate winner function
eval_winner <- function(game_1, player) {
  game <- matrix(game_1, nrow = 3, byrow = T)
  hor <- rowSums(game)
  ver <- colSums(game)
  diag <- c(sum(diag(game)), sum(diag(apply(game, 1, rev))))
  if (-4 %in% c(hor, ver, diag))
    return(-10)
  if (4 %in% c(hor, ver, diag))
    return(10)
  else
    return(0)
}



# Minimax AI function
minimax <- function(game_1, player) {
  free <- which(game_1 == 0)
  if(length(free) == 1) {
    game_1[free] <- player
    return(list(move = free, U = eval_winner(game_1, player)))
  }
  poss.results <- rep(0, 16)
  for(i in free) {
    game <- game_1
    game[i] <- player
    poss.results[i] <- eval_winner(game, player)
  }
  mm <- ifelse(player == -1, "which.min", "which.max")
  if(any(poss.results == (player * 10))) {
    move <- do.call(mm, list(poss.results))
    return(list(move = move, U = poss.results[move]))
  }
  for(i in free) {
    game <- game_1
    game[i] <- player
    poss.results[i] <- minimax(game, -player)$U
  }
  random <- runif(16, 0, 0.1)
  poss.results[-free] <- 100 * -player
  poss.results <- poss.results + (player * random)
  move <- do.call(mm, list(poss.results))
  return(list(move = move, U = poss.results[move]))
}



# Main game engine human versus randomly choosing computer!
tic_tac_toe <- function(player1 = "human", player2 = "computer") {
  game <- rep(0, 16) # Empty board
  winner <- FALSE # Define winner
  player <- 1 # First player
  #players <- c(player1, player2)
  players <- c("human", "computer")
  draw_board(game)
  while (0 %in% game & winner == 0) { # Keep playing until win or full board
    if (players[(player + 3) %% 3] == "human") # Human player
      move <- move_human(game)
    else { # Computer player
      move <- minimax(game, player)
      move <- move$move
    }
    game[move] <- player # Change board
    draw_board(game)
    winner <- max(eval_winner(game, 1), abs(eval_winner(game, -1))) == 6 # Winner, winner, chicken dinner?
    player <- -player # Change player
  }
  if (winner == 1)
    print("Human has won")
  else if (winner == 2)
    print("Computer has won")
  else
    print("Play ended in a draw")
}

1 Ответ

0 голосов
/ 24 мая 2019

Повторю сказанное TheWhiteRabbit: вы должны взглянуть на https://stackoverflow.com/help/how-to-ask

Если вы будете более конкретны и включите свой код в будущем, мы можем быть более полезными, но я дам вам несколько общих советов на основе того, что вы предоставили.

Я предполагаю, что ваша проблема может быть одной из следующих:

  1. Вы не ограничиваете свою глубину. Вы пытаетесь найти весь путь до финала. Минимакс должен только искать достаточно оборотов вперед, чтобы ваше оборудование могло справиться с нагрузкой.
  2. Ваша функция подсчета очков слишком неэффективна. Функция оценки часто составляет большую часть вашего времени вычислений при поиске минимаксного кода. Если это неэффективно, вы заплатите за это.
  3. Точно так же ваш код, который генерирует список допустимых ходов, может быть неэффективным.
  4. Возможно, вы рассматриваете неверные ходы, в результате чего ваше дерево будет разветвляться намного больше, чем следовало.
  5. Вы недостаточно обобщаете свой код. Это не работает для 4x4, потому что вы жестко запрограммировали что-то, чтобы положиться на доску 3x3, не осознавая этого.
  6. Ваше удаление альфа-бета неверно. Вы ничего не обрезаете.

Исходя из моего опыта реализации вариантов MiniMax +, это, как правило, некоторые из точек отказа.

...