Clases del programa para enfrentar jugadores

El programa que define el centro de control, y que se suministra junto con las clases anteriores, está diseñado para enfrentar a dos jugadores, pero usa ciertas clases que se usarán en el centro de control final: una versión más completa para jugar una liga.

Clase Tablero

class Tablero {
  public:
   Tablero() throw(std::bad_alloc);
  ~Tablero();
   void Iniciar() throw(std::bad_alloc);
   contenido LeerCelda(Coordenada) const;
   contenido ModificarCelda(Coordenada, contenido);
   bool ColocarBarco(int, Coordenada, int, direccion) throw(std::bad_alloc);
   bool Colision();
   void Mostrar();
   bool ComprobarBarco(Coordenada);
   
  private:
   contenido celda[cte::ancho][cte::alto];
   Barco **barco; // Array dinámico de punteros de barcos
};

Esta clase almacena y manipula todos los datos relativos a una partida y a un jugador.

Los datos que se almacenan son un array de celdas, con el contenido del tablero del jugador, donde se guardan los barcos y el estado de cada celda. Puesto que estos datos son inaccesibles para los jugadores, se almacena el estado real actual de cada jugador: posición de los barcos, coordenadas de los disparos, celdas con agua y tocados.

El otro dato es un array dinámico de objetos de la clase Barco, cada uno de los objetos contendrá los datos de uno de los barcos del jugador. Estos objetos permiten a un objeto de esta clase averiguar si un barco ha sido hundido o tocado.

Entre las funciones tenemos el constructor y destructor.

La función Iniciar limpia el array celda, y destruye y crea un nuevo array dinámico de Barcos, que inicialmente contendrá sólo punteros nulos.

LeerCelda devuelve el contenido de la celda cuya coordenada se pasa como parámetro.

ModificarCelda modifica el contenido de la celda cuya coordenada se pasa como parámetro, con el valor del segundo parámetro, y devuelve el valor previo de esa celda.

ColocarBarco crea un objeto de la clase Barco, que se añade al array dinámico de barcos, en la posición del primer parámetro. El resto de los parámetros indican la posición, tamaño y dirección del barco.

Colision verifica si los barcos del jugador entran en colisión. Esta función será invocada una vez se tengan los datos de todos los barcos.

Mostrar muestra el tablero en pantalla.

ComprobarBarco actualiza la información del barco tocado, siempre que sea necesario. Es decir, si la coordenada recibida como parámetro pertenece a un barco, y no ha sido tocada previamente. Devuelve true si ha sido hundido y false si no es un barco o si sólo ha sido tocado.

Clase Torneo

class Torneo {
  public:
   Torneo(Jugador *j1, Jugador *j2);
   int Iniciar() throw(std::bad_alloc); 
   int Partida(int);
   void Resultado();
   int Ganadas() const;
  private:
   Jugador *jugador[2];
   Tablero tablero[2];
   int ganadas[2];
};

Contiene la información de un torneo que enfrenta a dos jugadores, un número determinado de partidas, alternandose en el comienzo.

Entre los datos que contiene hay un array de dos punteros a objetos derivados de la clase base abstracta "Jugador", que se reciben como parámetros en el constructor.

También contiene un array de dos objetos Tablero, para almacenar datos durante la partida.

Un tercer array de enteros almacena el número de partidas ganadas por cada jugador.

El interfaz se compone de tres funciones y el constructor.

El constructor, recibe dos punteros correspondientes a cada uno de los jugadores, que serán de una clase derivada de la clase virtual Jugador. También se encarga de inicializar el array jugador, asignándole los parámetros recibidos y el array ganadas, con cero.

Iniciar inicia una partida, para lo cual inicia los tableros, llama a la función NuevaPartida de cada uno de los jugadores y les pide los datos de los barcos, actualiza el tablero, y comprueba si la colocación de los barcos es legal.

El valor de retorno indica si alguno o ambos jugadores ha cometido una infracción al colocar los barcos.

Partida juega una partida completa. El parámetro indica cual de los jugadores empieza a jugar. El valor de retorno indica cual de los jugadores gana.

Una partida puede terminar bien porque uno de los jugadores haya hundido todos los barcos del contrincante, o bien porque haya cometido un error: coordenada fuera del tablero o disparo en una coordenada previamente tocada.

El bucle principal se repite hasta que se termine la partida por uno de esos motivos, y consiste en:

  • Pedir la coordenada al jugador activo, mediante una llamada a la función PedirCoordenada.
  • Leer en el tablero del jugador pasivo el contenido de esa coordenada, mediante la función LeerCelda del tablero del jugador pasivo.
  • Informar al jugador pasivo de la coordenada en que disparó el activo, mediante la función Informar del jugador pasivo.
  • En función del contenido:
    • Si es "tocado": error, no se puede disparar sobre un tocado.
    • Si es "novalido": error, coordenada fuera del tablero.
    • Si es "buque": se comprueba el barco, mediante una llamada a ComprobarBarco del tablero correspondiente al jugador pasivo. Se actualiza el tablero del jugador pasivo. Se informa al jugador activo del resultado (tocado o hundido), mediante la función Responder. Si se han hundido todos los barcos, se da la partida por finalizada.
    • Si es "agua" o "libre": se actualiza el tablero del jugador pasivo, y se informa al jugador activo del resultado (agua).
  • Si no ha habido error, se cambia de turno.

Resultado muestra el resultado de partidas ganadas por cada jugador.

Ganadas devuelve el número de partidas ganadas por el jugador que más partidas lleve ganadas hasta el momento.

Función main

La función main inicializa la semilla del generador de números aleatorios, crea un torneo con los dos jugadores correspondientes, y los enfrenta un número de veces, hasta que uno de ellos llegue al valor determinado por la constante cte::nPartidas.

Al final, muestra el número de partidas ganadas por cada jugador.

Es posible enfrentar a un jugador consigo mismo, creando un torneo con dos objetos Jugador de la misma clase:

Torneo torneo(new Jugador1, new Jugador1);