Estoy haciendo un simple juego de tres en raya donde las filas están representadas por tres matrices y las columnas son elementos de esas matrices. Para mi elección de computadora, uso dos funciones separadas para obtener la fila y la columna.

$first = ["-","-","-"]
$secound = ["-","-","-"]
$third = ["-","-","-"]
def get_row
    row = nil
    case rand(3)
    when 0
        row = $first
    when 1
        row = $secound
    else
        row = $third
    end
    row
end
def get_col
    col = nil
    case rand(3)
    when 0
        col = 0
    when 1
        col = 1
    else 
        col = 2
    end
    col
end

Luego uso una tercera función que sigue generando una nueva "suposición" hasta que encuentra un lugar vacío, en cuyo punto marca un 0.

def computer_guess
    temp = false
    try = get_row[get_col]
    while temp == false 
        if try == "-"
           get_row[get_col] = "O"
            temp = true 
        else
            try = get_row[get_col]
        end
    end
end

Mi problema es que no puedo devolver la suposición a la misma posición en la que verifico la validez. ¿Hay alguna forma de sincronizarlos o necesito un enfoque diferente?

1
Dante Davidson 19 feb. 2020 a las 08:18

3 respuestas

La mejor respuesta

El problema con su enfoque es que get_row[get_col] devuelve un elemento aleatorio cada vez que se llama, por lo que get_row[get_col] = "O" también establecerá un elemento aleatorio en { {X2}}. Inspeccionas un elemento y luego configuras otro.

Puede solucionar esto rápidamente modificando el elemento recuperado en el lugar:

if try == "-"
  try.replace("O")
  # ...

Pero semánticamente, no me gusta mucho esa solución. Pensando en un tablero de tres en raya, prefiero asignar un "O" al lugar libre que transformar el marcador de posición existente de "-" en "O".

¿Notó que su método get_row devuelve una matriz mientras que get_col devuelve un índice? Creo que esta mezcla de matrices e índices hace que su código sea un poco complicado.

Es mucho más fácil (en mi opinión) acceder a ambos, fila y columna a través de un índice.

Para hacerlo, podría colocar sus tres filas en otra matriz:

$board = [
  ['-', '-', '-'],
  ['-', '-', '-'],
  ['-', '-', '-']
]

Se puede acceder a la primera fila a través de $board[0] y a su primer elemento a través de $board[0][0]. Para establecer un elemento que usaría: $board[1][2] = 'O' (esto establece el elemento más a la derecha de la fila del medio en "O"). Por supuesto, también puede usar variables, p. $board[row][col].

Con esta matriz bidimensional, su computer_guess podría reescribirse usando solo dos índices aleatorios: (get_row y get_col ya no son necesarios)

def computer_guess
  loop do
    row = rand(3)                # random row index
    col = rand(3)                # random column index
    if $board[row][col] == '-'   # if corresponding spot is "-"
      $board[row][col] = 'O'     #    set that spot to "O"
      break                      #    and break out of the loop
    end
  end
end

Sin embargo, tenga en cuenta que adivinar "a ciegas" los puntos hasta que encuentre uno libre podría no ser el mejor enfoque.

En su lugar, podría generar una lista de espacios "gratuitos". Esto se puede hacer generando primero una matriz de todas las coordenadas 1 y luego select -ing esos pares de filas / columnas cuyo lugar es "-":

def free_spots
  coordinates = [0, 1, 2].product([0, 1, 2])
  coordinates.select { |row, col| $board[row][col] == '-' }
end

Ahora solo tiene que elegir un par aleatorio (a través de { {X0}}) y establezca el lugar correspondiente en "O":

def computer_guess
  row, col = free_spots.sample
  $board[row][col] = 'O'
end

1 {{X0} } devuelve el Producto cartesiano de las matrices proporcionadas. Es una forma fácil de obtener todos los pares:

[0, 1, 2].product([0, 1, 2])
#=> [[0, 0], [0, 1], [0, 2],
#    [1, 0], [1, 1], [1, 2],
#    [2, 0], [2, 1], [2, 2]]
1
Stefan 21 feb. 2020 a las 06:06

Aquí hay otro enfoque. Este código imita la computadora del juego contra sí mismo. Puede reemplazar fácilmente el movimiento de una computadora con la entrada del usuario.

ROWS = 3
COLUMNS = 3
MAX_TURNS = ROWS * COLUMNS

def random_cell
  { row: rand(ROWS), column: rand(COLUMNS) }
end

def empty_random_cell(board)
  while true
    cell = random_cell
    return cell if board_value(board, cell).nil?
  end
end

def board_value(board, cell)
  board[cell[:row]][cell[:column]]
end

def turn(board, cell, value)
  row = cell[:row]
  column = cell[:column]
  board[row][column] = value
end

def print_board(board)
  ROWS.times do |row|
    COLUMNS.times do |column|
      value = board[row][column]
      print value.nil? ? '_' : value
      print ' '
    end
    puts
  end
end

board = Array.new(ROWS) { Array.new(COLUMNS) }
print_board(board)
turns_counter = 0
while true
  cell = empty_random_cell(board)
  turn(board, cell, 'X')
  turns_counter += 1
  break if turns_counter == MAX_TURNS
  cell = empty_random_cell(board)
  turn(board, cell, '0')
  turns_counter += 1
  break if turns_counter == MAX_TURNS
end

print_board(board)
1
user3309314 19 feb. 2020 a las 07:02

Cuando solo hay un lugar disponible, puede tomar tiempo adivinarlo.
Por lo tanto, podría ser mejor cotejar los puntos disponibles y obtener un valor aleatorio a partir de ahí:

def computer_guess
  free_spots=[]
  free_spots.concat($first.each_with_index.map{|x,i|x=='-' ? ['$first',i] : nil}.compact)
  free_spots.concat($secound.each_with_index.map{|x,i|x=='-' ? ['$secound',i] : nil}.compact)
  free_spots.concat($third.each_with_index.map{|x,i|x=='-' ? ['$third',i] : nil}.compact)
  try=free_spots.sample
  eval"#{try[0]}[#{try[1]}]='O'" unless try.nil?
end
1
Fernand 19 feb. 2020 a las 09:35