Juego 4 en raya

Iniciado por alvarogt91, 6 Junio 2014, 09:00 AM

0 Miembros y 1 Visitante están viendo este tema.

alvarogt91

Hola a todos estoy haciendo el juego del 4 en raya y a la hora de sacar el ganador no me funciona bien porque creo que al estar sumando filas y columnas me estoy saliendo de la matriz de enteros. Estoy usando Qt designer  C++ para hacer la interfaz del juego. Si alguien puede ayudarme con el método Ganado(); para sacar las horizontales, verticales y diagonales le estaría muy agradecido. Adjunto el enunciado y el programa por partes ya que esta dividido en ficheros:

ENUNCIADO:
En este ejercicio vamos a implementar el conocido juego de las 4 en raya o conecta 4. El programa arrancará con un panel de 6x7 vacío, informando que es el turno de las piezas rojas. Cuando tire el primer jugador (pinchando con el ratón en alguno de los botones azules) se colocará la ficha en la columna correspondiente y dará el turno al segundo jugador (piezas amarillas).
En cualquier momento se podrá reiniciar la partida (segundo botón), salir, o mostrar el Acerca de (About) de la aplicación. El programa controlará que no se tira sobre una columna llena y también comprobará tras cada jugada si ha ganado alguno de los jugadores o han quedado empates (Figura 2). Cuando algún jugador gane o queden en tablas informaremos al usuario y la partida se reiniciará (borraremos el tablero y será el turno de las rojas de nuevo).

CÓDIGO:
<mainwindow.h>
-----------------------------------------------------------------------------------------------
#ifndef MAINWINDOW_H
#define MAINWINDOW_H

#include <QMainWindow>
#include <QPushButton>

#include<iostream>
using namespace std;

namespace Ui {
class MainWindow;
}

class MainWindow : public QMainWindow
{
    Q_OBJECT

public:
    explicit MainWindow(QWidget *parent = 0);
    ~MainWindow();

private slots:

    void on_actionSalir_triggered();

    void on_actionAcerca_de_triggered();

    void on_pushButton_7_clicked();

    void on_pushButton_9_clicked();

    void on_pushButton_11_clicked();

    void on_pushButton_13_clicked();

    void on_pushButton_15_clicked();

    void on_pushButton_17_clicked();

    void on_pushButton_19_clicked();

    void on_actionNuevo_Juego_triggered();

    void BotonPulsado(int columna);

    void Ganado(int fila,int columna,int ficha);

private:
    //declaracion de los atributos necesarios para nuestro codigo.
    Ui::MainWindow *ui;
    QPushButton *M[6][7];
    int V[7];
    int Mint[6][7];
    bool turno;
    bool ganadorojas;
    bool ganadoamar;
};

#endif // MAINWINDOW_H
----------------------------------------------------------------------------------------------
<main.cpp>
#include "mainwindow.h"
#include <QApplication>


int main(int argc, char *argv[])
{
    QApplication a(argc, argv);
    MainWindow w;
    w.show();

    return a.exec();
}
---------------------------------------------------------------------------------------------
<mainwindow.cpp>
#include "mainwindow.h"
#include "ui_mainwindow.h"

//librerias para las distinas opciones
#include <QMessageBox>
#include <QPushButton>
#include <QIcon>
#include <QPixmap>


//Constructor de la ventana principal
MainWindow::MainWindow(QWidget *parent) :
    QMainWindow(parent),
    ui(new Ui::MainWindow)
{
    //Inicializacion de la ventana.
    ui->setupUi(this);

    //Asignacion de los botones a las distintas posiciones de la matriz.
    M[0][0] = ui->pushButton_8;
    M[0][1] = ui->pushButton_10;
    M[0][2] = ui->pushButton_12;
    M[0][3] = ui->pushButton_14;
    M[0][4] = ui->pushButton_16;
    M[0][5] = ui->pushButton_18;
    M[0][6] = ui->pushButton_20;
    M[1][0] = ui->pushButton_21;
    M[1][1] = ui->pushButton_22;
    M[1][2] = ui->pushButton_23;
    M[1][3] = ui->pushButton_24;
    M[1][4] = ui->pushButton_25;
    M[1][5] = ui->pushButton_26;
    M[1][6] = ui->pushButton_27;
    M[2][0] = ui->pushButton_28;
    M[2][1] = ui->pushButton_29;
    M[2][2] = ui->pushButton_30;
    M[2][3] = ui->pushButton_31;
    M[2][4] = ui->pushButton_32;
    M[2][5] = ui->pushButton_33;
    M[2][6] = ui->pushButton_34;
    M[3][0] = ui->pushButton_35;
    M[3][1] = ui->pushButton_36;
    M[3][2] = ui->pushButton_37;
    M[3][3] = ui->pushButton_38;
    M[3][4] = ui->pushButton_39;
    M[3][5] = ui->pushButton_40;
    M[3][6] = ui->pushButton_41;
    M[4][0] = ui->pushButton_42;
    M[4][1] = ui->pushButton_43;
    M[4][2] = ui->pushButton_44;
    M[4][3] = ui->pushButton_45;
    M[4][4] = ui->pushButton_46;
    M[4][5] = ui->pushButton_47;
    M[4][6] = ui->pushButton_48;
    M[5][0] = ui->pushButton_49;
    M[5][1] = ui->pushButton_50;
    M[5][2] = ui->pushButton_51;
    M[5][3] = ui->pushButton_52;
    M[5][4] = ui->pushButton_53;
    M[5][5] = ui->pushButton_54;
    M[5][6] = ui->pushButton_55;

    for(int i=0;i<7;i++){
        V=0;
    }
    for(int j=0;j<6;j++){
        for(int k=0;k<7;k++){
            Mint[j][k]=0;
        }
    }
    turno=true;
    ganadorojas=false;
    ganadoamar=false;
}
//Destructor
MainWindow::~MainWindow()
{
    delete ui;
}
//funcion salir triggered
void MainWindow::on_actionSalir_triggered()
{
    close();
}
//funcion acerca de triggered
void MainWindow::on_actionAcerca_de_triggered()
{
    QMessageBox::information(this,"Acerca del Juego","Realizado por Alvaro Garrido Tafalla y Jorge Medina Carbonell","Aceptar");
}
//funcion reiniciar juego triggered
void MainWindow::on_actionNuevo_Juego_triggered()
{
    for(int i=0;i<6;i++){
        for(int j=0;j<7;j++){
            M[j]->setIcon(QIcon(":/Iconos/Material ejercicio 1/circle_grey.png"));
            Mint[j]=0;
        }
    }
    for(int i=0;i<7;i++){
        V=0;
    }
    turno=true;
    ganadorojas=false;
    ganadoamar=false;
    ui->label->setText("Turno de las rojas");
}
//Funciones clicked de cada boton del panel, que llaman a la funcion BotonPulsado
void MainWindow::on_pushButton_7_clicked()
{
    BotonPulsado(0);
}
void MainWindow::on_pushButton_9_clicked()
{
    BotonPulsado(1);
}
void MainWindow::on_pushButton_11_clicked()
{
    BotonPulsado(2);
}
void MainWindow::on_pushButton_13_clicked()
{
    BotonPulsado(3);
}
void MainWindow::on_pushButton_15_clicked()
{
    BotonPulsado(4);
}
void MainWindow::on_pushButton_17_clicked()
{
    BotonPulsado(5);
}
void MainWindow::on_pushButton_19_clicked()
{
    BotonPulsado(6);
}
//funcion BotonPulsado que permite cambir el icono de los botones.
void MainWindow::BotonPulsado(int columna){

    if(V[columna]<6){//comprueba que no se tira sobre una columna llena
        int pos=5-V[columna];
        V[columna]=V[columna]+1;
        if(turno==true){
            M[pos][columna]->setIcon(QIcon(":/Iconos/Material ejercicio 1/circle_red.png"));
            Mint[pos][columna]=1;
            turno=false;
            ui->label->setText("Turno de las amarillas");
            Ganado(pos,columna,1);
        }else{
            M[pos][columna]->setIcon(QIcon(":/Iconos/Material ejercicio 1/circle_yellow.png"));
            Mint[pos][columna]=2;
            turno=true;
            ui->label->setText("Turno de las rojas");
            Ganado(pos,columna,2);
        }
    }
}
//Ganado
void MainWindow::Ganado(int fila,int columna,int ficha){


    //horizontales
    int cont=1;
    if(Mint[fila][columna-1]==ficha || Mint[fila][columna+1]==ficha){
        cont++;
        if(Mint[fila][columna-2]==ficha || Mint[fila][columna+2]==ficha){
            cont++;
            if(Mint[fila][columna-3]==ficha || Mint[fila][columna+3]==ficha){
                cont++;
                if(ficha==1 && cont==4){
                    ganadorojas=true;
                }else{
                    ganadoamar=true;
                }
            }
        }
    }
    //verticales
    if(Mint[fila-1][columna]==ficha || Mint[fila+1][columna]==ficha){
        if(Mint[fila-2][columna]==ficha || Mint[fila+2][columna]==ficha){
            if(Mint[fila-3][columna]==ficha || Mint[fila+3][columna]==ficha){
                if(ficha==1){
                    ganadorojas=true;
                }else{
                    ganadoamar=true;
                }
            }
        }
    }
    if(ganadorojas==true ){
        QMessageBox::information(this,"Fin de juego","Ganan las Rojas","OK");
        on_actionNuevo_Juego_triggered();
    }
    if(ganadoamar==true){
        QMessageBox::information(this,"Fin de juego","Ganan las Amarillas","OK");
        on_actionNuevo_Juego_triggered();
    }
}
-----------------------------------------------------------------------------------------------






eferion

A la hora de poner código, usa las etiquetas GeSHi, por favor.

En el algoritmo para calcular si hay 4 fichas alineadas...

Código (cpp) [Seleccionar]

    if(Mint[fila][columna-1]==ficha || Mint[fila][columna+1]==ficha){
        cont++;
        if(Mint[fila][columna-2]==ficha || Mint[fila][columna+2]==ficha){
            cont++;
            if(Mint[fila][columna-3]==ficha || Mint[fila][columna+3]==ficha){
                cont++;
                if(ficha==1 && cont==4){
                    ganadorojas=true;
                }else{
                    ganadoamar=true;
                }
            }
        }
    }


... hay varios problemas:

* No compruebas si estás en el borde del tablero, por lo que, efectivamente, podrías salirte del mismo.

* ¿Qué sucede si "Mint[fila][columna-1] == ficha && Mint[fila][columna+2] == ficha && Mint[fila][columna-3] == ficha" ?? pues básicamente que te da el juego por ganado aunque realmente las fichas no están alineadas

* ¿Qué utilidad tiene ahí cont?? Ninguna, los ifs están anidados, luego es imposible llegar a if(ficha==1 && cont==4) y que cont sea distinto de 4... además... ¿y el else de ese if? ¿no necesita comprobar que "cont == 4" ? Mejor quitar directamente "cont", no crees?

* ¿Qué sucede si la ficha que acabas de poner hace un 4 en raya pero no pertenece a uno de los extremos? Pues básicamente que no va a reconocer la jugada como ganadora, tu algoritmo asume que la nueva ficha pertenece SIEMPRE a uno de los dos extremos de la secuencia.

Para el caso de búsquedas en horizontal, el código presenta problemas similares.

Además tampoco está implementado el caso de tener las 4 fichas en vertical.

Un saludo.

alvarogt91

Código (cpp) [Seleccionar]

En el caso de que gane 4 en vertical si esta implementado el que no esta es el de las diagonales. Y sabia que tenia la mayoría de errores que me has dicho pero estoy pidiendo una orientación de como podría ser por ejemplo comprobar si han ganado 4 en horizontal ya que no se por donde tirar. Como bien dices la matriz de enteros se me desborda y empezaría recorriendo la matriz de 6x7 para evitarlo.

eferion

Una forma sencilla pudiera ser tener un catálogo de funciones:

* Función para comprobar 4 en línea en diagonal hacia la derecha
* Función para comprobar 4 en línea en diagonal hacia la izquierda
* Función para comprobar 4 en línea en vertical
* Función para comprobar 4 en línea en horizontal

Cada una de estas funciones podría recibir únicamente la fila y columna desde la que empezar a comprobar:

Código (cpp) [Seleccionar]

bool Comprobar4EnLinea( int fila, int columna, int incFila, int incColumna )
{
  bool to_return = true;

  if ( fila > 0 && fila < MAXFILAS && columna >= 0 && columna < MAXCOLUMNAS )
  {
    int ficha = Mint[fila][columna];

    for ( int i = 0; i < 3; i++ )
    {
      fila += incFila;
      columna += incColumna;

      if ( fila >= 0 && fila < MAXFILAS && columna >= 0 && columna < MAXCOLUMNAS )
      {
        if ( Mint[fila][columna] != ficha )
        {
          to_return = false;
          break;
        }
      }
      else
        to_return = false;
    }
  }
  else
    to_return = false;

  return to_return;
}

bool ComprobarDiagonalDerecha( int fila, int columna )
{
  bool to_return = false;

  // Se prueban todas las combinaciones en las que esta involucrada la ficha recien puesta
  for ( int i = 0; i < 4; i++ )
  {
    if ( Comprobar4EnLinea( fila + i, columna + i, -1, -1 ) )
    {
      to_return = true;
      break;
    }
  }

  return to_return;
}


Con este catálogo el proceso se puede simplificar bastante:

Código (cpp) [Seleccionar]

void MainWindow::Ganado(int fila,int columna,int ficha)
{
  bool ganador = false;

  ganador |= ComprobarDiagonalDerecha( fila, columna );
  ganador |= ComprobarDiagonalIzquierda( fila, columna );
  ganador |= ComprobarVertical( fila, columna) ;
  ganador |= ComprobarHorizontal( fila, columna );

  if ( ganador )
  {
    if ( ficha == 1 )
      cout << "Ganan las amarillas" << endl;
    else
      cout << "Ganan las rojas" << endl;
  }
}


alvarogt91

#4

Muchas gracias me ha servido de bastante ayuda.
He hecho también la diagonal por la izquierda y el programa funciona de maravilla. Ya solo me queda las horizontales y verticales.
Un Saludo.