Juego de cartas
POO
Objetivo
Implementar un juego de cartas de solitario.
Se implementará una versión del Klondike.
Se juega con una baraja de 52 cartas de las cuales 28 se colocan en la mesa
en 7 pilas. La primara con 1 carta, la segunda con 2, etc. La primera carta de
cada pila esta boca arriba y las demás boca abajo.
El objetivo es pasar una por una las cartas a 4 pilas más, una para cada palo
de las cartas.
Las cartas restantes se ponen boca abajo y forman la pila de reserva. Las
cartas se pasan una a una a una pila más, la pila de descarte. De ahí pueden
pasar a las lilas restantes si corresponde en el orden.
Objetivo
Las pilas de salida aceptan una carta si es del mismo palo y es
una as, o si le sigue a la del tope.
Las pilas de mesa aceptan cartas si es la carta anterior y tiene
color diferente.
Pilas de palo
descarte
Pilas de mesa
salir
empezar
baraja
Responsabilidades de las clases
La definición de una clase debe proporcionar al usuario toda la
información necesaria para manipular correctamente un ejemplar
de la clase y nada más.
Un método debe recibir toda la información necesaria para llevar a
cabo sus responsabilidades dadas y nada más.
Clase Carta
La clase Carta se utiliza para mantener el valor de una carta y
regresar el valor (rango) y el palo (figura).
No tiene la capacidad para dibujar nada en la pantalla.
Carta
palo – devolver el palo
rango – devolver el rango
color – devolver el color
Clase VistaDeCarta
Se separan los detalles de visualización en esta clase.
Es responsable de dibujar, borrar, devolver true si la carta está boca
arriba, voltear una carta, probar si se eligió la carta y mover a otra
posición.
VistaDeCarta
Borrar, dibujar – borrar y dibujar la
VistaDeCarta –valores de datos
imagen de una carta
LaCarta – (tipo Carte) el valor de la carta
BocaArriba, volver – probar y voltear
Arriba – (booleano) estado de bocaarriba o boca abajo
la carta
ubicx, ubicy – ubicación en superficie de juego
Incluye(int, int) – probar si un punto
MoverA(int, int) – mover carta a nueva posición
está dentro de los límites
MoverA(int, int) – mover carta a
nueva posición
Implementación de Carta
#ifndef cartah
#define cartah
// incluye este archivo solo una vez
const int AnchoCarta = 73;
const int AlturaCarta = 97;
class Carta{
public:
Carta(int sv, int cv){p = sv; r = cv;};
int palo(){return p;};
int color(){return (palo() % 2);};
int rango(){return r;};
private:
int p;
int r;
};
#endif
Implementación de VistaDeCarta
#ifndef cardvh
#define cradvh
#include "carta.h"
class VistaDeCarta{
public:
VistaDeCarta(Carta *);
VistaDeCarta(int s, int c);
Carta * carta();
void Dibujar();
void Borrar();
int BocaArriba();
void Volver();
int Incluye(int, int);
int x();
int y();
void MoverA(int, int);
private:
Carta * LaCarta;
int Arriba;
int ubicx;
int ubicy;
};
Implementación de VistaDeCarta
(cont.) Constructores
VistaDeCarta::VistaDeCarta(Carta *c){
LaCarta = c;
Arriba = 0;
ubicx = ubicy = 0;
}
VistaDeCarta::VistaDeCarta(int s, int c){
LaCarta = new Carta(s,c);
Arriba = 0;
ubicx = ubicy = 0;
}
Implementación de VistaDeCarta
(cont.)
inline Carta* VistaDeCarta::carta(){return LaCarta;}
inline int VistaDeCarta::BocaArriba(){return Arriba;}
inline void VistaDeCarta::Volver(){Arriba = !
Arriba;}
inline int VistaDeCarta::x(){return ubicx;}
inline int VistaDeCarta::y(){return ubicy;}
inline void VistaDeCarta::MoverA(int xs, int ys)
{ubicx = xs; ubicy = ys;}
#endif
void VistaDeCarta::Dibujar(){
Borrar();
if(FirstTime)
FirstTime = false;
if( Arriba){
putimage (x(),y(),figCartas[LaCarta->rango()+
13*LaCarta->palo()-1],0);}
else
putimage(x(),y(),figCartas[52],0);
}
void VistaDeCarta::Borrar(){
setfillstyle(SOLID_FILL,GREEN);
setbkcolor(GREEN);
setcolor(GREEN);
bar3d(x(),y(),x()+AnchoCarta+2,y()+
AlturaCarta+2,1,1);
}
int VistaDeCarta::Incluye(int a, int b){
return (a>=x()) && (a<=x()+AnchoCarta) &&
(b>=y()) && (b<=y()+AlturaCarta);
}
Clase LigaDeCarta
Las pilas se implementan usando otra clase que es hija de
VistaDeCarta y que es la lista de cada una de las cartas de cada
pila.
LigaDeCarta
PonerLiga(LigaDeCarta*) – agrega una carta a la lista.
siguiente() – regresa el apuntador a la siguiente carta.
Implementación de LigaDeCartas
class LigaDeCarta : public VistaDeCarta{
public:
LigaDeCarta(int s, int c);
LigaDeCarta(Carta * c);
LigaDeCarta * Siguiente();
void PonerLiga(LigaDeCarta * UnaCarta);
private:
LigaDeCarta * liga;
};
inline
{;}
inline
inline
inline
LigaDeCarta::LigaDeCarta(int s,int c):VistaDeCarta(s,c)
LigaDeCarta::LigaDeCarta(Carta *c):VistaDeCarta(c) {;}
LigaDeCarta * LigaDeCarta::Siguiente(){return liga;}
void LigaDeCarta::PonerLiga(LigaDeCarta *UnaCarta)
{liga = UnaCarta;}
La PilaDeCartas
Es la clase base a partir de la cual se definirá cada pila.
Contiene un miembro dato (tope) que señala al inicio de la pila.
PilaDeCarta
AgregarCarta(Carta*) – agrega una carta a la pila. Cambia
las coordenadas de la carta a las de la pila, pero no dibuja
nuevamente la pila.
PuedeToma(Carta*) – Ve si la pila puede tomar una carta,
por omisión devuelve no.
contiene(int, int) – ve si la carta contiene punto
PilaDeCarta – página 2
despliega() – mostrar la pila. Por omisión muestra la carta
superior.
Inicializa() – inicia pila
Escoge(int, int) – se apreto un botón en la posición. Por
omisión no hace nada
RemueveCarta – remueve la primera carta de la pila
Implementación de PilaDeCartas
Contiene métodos
class PilaDeCartas{
visrtuales
public:
PilaDeCartas();
PilaDeCartas(int, int);
void virtual AgregarCarta(LigaDeCarta *);
int virtual PuedeTomar(Carta *);
int Contiene(int, int);
void virtual Despliega();
void virtual Inicializa();
LigaDeCarta * RemueveCarta();
void virtual Escoge(int, int);
//private:
protected:
int x;
int y;
LigaDeCarta * tope;
};
inline PilaDeCartas::PilaDeCartas(int a,
int b){x = a; y = b; tope = nuloliga;}
void PilaDeCartas::AgregarCarta(LigaDeCarta *
UnaCarta){
if(UnaCarta != nuloliga){
UnaCarta->PonerLiga(tope);
tope=UnaCarta;
tope->MoverA(x,y);
}
}
int PilaDeCartas::PuedeTomar(Carta *
UnaCarta){
UnaCarta = UnaCarta;
return 0;
}
int PilaDeCartas::Contiene(int a,int b){
for(LigaDeCarta *p=tope;p!=nuloliga;p=p->Siguiente())
if(p->Incluye(a,b))return 1;
return (a>=x) && (a<=x+AnchoCarta) && (b>=y) &&
(b<=y+AlturaCarta);
}
void PilaDeCartas::Despliega(){
setfillstyle(LINE_FILL,BLUE);
if(tope == nuloliga){
setfillstyle(SOLID_FILL,YELLOW);
setcolor(BLUE);
bar3d(x,y,x+AnchoCarta+2,(y+AlturaCarta),1,1);
}else
tope->Dibujar();
}
void PilaDeCartas::Inicializa(){
tope = nuloliga;
}
LigaDeCarta * PilaDeCartas::RemueveCarta(){
LigaDeCarta * p;
if(tope == nuloliga)
return nuloliga;
p = tope;
tope = tope->Siguiente();
return p;
}
void PilaDeCartas::Escoge(int x, int y){
/* no hacer nada */ x = x; y = y;
}
Clase PilaDeReparto
Esta clase es hija de PilaDeCartas y define un método para
repartir las cartas a la pila de barajas.
PilaDePalos subclase de PilaDeCartas
RepartirA – genera una pila de cartas que introduce en la
pila de baraja.
Implementación de PilaDeReparto
class PilaDeReparto : public PilaDeCartas{
public:
PilaDeReparto();
void RepartirA(PilaDeCartas *);
};
inline
PilaDeReparto::PilaDeReparto():PilaDeCartas(
0, 0) {;}
void PilaDeReparto::RepartirA(PilaDeCartas * UnaPila){
LigaDeCarta *p , *q;
int max, limite, i;
// primero ve cuantas cartas tenemos
for(max=0,p=tope;p!=nuloliga;p = p->Siguiente()){
max++;
if(p->BocaArriba()) p->Volver();
}
// después sacarlas en forma aleatoria una por una
for(;max>0;max--){
limite = ((rand() >> 3) % max) + 1;
for(i=1, p=tope; i<=limite;){
while(p->BocaArriba()) p= p->Siguiente();
i += 1;
if(i <= limite) p = p->Siguiente();
}
q = new LigaDeCarta(p->carta());
UnaPila->AgregarCarta(q);
p->Volver();
}
}
Clase PilaDePalos
Esta clase es hija de PilaDeCartas y anula el método
PuedeTomar.
PilaDePalos subclase de PilaDeCartas
PuedeToma(Carta*) – devuelve verdadero si la pila está
vacía y la carta es un as, o si la carta es del mismo palo
que la pila y es la siguiente en la secuencia.
Implementación de PilaDePalos
class PilaDePalos : public PilaDeCartas{
public:
PilaDePalos(int a, int b);
int virtual PuedeTomar(Carta *);
};
inline PilaDePalos::PilaDePalos(int a, int
b):PilaDeCartas(a, b) {;}
int PilaDePalos::PuedeTomar(Carta * UnaCarta){
if(tope == nuloliga){ //pila vacía
if(UnaCarta->rango() == 1) return 1;
return 0;
}
if((tope->carta())->palo() != UnaCarta->palo())
return 0; //palo diferente
if(((tope->carta())->rango()+1)==UnaCarta->rango())
return 1;//carta que sigue
return 0;
}
Clase PilaDeMesa
Esta clase es hija de PilaDeCartas y anula los métodos PuedeTomar,
AgregarCarta, Despliega, Escoge, Inicializa
PilaDeMesa subclase de PilaDeCartas
PuedeToma(Carta*) – devuelve verdadero si la pila está
vacía y la carta es un rey, o si la carta es del color
contrario que la pila y es la anterior en la secuencia.
AgregarCarta(LigaDeCarta *) – agrega una carta a la pila
en la posición adecuada.
CopiarMonton(LigaDeCarta *, PilaDeCartas *) – agrega un
monton de cartas de otra pila de mesa.
PilaDeMesa subclase de PilaDeCartas
Despliega – despliega la pila
escoge– escoge una carta o un montón.
Inicializa – inicia todas las pilas de mesa
Implementación
class PilaDeMesa : public PilaDeCartas{
public:
PilaDeMesa(int c, int x, int y):
PilaDeCartas(x,y) {columna = c;}
void virtual AgregarCarta(LigaDeCarta *);
int virtual PuedeTomar(Carta *);
void CopiarMonton(LigaDeCarta *,
PilaDeCartas *);
void virtual Despliega();
void virtual Escoge(int, int);
void virtual Inicializa();
private:
int columna;
};
void PilaDeMesa::Inicializa()
{
int i;
//pone el n£mero correcto de cartas en la mesa
PilaDeCartas::Inicializa();
for(i=0; i<=columna; i++)
AgregarCarta((juego->baraja)->RemueveCarta());
// volver la ultima
if(tope != nuloliga){
tope->Volver();
}
}
void PilaDeMesa::AgregarCarta(LigaDeCarta * UnaCarta){
int tx, ty;
if(tope == nuloliga)
PilaDeCartas::AgregarCarta(UnaCarta);
else{
tx = tope->x();
ty = tope->y();
// calcular donde colocar la carta
if(tope->BocaArriba())
ty += round(AlturaCarta*0.3);// la baja un poco
PilaDeCartas::AgregarCarta(UnaCarta);
tope->MoverA(tx,ty);
}
}
int PilaDeMesa::PuedeTomar(Carta * UnaCarta){
if(tope == nuloliga){//puede tomar reyes en una
pila vacía
if(UnaCarta->rango()==13) return 1;
return 0;
}
// ver si está boca arriba
if(!tope->BocaArriba())
return 0;
// ver si son diferentes colores
if((tope->carta())->color()==UnaCarta->color())
return 0;
// ver si los números son legales
if(((tope->carta())->rango()-1)==UnaCarta->rango())
return 1;
return 0;
}
void PilaDeMesa::CopiarMonton(LigaDeCarta *
c, PilaDeCartas * UnaPila){
LigaDeCarta * d;
tope->Borrar();
d = RemueveCarta();
Despliega();
if(c != d) CopiarMonton(c, UnaPila);
UnaPila->AgregarCarta(d);
UnaPila->Despliega();
}
static void DespliegaPila(LigaDeCarta * p){
if(p->Siguiente())
DespliegaPila(p->Siguiente());
p->Borrar();
p->Dibujar();
}
void PilaDeMesa::Despliega(){
Carta * p;
// ninguna carta no se puede hacer nada mejor
if(tope == nuloliga)
PilaDeCartas::Despliega();
else
DespliegaPila(tope);
}
void PilaDeMesa::Escoge(int x, int y){
LigaDeCarta * c;
int i;
//no hay cartas, no hace nada
if(tope == nuloliga) return;
//si la carta de la cima no está boca arriba, volverla
if(! tope->BocaArriba()){
tope->Borrar();tope->Volver();tope->Dibujar();return;
}
//si no fue carta de arriba, ver si es posible moverla
if(tope->Incluye(x, y)){
//ver si es posible moverla a la pila de palos
if(juego->PaloPuedeAgregar(tope->carta())){
CopiarMonton(tope,juego->PaloAgregarPila(tope>carta()));
return;
}
//si no, ver si es posible moverla a una pila de mesa
// pero solo si no es parte de la pila
if((tope->Siguiente() == nuloliga) ||
!(((tope->Siguiente())->BocaArriba())))
if(juego->MesaPuedeAgregar(tope->carta())){
CopiarMonton(tope,juego->MesaAgregarPila(tope>carta()));
return;
}
}
//si no ver si es posible mover una pila
for(c=tope->Siguiente();c!=nuloliga;c=c->Siguiente())
if(c->BocaArriba()&&c->Incluye(x,y)){
if(juego->MesaPuedeAgregar(c->carta())){
CopiarMonton(c,juego->MesaAgregarPila(c->carta()));
}
return;
}
//si no, no hacer nada
}
clase PilaDeBaraja
PilaDeBaraja subclase de PilaDeCartas
AgregarCarta(LigaDeCarta *) – agrega una carta a la pila.
escoge– si esta vacía, agrega las cartas de la pila de
descarte, sino saca la carta del tope y la agrega a la pila
de descarte.
Inicializa – copia la pila de reparto en esta pila en orden
aleatorio
class PilaDeBaraja : public PilaDeCartas{
public:
PilaDeBaraja(int x,int
y):PilaDeCartas(x,y){;}
void virtual AgregarCarta(LigaDeCarta *);
void virtual Escoge(int, int);
void virtual Inicializa();
};
void PilaDeBaraja::Inicializa(){
PilaDeCartas::Inicializa();
NuevaBaraja->RepartirA(this);
}
void
PilaDeBaraja::AgregarCarta(LigaDeCarta *
c){
if(c->BocaArriba())
c->Volver();
PilaDeCartas::AgregarCarta(c);
}
void PilaDeBaraja::Escoge(int x, int y){
LigaDeCarta *c;
if(tope == nuloliga){
c = (juego->descarte)->RemueveCarta();
while (c != nuloliga){
AgregarCarta(c);
c=(juego->descarte)->RemueveCarta();
}
}else {
c = RemueveCarta();
if(c != nuloliga)
(juego->descarte)->AgregarCarta(c);
}
Despliega();
(juego->descarte)->Despliega();
}
clase PilaDeDescarte
PilaDeDescarte subclase de PilaDeCartas
AgregarCarta(LigaDeCarta *) – agrega una carta a la pila.
escoge–saca la carta del tope y la agrega a la pila de palos
o a alguna pile de mesa.
void PilaDeDescarte::AgregarCarta(LigaDeCarta *c)
{
if(!(c->BocaArriba()))
c->Volver();
PilaDeCartas::AgregarCarta(c);
}
void PilaDeDescarte::Escoge(int x, int y){
PilaDeCartas * UnaPila;
if(tope == nuloliga) return;
// ver si es posible moverla a una pila de palos
if(juego->PaloPuedeAgregar(tope->carta())){
UnaPila=juego->PaloAgregarPila(tope->carta());
UnaPila->AgregarCarta(RemueveCarta());
Despliega();
UnaPila->Despliega();
return;
}
if(juego->MesaPuedeAgregar(tope->carta())){
UnaPila=juego->MesaAgregarPila(tope->carta());
UnaPila->AgregarCarta(RemueveCarta());
Despliega();
UnaPila->Despliega();
return;
}
}
La clase Boton
Es la clase encargada de agregar botones de control a la
aplicación.
Boton
Dibuja – dibuja el botón
Presionado – verdadero si se presionó.
class Boton{
public:
Boton(int x, int y, int ancho, int alto,char *s);
void dibuja();
bool presionado(int x1, int y1);
private:
int x,y,w,h;
char cad[20];
};
void Boton::dibuja(){
int i;
setfillstyle(SOLID_FILL,LIGHTGRAY);
bar(x,y,x+w,y+h);
for(i=0;i<4;i++){
setcolor(WHITE);
line(x+i,y+i,x+w-i,y+i);
line(x+i,y+i,x+i,y+h-i);
setcolor(DARKGRAY);
line(x+i,y+h-i,x+w-i,y+h-i);
line(x+w-i,y+i,x+w-i,y+h-i);
}
setcolor(BLACK);
settextjustify(CENTER_TEXT,VCENTER_TEXT);
setbkcolor(LIGHTGRAY);
outtextxy(x+w/2,y+h/2,cad);
}
bool Boton::presionado(int x1, int y1){
return x1>=x&&x1<=x+w&&y1>=y&&y1<=y+h;
}
clase VentanaDeJuego
Contiene los métodos para el manejo del juego. Sus responsabilidades son
generar la baraja ordenada, repartirla en la pila de bajar desordenada, iniciar
todas las pilas y dibujar el tablero,
VentanaDeJuego
JuegoNuevo – inicia un juego.
BorraArea – borra la ventana de juego. PaloPuedeAgregar(Carta
*) – verdadero se una pila de palos puede agregar una carta.
MesaPuedeAgregar(Carta *) - verdadero se una pila de mesa
puede agregar una carta.
PaloPuedeAgregar(Carta *) - verdadero se una pila de palos
puede agregar una carta.
PaloAgregarPila(Carta *) – agrega una carta a una pila de palos.
MesaAgregarPila(Carta *) – agrega una carta a una pila de mesa.
Maneja - procesa los clic del mouse
VentanaDeJuego – valores de datos
TodasLasPilas[13] - todas las pilas
PilasDePalos[4] - las pila de palos
Mesa[7] - la mesa de juegos
botonSalir – botón de terminación
botonIniciar – botón de reinicio
class VentanaDeJuego{
public:
PilaDeCartas *descarte;
PilaDeCartas *baraja;
VentanaDeJuego();
void JuegoNuevo();
void BorraArea(int,int,int,int);
int PaloPuedeAgregar(Carta *);
PilaDeCartas * PaloAgregarPila(Carta *);
int MesaPuedeAgregar(Carta *);
PilaDeCartas * MesaAgregarPila(Carta *);
void Maneja();
protected:
PilaDeCartas * TodasLasPilas[13]; // todas las
pilas
PilaDeCartas * PilasDePalos[4];// la pila de palos
PilaDeCartas * Mesa[7];
// la mesa de juegos
Boton *botonSalir,*botonIniciar;
void virtual Redibuja();
};
Variables externas
extern PilaDeReparto * NuevaBaraja;
extern int round(float x);
extern bool mouse_clicked;
VentanaDeJuego::VentanaDeJuego(){
int i, j, altura;
//crea la baraja original (no barajada)
NuevaBaraja = new PilaDeReparto();
for(i=0; i<4; i++)
for(j=1; j<=13; j++)
NuevaBaraja->AgregarCarta(new LigaDeCarta(i, j));
//crea pilas de palos
altura = 20;//AltoTablero - round(1.5*AlturaCarta);
//crea las pilas de baraja y de descarte
TodasLasPilas[0] = baraja = new PilaDeBaraja(700,AlturaCarta);
TodasLasPilas[1] = descarte = new PilaDeDescarte(620,AlturaCarta);
//crea pila de palos
for(i=0; i<4; i++)
TodasLasPilas[i+2] = PilasDePalos[i] =
new PilaDePalos(30 + (round(1.4*AnchoCarta)*i),altura);
/*PilaDePalos*/
//crea cuadro
altura = AlturaCarta+4;
for(i=0; i<7; i++)
TodasLasPilas[i+6] = Mesa[i] =
new PilaDeMesa(i,10 + (round(1.2*AnchoCarta)*i),altura);
botonSalir = new Boton(50,500,60,40,"Salir");
botonIniciar = new Boton(150,500,60,40,"Iniciar");
}
void VentanaDeJuego::JuegoNuevo(){
int i;
// inicia todas las pilas
for(i=0; i<13; i++)
TodasLasPilas[i]->Inicializa();
//dibuja nuevamente
Redibuja();
}
void VentanaDeJuego::Redibuja(){
int i;
setcolor(WHITE);
setbkcolor(GREEN);
clearviewport();
for(i=0; i<13; i++)
TodasLasPilas[i]->Despliega();
botonSalir->dibuja();
botonIniciar->dibuja();
}
int VentanaDeJuego::PaloPuedeAgregar(Carta *
UnaCarta){
int i;
for(i=0; i<4; i++)
if(PilasDePalos[i]->PuedeTomar(UnaCarta))
return 1;
return 0;
}
PilaDeCartas *
VentanaDeJuego::PaloAgregarPila(Carta *
UnaCarta){
int i;
for(i=0; i<4; i++)
if(PilasDePalos[i]->PuedeTomar(UnaCarta))
return PilasDePalos[i];
// ojala nunca suceda
return NuevaBaraja;
}
int VentanaDeJuego::MesaPuedeAgregar(Carta *
UnaCarta){
int i;
for(i=0; i<7; i++)
if(Mesa[i]->PuedeTomar(UnaCarta)) return 1;
return 0;
}
PilaDeCartas * VentanaDeJuego::MesaAgregarPila(Carta
* UnaCarta){
int i;
for(i=0; i<7; i++)
if(Mesa[i]->PuedeTomar(UnaCarta))
return Mesa[i];
// ojala nunca suceda
return NuevaBaraja;
}
void VentanaDeJuego::Maneja(){
int i,X,Y;
bool Salir=false;
do{
while(!mouse_clicked){}
X = mousex();
Y = mousey();
mouse_clicked =false;
for(i = 0; i < 13; i++)
if(TodasLasPilas[i]->Contiene(X,Y)){
TodasLasPilas[i]->Escoge(X,Y);
}
Salir = botonSalir->presionado(X,Y);
if(botonIniciar->presionado(X,Y))
JuegoNuevo();
}while(!(Salir));
return;
}
Función main
Descargar

Juego de cartas