Volver al inicio

Biblioteca Battleship en Python: Clases Field y Ship

El artículo desglosa la creación de una biblioteca de lógica de juego Battleship en Python. Describe las clases Field y Ship, métodos de validación de coordenadas, colocación de barcos y errores típicos. Proporciona ejemplos de código y recomendaciones de refactorización para una arquitectura óptima.

Creando una Biblioteca Battleship: Field y Ship en Python
Advertisement 728x90

Desarrollando una Biblioteca de Lógica para el Juego de Batalla Naval en Python: Arquitectura y Errores Comunes

La biblioteca implementa la lógica del clásico juego de Batalla Naval con un enfoque en algoritmos matemáticamente óptimos. Las clases principales son Campo para representar el tablero de juego y Barco para gestionar los barcos. El campo se almacena como una matriz de 10x10 usando listas de listas, donde los símbolos denotan estados: espacio para una celda vacía, '1' para una parte de barco intacta, '.' para un fallo, 'X' para una celda destruida.

La clase Campo maneja la creación del tablero, validación de coordenadas, colocación de barcos y procesamiento de disparos. Las coordenadas se ingresan en el formato 'a1', donde las letras A-J corresponden a filas y los números 1-10 a columnas. Las reglas son fijas: 1 barco de cuatro celdas, 2 barcos de tres celdas, 3 barcos de dos celdas, 4 barcos de una celda; los barcos no deben tocarse entre sí, ni siquiera en las esquinas.

Implementando la Clase Campo

La inicialización crea una cuadrícula vacía:

Google AdInline article slot
class Campo:
    def __init__(self):
        altura = 10
        ancho = 10
        self.cuadricula = [[' ' for i in range(ancho)] for i in range(altura)]

El método mostrar() imprime el campo en la consola con coordenadas. La primera versión contenía un error: el método line.insert(0, letter) mutaba la cuadrícula original al agregar letras en llamadas repetidas. La solución: imprimir la letra por separado sin alterar la estructura.

def mostrar(self):
    print('  1 2 3 4 5 6 7 8 9 10')
    letras = 'ABCDEFGHIJ'
    contador_letras = 0
    for linea in self.cuadricula:
        print(letras[contador_letras], *linea)
        contador_letras += 1

La validación de coordenadas se extrae en el método privado _validar_coordenada(). Verifica la longitud de la cadena (2-3 caracteres), presencia de una letra en A-J y un número en 1-10. El método encontrar_coordenada() determina el estado de la celda: libre, golpeada, destruida, no_dañada, ya_golpeada.

Los diccionarios para conversión de coordenadas se almacenan como atributos self.filas y self.columnas:

Google AdInline article slot
  • filas: {'a': 0, 'b': 1, ..., 'j': 9}
  • columnas: {'1': 0, '2': 1, ..., '10': 9}

La Clase Barco y la Colocación de Barcos

La clase Barco almacena parámetros en un diccionario:

class Barco:
    def __init__(self):
        self.parametros = {
            'coordenadas vivas': [],
            'coordenadas golpeadas': [],
            'vivo': True
        }
        self.campo = None
    def establecer_campo(self, campo):
        self.campo = campo

El método agregar_barco(barco, linea_coordenadas, longitud) en Campo coloca un barco basado en una cadena como 'a1-a2-a3'. Primero, validación de línea _validar_linea_barco(): analizar en coordenadas, verificar linealidad (horizontal/vertical) y coincidencia de longitud. Luego, para cada coordenada, llamar barco.establecer_coordenada_en_barco(coordenada), estableciendo '1' en la cuadrícula.

def agregar_barco(self, barco, linea_coordenadas, longitud):   
    barco.establecer_campo(self)
    if not self._validar_linea_barco(linea_coordenadas):
        return False
    coordenadas = linea_coordenadas.split('-')   
    if longitud != len(coordenadas):
        return False
    for coordenada in coordenadas:
        resultado = barco.establecer_coordenada_en_barco(coordenada)
        if resultado:
            filas = self.filas[coordenada[0]]
            columnas = self.columnas[coordenada[1:]]
            self.cuadricula[filas][columnas] = '1'
    return True

La relación Campo-Barco es bidireccional: Campo llama barco.establecer_campo(self), y Barco usa self.campo para validación. Esto viola el principio de encapsulación de capas base pero simplifica la API.

Google AdInline article slot

Perspectivas de Refactorización

El proyecto reveló errores clave para principiantes:

  • Sobrecarga de Métodos: encontrar_coordenada() combinaba validación, búsqueda y salida—se dividió en _validar_coordenada() y obtener_estado_celda().
  • Mutación de Datos: Evitar insert() en mostrar(); trabajar con copias.
  • Diccionarios Codificados: Extraer en constantes de clase o usar ord() para conversiones.
  • Valores de Retorno: Estandarizar: True/False para éxito, cadenas para errores.

Para un juego óptimo, integrar algoritmos de búsqueda probabilística: al acertar, escanear celdas adyacentes; al destruir, excluir cubiertas de probabilidades.

Conclusiones Clave

  • Campo como matriz de listas con símbolos para estados; validación de coordenadas vía diccionarios self.filas/self.columnas.
  • Barco almacena coordenadas vivas/golpeadas; enlace bidireccional con Campo vía establecer_campo().
  • Colocación vía linea_coordenadas ('a1-a2'); verificar linealidad y zonas de amortiguación.
  • Evitar mutar cuadrícula en mostrar(); extraer verificaciones comunes en métodos privados.
  • Para algoritmos avanzados: almacenar un mapa de probabilidad de disparos separado de la cuadrícula.

— Editorial Team

Advertisement 728x90

Leer después