[ Foro de Pascal ]

Juegos de tres en raya y de 4 en raya

26-Feb-2012 00:57
Nacho Cabanes (+32)
14 Respuestas

Como se estaba hablando de esto en otro hilo, abro uno específico para hablar del juego de las 3 en raya y, después, del de las 4 en raya.

Para el de las 3 en raya, se juega en un tablero de 3x3, así que se puede usar un array de 2 dimensiones para representarlo.

El pseudocódigo podría ser algo como

Repetir:
- Dibujar el tablero
- Preguntar movimiento al jugador 1
- Dibujar la casilla del jugador 1 (o todo el tablero)
- Si no ha terminado la partida:
 + Preguntar movimiento al jugador 2
 + Dibujar la casilla del jugador 2 (o todo el tablero)
 + Comprobar si ha terminado la partida
Hasta 3 en raya o empate (tablero lleno)


04-Mar-2012 19:31
Nacho Cabanes (+32)

Un ejemplo de cómo se puede desarrollar el juego de las 3 en raya, convirtiendo el pseudocódigo anterior en funciones y procedimientos para que el cuerpo del programa no sea excesivamente largo:

 
(* Tres en raya basico en consola, por Nacho*)
 
program TresEnRaya1;
 
const
    (* Simbolos del tablero: blanco, jug.1, jug.2*)
    simbolo: array [0..2] of char  = (' ', 'O', 'X');
 
 
var
    tablero: array[1..3, 1..3] of integer; (* Tablero de juego*)
    terminado: boolean;
 
 
procedure DibujarTablero;
var
    fila, columna: integer;
begin
    WriteLn;
    WriteLn('-------------');
    for fila := 1 to 3 do
    begin
        Write('|');
        for columna := 1 to 3 do
            Write(' '+simbolo[tablero[fila,columna]]+' |');
        WriteLn;
        WriteLn('-------------');
    end
end;
 
 
(* ----- Pregunta donde mover y lo anota en el tablero ----- *)
procedure PreguntarPosicion( jugador: integer );  (* 1 := Jug.1, 2= Jug.2*)
var 
    fila, columna: integer;
begin   
    repeat
        WriteLn;
 
        (* Pido fila*)
        repeat
            Write('En que fila (1 a 3) ');
            ReadLn(fila);
        until fila in [1..3];
 
        (* Pido columna*)
        repeat
            Write('En que columna (1 a 3) ');
            ReadLn(columna);
        until columna in [1..3];
 
        if (tablero[fila,columna] <> 0) then
            WriteLn('Casilla ocupada!');
 
    until (tablero[fila,columna] = 0);
 
    (* Si todo es correcto, se la asigno*)
    tablero[fila,columna] := jugador;
end;
 
 
(* ----- Devuelve "true" si hay tres en raya ----- *)
function ComprobarGanador: boolean;
var
    hay3enRaya: boolean;
    fila, columna: integer;
begin
    hay3enRaya := false;
 
    (* Si en alguna fila todas las casillas son iguales y no vac?¡as*)
    for fila := 1 to 3 do
        if ((tablero[fila, 1] = tablero[fila, 2]) 
                and (tablero[fila, 1] = tablero[fila, 3])
                and (tablero[fila, 1] <> 0))  then
            hay3enRaya := true;
 
    (* Lo mismo para las columnas*)
    for columna := 1 to 3 do
        if ((tablero[1,columna] = tablero[2,columna])
                and (tablero[1,columna] = tablero[3,columna])
                and (tablero[1,columna] <> 0))  then
            hay3enRaya := true;
 
    (* Y finalmente miro las dos diagonales*)
    if ((tablero[1, 1] = tablero[2, 2])
            and (tablero[1, 1] = tablero[3, 3])
            and (tablero[1, 1] <> 0))  then
        hay3enRaya := true;
    if ((tablero[1, 3] = tablero[2, 2])  
            and (tablero[1, 3] = tablero[3, 1])
            and (tablero[1, 3] <> 0))  then
        hay3enRaya := true;
 
    ComprobarGanador := hay3enRaya;
end;
 
 
(* ----- Devuelve "true" si hay empate ----- *)
function ComprobarEmpate: boolean;
var
    algunHueco: boolean;
    fila, columna: integer;
begin
    (* Si no quedan huecos donde mover, es empate*)
    algunHueco := false;
 
    for fila := 1 to 3 do
        for columna := 1 to 3 do
            if(tablero[fila,columna] = 0) then
                algunHueco := true;        
 
    ComprobarEmpate := not algunHueco;
end;
 
 
    (* ----- Cuerpo del programa ----- *)
 
 
begin
 
    begin
        terminado := false;
 
        (* Dibujar el tablero inicial*)
        DibujarTablero;
        repeat            
            (* Pedir al jugador 1*)
            PreguntarPosicion( 1 );
            (* Dibujar la casilla del jugador 1*)
            DibujarTablero;
            (* Comprobar si ha terminado la partida*)
            terminado := ComprobarGanador;
            if terminado then
                WriteLn('Gana jugador 1')
            else
                begin
                    terminado := ComprobarEmpate;
                    if terminado then
                        WriteLn('Empate!')
                    else
                    begin
                        (* Pedir al jugador 2*)
                        PreguntarPosicion( 2 );
                        (* Dibujar la casilla del jugador 2*)
                        DibujarTablero;
                        (* Comprobar si ha terminado la partida*)
                        terminado := ComprobarGanador;
                        if terminado then
                            WriteLn('Gana jugador 2');                
                    end
            end
        (* Repetir hasta 3 en raya o empate (tablero lleno)*)
        until terminado;
    end
 
end.
 




05-Mar-2012 02:28
Luis Torres (+12)

Yo lo hice así:

 
program tresEnRaya;
uses CRT;
var
 matriz: array[1..3,1..3] of char;
 i,cont: byte;
 
 
procedure inicializarMatriz;
begin
  matriz[1,1]:='A';
  matriz[1,2]:='B';
  matriz[1,3]:='C';
  matriz[2,1]:='D';
  matriz[2,2]:='E';
  matriz[2,3]:='F';
  matriz[3,1]:='G';
  matriz[3,2]:='H';
  matriz[3,3]:='J';
end;
 
procedure mostrarCuadricula;
begin
gotoxy(31,7); writeln('     ³   ³       ');
gotoxy(31,8); writeln('     ³   ³       ');
gotoxy(31,9); writeln(' ÄÄÄÄÅÄÄÄÅÄÄÄÄ   ');
gotoxy(31,10);writeln('     ³   ³       ');
gotoxy(31,11);writeln('     ³   ³       ');
gotoxy(31,12);writeln(' ÄÄÄÄÅÄÄÄÅÄÄÄÄ   ');
gotoxy(31,13);writeln('     ³   ³       ');
gotoxy(31,14);writeln('     ³   ³       ');
end;
 
procedure ubicacion(x: byte; y: byte);
 
begin
  if x=1 then
   begin
      case y of
        1: gotoxy(34,8);
        2: gotoxy(34,11);
        3: gotoxy(34,14);
       end;
   end;
  if x=2 then
   begin
      case y of
        1: gotoxy(38,8);
        2: gotoxy(38,11);
        3: gotoxy(38,14);
       end;
   end;
  if x=3 then
   begin
      case y of
        1: gotoxy(42,8);
        2: gotoxy(42,11);
        3: gotoxy(42,14);
       end;
   end;
end;
 
procedure mostrarJugadores;
begin
  gotoxy(20,18);writeln('JUGADOR 1: ');
  gotoxy(20,19);writeln('columna: ');
  gotoxy(20,20);writeln('fila: ');
  gotoxy(48,18);writeln('JUGADOR 2: ');
  gotoxy(48,19);writeln('columna: ');
  gotoxy(48,20);writeln('fila: ');
end;
 
procedure pedirDatos;
var
 X,Y: byte;
begin
 if cont mod 2 = 1 then
  begin
    gotoxy(29,19); readln(X);
    gotoxy(26,20); readln(Y);
    matriz[X,Y]:= 'O';
    ubicacion(X,Y);
    writeln('O');
    inc(cont);
  end
 else
  begin
    gotoxy(57,19); readln(X);
    gotoxy(54,20); readln(Y);
    matriz[X,Y]:='X';
    ubicacion(X,Y);
    writeln('X');
    inc(cont);
  end
end;
 
function noTresEnRaya: boolean;
begin
 noTresEnRaya:= true;
 if (matriz[1,1]=matriz[1,2]) and (matriz[1,2]=matriz[1,3]) then
  begin
    noTresEnRaya:= false;
    if matriz[1,1]='O' then 
     begin
       gotoxy(50,11);
       writeln('Gano el Jugador 1!')
     end
    else 
     begin
       gotoxy(50,11);
       writeln('Gano el Jugador 2!');
     end
  end;
 if (matriz[2,1]=matriz[2,2]) and (matriz[2,2]=matriz[2,3]) then
  begin
    noTresEnRaya:= false;
    if matriz[2,1]='O' then 
     begin
       gotoxy(50,11);
       writeln('Gano el Jugador 1!')
     end
    else 
     begin
       gotoxy(50,11);
       writeln('Gano el Jugador 2!');
     end
  end;
 if (matriz[3,1]=matriz[3,2]) and (matriz[3,2]=matriz[3,3]) then
  begin
    noTresEnRaya:= false;
    if matriz[3,1]='O' then 
     begin
       gotoxy(50,11);
       writeln('Gano el Jugador 1!')
     end
    else 
     begin
       gotoxy(50,11);
       writeln('Gano el Jugador 2!');
     end
  end;
 
 if (matriz[1,1]=matriz[2,1]) and (matriz[2,1]=matriz[3,1]) then
  begin
    noTresEnRaya:= false;
    if matriz[1,1]='O' then
     begin
       gotoxy(50,11); 
       writeln('Gano el Jugador 1!')
     end
    else
     begin
       gotoxy(50,11); 
       writeln('Gano el Jugador 2!');
     end
  end;
 if (matriz[1,2]=matriz[2,2]) and (matriz[2,2]=matriz[3,2]) then
  begin
    noTresEnRaya:= false;
    if matriz[1,2]='O' then 
     begin
       gotoxy(50,11);
       writeln('Gano el Jugador 1!')
     end
    else 
     begin
       gotoxy(50,11);
       writeln('Gano el Jugador 2!');
     end
  end;
 if (matriz[1,3]=matriz[2,3]) and (matriz[2,3]=matriz[3,3]) then
  begin
    noTresEnRaya:= false;
    if matriz[1,3]='O' then 
     begin
       gotoxy(50,11);
       writeln('Gano el Jugador 1!')
     end
    else 
     begin
       gotoxy(50,11);
       writeln('Gano el Jugador 2!');
     end
  end;
 
 if (matriz[1,1]=matriz[2,2]) and (matriz[2,2]=matriz[3,3]) then
  begin
    noTresEnRaya:= false;
    if matriz[1,1]='O' then
     begin
       gotoxy(50,11); 
       writeln('Gano el Jugador 1!')
     end
    else 
     begin
       gotoxy(50,11);
       writeln('Gano el Jugador 2!');
     end
  end; 
 if (matriz[3,1]=matriz[2,2]) and (matriz[2,2]=matriz[1,3]) then
  begin
    noTresEnRaya:= false;
    if matriz[3,1]='O' then 
     begin
       gotoxy(50,11);
       writeln('Gano el Jugador 1!')
     end
    else
     begin
       gotoxy(50,11); 
       writeln('Gano el Jugador 2!');
     end
  end;  
 
end;
 
Begin
 ClrScr;
 cont:= 1;
 inicializarMatriz;
 gotoxy(20,3);writeln('* BIENVENIDO AL JUEGO LAS TRES EN RAYA *');
 mostrarCuadricula;
 mostrarJugadores;
 while noTresEnRaya and (cont<=9) do
  pedirDatos;
 readln;
End.
 


También lo dejo como adjunto.
Saludos.


05-Mar-2012 02:29
Luis Torres (+12)

Ahora me gustaría que nos presentara el algoritmo del "4 en Raya". Saludos.


05-Mar-2012 16:07
oscar gomez

Cordial saludo profesor nacho y compañeros.
Profesor es que no se si como una modesta sugerencia podrias modificar el programa del tres en raya para que por cada accion no se genere un nuevo tablero, sino que las jugadas se visualicen en uno solo y que modificaciones se deben hacer si se juega contra el pc.
mil gracias


07-Mar-2012 01:23
Luis Torres (+12)

Ya entiendo lo que me decías, el profesor sí validó las entradas. Lo acabo de correr y lo constaté. Lo malo es que muestra el cuadro nuevamente en diferente posición después de pedir una nueva entrada. Saludos.


07-Mar-2012 23:36
Nacho Cabanes (+32)

Lo de que muestre el tablero en diferente posición es para que funcione (casi) con cualquier compilador, aunque no tenga la unidad "crt".

Si preferís que siempre se vea sólo el tablero en su estado actual, basta poner "uses crt;" al principio del programa y "clrscr;" antes de dibujar el tablero.

Lo de jugar contra el PC es más trabajoso, y quería que fuera un fuente razonablemente breve. Aun así, os doy pistas por si alguien quiere intentarlo:

- Se podría escoger entre tres niveles de dificultad: fácil, medio, difícil

- El fácil es (casi) trivial de programar: se mueve en cualquier casilla al azar, siempre y cuando esté libre.

- El medio podría mirar si en alguna casilla hace tres en raya; en caso contrario mira si en alguna bloquea tres en raya inminentes del contrario; en caso contrario, mueve al azar.

- El difícil es bastante más complejo (y más trabajoso de programar): supone elegir el tablero que lleva a una secuencia más favorable, usando MiniMax: se estudian todos los posibles tableros que se pueden generar a partir de la posición actual, tomando los que mejor resultado dan para "nosotros" (el ordenador, que piensa, por eso lo de "max") y/o peor resultado para el contrario (por eso lo de "min"). Así, el ordenador siempre toma "la mejor decisión posible" (en juegos sencillos, como éste, en los que sí se pueden llegar a probar todas las combinaciones posibles, mientras que puede no ser factible en juegos como el ajedrez, por la enorme cantidad de memoria que consume).



08-Mar-2012 10:02
oscar gomez

SIN MAS PALABRAS QUE DECIRTE PROFESOR NACHO CABANES EXCELENTES!!! IDEAS LAS QUE NOS DAS PARA JUGAR CONTRA EL ORDENADOR Y DE IGUAL MANERA GRACIAS POR LA EXPLICACION QUE ME DAS RESPECTO A MOSTRAR UNA SOLA VEZ EL TABLERO PUES NO HABIA CAIDO EN CUENTA LO REFERENTE A LA VISUALIZACION EN DISTINTOS COMPILADORES.
MIL GRACIAS PROFESOR.


25-May-2012 10:20
oscar gomez

cordial saludo profesor nacho cabanes y compañeros.

profesor podrias orientarnos en una forma o algoritmo de poder ir iniciando con el programa del 4 en raya, mil gracias por tu generosa ayuda.


06-Jul-2012 21:03
oscar gomez

Hola profesor nacho cabanes.
profesor nos olvidaste en tu orientacion para poder realizar el juego del 4 en raya, ojala nos des tu valiosa ayuda que siempre esperamos con mucho agradecimiento.


08-Jul-2012 10:13
Nacho Cabanes (+32)

Es cierto. Para las 4 en raya, normalmente se juega en un tablero de 7 (ancho) x 6 (alto), así que se puede tambiénusar un array de 2 dimensiones para representarlo.

El pseudocódigo sería idéntico (o casi, según el nivel de detalles) al de las 3 en raya, con la diferencia de que el apartado de "comprobar si ha terminado la partida" es más trabajoso de realizar:

Repetir:
- Dibujar el tablero
- Preguntar movimiento al jugador 1
- Dibujar la casilla del jugador 1 (o todo el tablero)
- Si no ha terminado la partida:
 + Preguntar movimiento al jugador 2
 + Dibujar la casilla del jugador 2 (o todo el tablero)
 + Comprobar si ha terminado la partida
Hasta 4 en raya o empate (tablero lleno)


10-Jul-2012 19:02
Luis Torres (+12)

Esperaba mucho esta respueta, prof. Nacho Cabanes. La verdad es que el pseudocódigo que acaba de colocar es más o menos como yo lo había pensado; pero la parte más complicada, tal como lo menciona, es comprobar que alguno de los jugadores ha colocado cuatro fichas en seguidas o cuando el tablero esté lleno. ¿Podría indicarme un pseudocódigo para lograr esta comprobación?, ¿cómo sería más o menos esto?, deme alguna orientación, por favor. Muchas Gracias por su valiosa y oportuna ayuda.
Saludos.


17-Jul-2012 08:11
Nacho Cabanes (+32)

Una forma simple, aunque algo larga y engorrosa, de hacer un primer acercamiento a la comprobación de si hay 4 en raya sería:

Para cada columna
 - Si casilla1 = casilla2 = casilla3 = casilla4
   o casilla2 = casilla3 = casilla4 = casilla5
   o casilla3 = casilla4 = casilla5 = casilla6
   y casilla4 no esta vacia
 - Entonces ganador = casilla4

Para cada fila
 [Similar]

Para cada diagonal ascendente
 [Similar]

Para cada diagonal descendente
 [Similar]

Se puede simplificar usando "while" y un contador en vez de "if" tan largos, pero yo te recomendaría que primero lo implementaras así, que es fácil aunque suponga "copiar y pegar" varias veces con cuidado, y que lo mejores después (si quieres), cuando ya todo funcione.

Lo de saber si el tablero está lleno es tan sencillo como recorrer todo el tablero contar la cantidad de casillas ocupadas. Si son 42 (6x7) y antes no se ha encontrado un ganador, la partida queda en empate. Una alternativa es no contar sino usar un boolean "quedanCasillasEnBlanco", que sea "true" si encuentras alguna casilla no ocupada.


20-Jul-2012 00:58
Luis Torres (+12)

Ok. Gracias por la respuesta. Trataré de implementarla tal como lo indica. Si tengo problemas vuelvo a llamarlo.
Tengo otra pregunta: ¿cómo debe verse en pantalla el juego de 4 en raya?, la parte gráfica es muy limitada en Pascal. ¿Cuál sería la mejor forma de presentarlo?.
Saludos.


22-Jul-2012 18:21
Nacho Cabanes (+32)

Lo ideal es tratar de que el programa sea modular: un procedimiento "dibujarTablero", un procedimiento "pedirColumna", y el resto serían los que se encargan de la lógica del juego. Así, cuando crees una versión en modo gráfico, reharías el "pedirColumna" y el "dibujarTablero", pero el resto del programa no tendría cambios (al menos en principio).






(No se puede continuar esta discusión porque tiene más de dos meses de antigüedad. Si tienes dudas parecidas, abre un nuevo hilo.)