Fundamentos:Solucións:Bomber: Diferenzas entre revisións
Saltar á navegación
Saltar á procura
(Nova páxina: "Escribir un Xogo no que participan dous xogadores nun taboleiro de 8x8. En cada turno un xogador pode moverse ou poñer unha bomba, perdendo o xogador que non poda efectuar o seu ...") |
|||
(Non se amosan 3 revisións do historial feitas polo mesmo usuario.) | |||
Liña 7: | Liña 7: | ||
Ficheiro de construcción do programa. |
Ficheiro de construcción do programa. |
||
<source lang='text'> |
|||
Podes [http://web.iesrodeira.com/Descargas/Exercicios/Bomber/Makefile Descargar] o Makefile |
|||
<c> |
|||
FLAGS = `pkg-config --cflags --libs libglade-2.0` |
FLAGS = `pkg-config --cflags --libs libglade-2.0` |
||
FLAGSC = `pkg-config --cflags libglade-2.0` |
FLAGSC = `pkg-config --cflags libglade-2.0` |
||
Liña 14: | Liña 13: | ||
bomber: bomber.c |
bomber: bomber.c |
||
gcc bomber.c -o bomber $(FLAGS) -export-dynamic |
gcc bomber.c -o bomber $(FLAGS) -export-dynamic |
||
</ |
</source> |
||
==Aplicación GTK== |
==Aplicación GTK== |
||
Liña 31: | Liña 30: | ||
==== Pseudocódigo ==== |
==== Pseudocódigo ==== |
||
<c> |
|||
Cando se pulse unha tecla de movemento ou click no rato |
Cando se pulse unha tecla de movemento ou click no rato |
||
Segun a Xogada |
Segun a Xogada |
||
Liña 42: | Liña 41: | ||
Comprobar que o outro xogador non perdeu |
Comprobar que o outro xogador non perdeu |
||
Fin-Si |
Fin-Si |
||
</c> |
|||
==== Implementación en C ==== |
==== Implementación en C ==== |
||
===== [[Fundamentos:Solucións:Bomber:bomber.c|Ver/Descargar]]===== |
|||
=== bomber.c === |
|||
<source lang='C'> |
|||
/* Bomber |
|||
*/ |
|||
#include <stdio.h> |
|||
#include <gtk/gtk.h> |
|||
#include <gdk/gdkkeysyms.h> |
|||
#include <glade/glade.h> |
|||
#ifdef __WINDOWS__ |
|||
#define EXPORT __declspec (dllexport) |
|||
#else |
|||
#define EXPORT |
|||
#endif |
|||
// Pezas |
|||
#define VACIO 0 |
|||
#define XOG1 1 |
|||
#define XOG2 2 |
|||
#define BOMBA 100 |
|||
#define BOOM 200 |
|||
// GUI |
|||
GladeXML *__gui=NULL; |
|||
// taboleiro |
|||
char __tableiro[8][8]; |
|||
// Xogador ó que lle toca xogar |
|||
int __xog=XOG1; |
|||
// Vida das bombas |
|||
int __vida=0; |
|||
// Nomes dos xogadores |
|||
char *nomeXog[]={"","Marron","Azul"}; |
|||
void fichaGui(int fila,int columna,int xogador); |
|||
void iniciaTaboleiro(void); |
|||
int move_arriba(void); |
|||
void obtenCoordenadas(const char *nome,int *f,int *c); |
|||
void buscaFicha(int xog,int *f,int *c); |
|||
int tenMovemento(int fila,int columna); |
|||
void cambioXogador(void); |
|||
int move(int df,int dc); |
|||
EXPORT void on_xogadores_aceptar_clicked(GtkWidget *w,gpointer p); |
|||
EXPORT gboolean on_Xogos_key_press_event(GtkWidget *widget,GdkEventKey *event,gpointer user_data); |
|||
EXPORT gboolean on_celda_button_press_event (GtkWidget *widget, |
|||
GdkEventButton *event, |
|||
gpointer user_data); |
|||
/*fichaGui |
|||
RECIBE: fila, columna, xogador |
|||
DESCRIPCION: Pon no gui a ficha do xogador na fila e columna |
|||
indicadas. |
|||
*/ |
|||
void fichaGui(int fila,int columna,int xogador) |
|||
{ |
|||
GtkImage *img; |
|||
char buffer[12]; |
|||
// Obtemos a imaxe da ficha |
|||
sprintf(buffer,"image%d",fila*8+columna+1); |
|||
img=(GtkImage *) glade_xml_get_widget(__gui,buffer); |
|||
// Poñemos ficha na posición |
|||
sprintf(buffer,"xog%d.png",xogador); |
|||
gtk_image_set_from_file(img,buffer); |
|||
} |
|||
/*iniciaTaboleiro |
|||
DESCRIPCION: Posición inicial do xogo |
|||
*/ |
|||
void iniciaTaboleiro(void) |
|||
{ |
|||
int i,j; |
|||
GtkImage *img; |
|||
GtkWidget *sb; |
|||
char nome[8]; |
|||
int c; |
|||
int id; |
|||
i=0; |
|||
c=1; |
|||
while(i<8) |
|||
{ |
|||
j=0; |
|||
while(j<8) |
|||
{ |
|||
__tableiro[i][j]=VACIO; |
|||
sprintf(nome,"image%d",c); |
|||
img=(GtkImage *) glade_xml_get_widget(__gui,nome); |
|||
gtk_image_set_from_file(img,"xog0.png"); |
|||
j++; |
|||
c++; |
|||
} |
|||
i++; |
|||
} |
|||
__tableiro[0][0]=XOG1; |
|||
// Poñer ficha no GUI |
|||
fichaGui(0,0,XOG1); |
|||
__tableiro[7][7]=XOG2; |
|||
// Poñer ficha no GUI |
|||
fichaGui(7,7,XOG2); |
|||
__xog=XOG1; |
|||
sb=glade_xml_get_widget(__gui,"nombres"); |
|||
gtk_widget_show(sb); |
|||
} |
|||
/* buscaFicha |
|||
RECIBE: Xogador a buscar (__xog) dirección para a fila (f) e para a columna (c) |
|||
DESCRIPCION: Busca a ficha indicada no taboleiro e a almacena en f e c |
|||
*/ |
|||
void buscaFicha(int xog,int *f,int *c) |
|||
{ |
|||
*f=0; |
|||
*c=0; |
|||
while(((*f)<8)&&(__tableiro[*f][*c]!=xog)) |
|||
{ |
|||
while(((*c)<8)&&(__tableiro[*f][*c]!=xog)) |
|||
{ |
|||
(*c)++; |
|||
} |
|||
if ((*c)==8) |
|||
{ |
|||
*c=0; |
|||
(*f)++; |
|||
} |
|||
} |
|||
} |
|||
void decrementaBombas(void) |
|||
{ |
|||
int f,c; |
|||
f=0; |
|||
while(f<8) |
|||
{ |
|||
c=0; |
|||
while(c<8) |
|||
{ |
|||
if (__tableiro[f][c]>BOMBA) |
|||
{ |
|||
__tableiro[f][c]--; |
|||
if (__tableiro[f][c]==BOMBA) fichaGui(f,c,BOOM); |
|||
} |
|||
else if (__tableiro[f][c]==BOMBA) |
|||
{ |
|||
__tableiro[f][c]=VACIO; |
|||
fichaGui(f,c,VACIO); |
|||
} |
|||
c++; |
|||
} |
|||
f++; |
|||
} |
|||
} |
|||
/* podeMover |
|||
RECIBE: xogador a comprobar |
|||
DEVOLVE: 1 si o xogador pode mover, 0 si non. |
|||
*/ |
|||
int podeMover(int xog) |
|||
{ |
|||
int f,c,ok=0; |
|||
buscaFicha(__xog,&f,&c); |
|||
if (tenMovemento(f-1,c)||tenMovemento(f+1,c)|| |
|||
tenMovemento(f,c+1)||tenMovemento(f,c-1)|| |
|||
tenMovemento(f-1,c-1)||tenMovemento(f-1,c+1)|| |
|||
tenMovemento(f+1,c-1)||tenMovemento(f+1,c+1)) ok=1; |
|||
return ok; |
|||
} |
|||
/* tenMovemento |
|||
RECIBE: fila e columna |
|||
DEVOLVE: 1 si se pode mover a esa fila e columna, 0 noutro caso |
|||
*/ |
|||
int tenMovemento(int fila,int columna) |
|||
{ |
|||
int ok=0; |
|||
if ((fila>=0)&&(columna>=0)&&(fila<8)&&(columna<8)&& |
|||
(__tableiro[fila][columna]==VACIO)) ok=1; |
|||
return ok; |
|||
} |
|||
/* Move a ficha do xogador que lle toca |
|||
*/ |
|||
int move(int df,int dc) |
|||
{ |
|||
int ok=0; |
|||
int f,c; |
|||
/* |
|||
1.- Buscar a ficha (f,c) |
|||
2.- Si pode mover o sitio que lle toca |
|||
Quitar a ficha de donde esta |
|||
Poñela no seu sitio |
|||
ok=1 |
|||
Fin-Si |
|||
*/ |
|||
buscaFicha(__xog,&f,&c); |
|||
if (tenMovemento(f+df,c+dc)) |
|||
{ |
|||
__tableiro[f][c]=__tableiro[f][c]-__xog; |
|||
fichaGui(f,c,__tableiro[f][c]); |
|||
__tableiro[f+df][c+dc]=__xog; |
|||
fichaGui(f+df,c+dc,__xog); |
|||
ok=1; |
|||
} |
|||
return ok; |
|||
} |
|||
/* Pon bomba o xogador que lle toca |
|||
*/ |
|||
int bomba(int df,int dc) |
|||
{ |
|||
int ok=0; |
|||
int f,c; |
|||
/* |
|||
1.- Buscar a ficha (f,c) |
|||
2.- Si pode mover o sitio que lle toca |
|||
Quitar a ficha de donde esta |
|||
Poñela no seu sitio |
|||
ok=1 |
|||
Fin-Si |
|||
*/ |
|||
buscaFicha(__xog,&f,&c); |
|||
if (tenMovemento(f+df,c+dc)) |
|||
{ |
|||
__tableiro[f+df][c+dc]=BOMBA+__vida; |
|||
fichaGui(f+df,c+dc,BOMBA); |
|||
ok=1; |
|||
} |
|||
return ok; |
|||
} |
|||
/* Visualiza o turno na barra de estado |
|||
*/ |
|||
void changeStatus(void) |
|||
{ |
|||
GtkWidget *sb; |
|||
char buffer[128]; |
|||
int id; |
|||
sb=glade_xml_get_widget(__gui,"statusbar"); |
|||
id=gtk_statusbar_get_context_id(GTK_STATUSBAR(sb),"turno"); |
|||
sprintf(buffer,"Turno: %s",nomeXog[__xog]); |
|||
gtk_statusbar_push(GTK_STATUSBAR(sb),id,buffer); |
|||
} |
|||
/*obtenCoordenadas |
|||
RECIBE: O nome da casilla |
|||
As direccións de memoria onde deixar a fila (f) e a columna (c) |
|||
DESCRIPCION: Obten as coordenadas da casilla a partir do nome |
|||
*/ |
|||
void obtenCoordenadas(const char *nome,int *f,int *c) |
|||
{ |
|||
int num; |
|||
// Obter o número da casilla do nome |
|||
num=atoi(&nome[8])-1; |
|||
// Calcular fila e columna |
|||
*f=num/8; |
|||
*c=num%8; |
|||
} |
|||
/* dialogoFin |
|||
*/ |
|||
void dialogoFin(void) |
|||
{ |
|||
GtkWidget *fin; |
|||
char buffer[1024]; |
|||
int gan,f1,f2; |
|||
if (__xog==XOG2) gan=XOG1; |
|||
else gan=XOG2; |
|||
sprintf(buffer,"<big><b>Felicitacións %s</b></big>",nomeXog[gan]); |
|||
fin=glade_xml_get_widget(__gui,"msg"); |
|||
gtk_label_set_markup(GTK_LABEL(fin),buffer); |
|||
fin=glade_xml_get_widget(__gui,"fin"); |
|||
gtk_widget_show(fin); |
|||
} |
|||
void cambioXogador(void) |
|||
{ |
|||
int f,c; |
|||
if (__xog==XOG1) __xog=XOG2; |
|||
else __xog=XOG1; |
|||
if (__vida>0) decrementaBombas(); |
|||
if (!podeMover(__xog)) |
|||
{ |
|||
buscaFicha(__xog,&f,&c); |
|||
fichaGui(f,c,BOOM); |
|||
dialogoFin(); |
|||
} |
|||
changeStatus(); |
|||
} |
|||
//--------------------------------------------------------------------- |
|||
// Xestores de Sinais |
|||
//--------------------------------------------------------------------- |
|||
EXPORT gboolean on_celda_button_press_event (GtkWidget *widget, |
|||
GdkEventButton *event, |
|||
gpointer user_data) |
|||
{ |
|||
const char *nome; |
|||
int f,c,fx,cx; |
|||
int ok=0; |
|||
if (event->type==GDK_BUTTON_PRESS) |
|||
{ |
|||
// Obtemos as coordenadas do nome |
|||
nome=gtk_widget_get_name(widget); |
|||
obtenCoordenadas(nome,&f,&c); |
|||
// Si a casilla está valeira |
|||
if (__tableiro[f][c]==VACIO) |
|||
{ |
|||
// Localizamos o xogador |
|||
buscaFicha(__xog,&fx,&cx); |
|||
switch(event->button) |
|||
{ |
|||
case 1: // Si o xogador está nunha casilla contigua |
|||
// arriba, abaixo, na dereita ou na esquerda |
|||
if ((abs(fx-f)<=1)&&(abs(cx-c)<=1)&&((f==fx)||(c==cx))) |
|||
{ |
|||
__tableiro[fx][cx]=__tableiro[fx][cx]-__xog; |
|||
fichaGui(fx,cx,__tableiro[fx][cx]); |
|||
__tableiro[f][c]=__xog; |
|||
fichaGui(f,c,__xog); |
|||
ok=1; |
|||
} |
|||
break; |
|||
case 3: // Si o xogador está en calquera casilla do redor |
|||
if ((abs(fx-f)<=1)&&(abs(cx-c)<=1)) |
|||
{ |
|||
__tableiro[f][c]=BOMBA+__vida; |
|||
fichaGui(f,c,BOMBA); |
|||
ok=1; |
|||
} |
|||
break; |
|||
} |
|||
if (ok) cambioXogador(); |
|||
} |
|||
} |
|||
return FALSE; |
|||
} |
|||
EXPORT void on_gardar_activate(GtkWidget *w,gpointer p) |
|||
{ |
|||
GtkWidget *ad; |
|||
gchar *fn; |
|||
FILE *f; |
|||
ad=glade_xml_get_widget(__gui,"gardar"); |
|||
if (gtk_dialog_run (GTK_DIALOG(ad)) == GTK_RESPONSE_OK) |
|||
{ |
|||
fn=gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(ad)); |
|||
f=fopen(fn,"w"); |
|||
fwrite(&__xog,sizeof(__xog),1,f); |
|||
fwrite(&__vida,sizeof(__vida),1,f); |
|||
fwrite(nomeXog[1],11,1,f); |
|||
fwrite(nomeXog[2],11,1,f); |
|||
fwrite(__tableiro,sizeof(__tableiro),1,f); |
|||
fclose(f); |
|||
g_free(fn); |
|||
} |
|||
gtk_widget_hide(ad); |
|||
} |
|||
EXPORT void on_abrir_activate(GtkWidget *w,gpointer p) |
|||
{ |
|||
GtkWidget *ad,*sb; |
|||
gchar *fn; |
|||
FILE *f; |
|||
char msg[128]; |
|||
int i,j; |
|||
ad=glade_xml_get_widget(__gui,"abrir"); |
|||
if (gtk_dialog_run (GTK_DIALOG(ad)) == GTK_RESPONSE_OK) |
|||
{ |
|||
// Recuperar o ficheiro |
|||
fn=gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(ad)); |
|||
f=fopen(fn,"r"); |
|||
fread(&__xog,sizeof(__xog),1,f); |
|||
fread(&__vida,sizeof(__vida),1,f); |
|||
sb=glade_xml_get_widget(__gui,"vida"); |
|||
gtk_spin_button_set_value(GTK_SPIN_BUTTON(sb),__vida); |
|||
// Nome do Xog 1 |
|||
fread(msg,11,1,f); |
|||
// Poñelo no entry |
|||
sb=glade_xml_get_widget(__gui,"xogadores_marron"); |
|||
gtk_entry_set_text(GTK_ENTRY(sb),msg); |
|||
nomeXog[1]=(char *)gtk_entry_get_text(GTK_ENTRY(sb)); |
|||
// Nome do Xog 2 |
|||
fread(msg,11,1,f); |
|||
sb=glade_xml_get_widget(__gui,"xogadores_azul"); |
|||
gtk_entry_set_text(GTK_ENTRY(sb),msg); |
|||
nomeXog[2]=(char *)gtk_entry_get_text(GTK_ENTRY(sb)); |
|||
fread(__tableiro,sizeof(__tableiro),1,f); |
|||
fclose(f); |
|||
// Poñer as fichas no gui |
|||
for(i=0;i<8;i++) |
|||
for(j=0;j<8;j++) |
|||
{ |
|||
if (__vida>0) |
|||
{ |
|||
if (__tableiro[i][j]>BOMBA) fichaGui(i,j,BOMBA); |
|||
else if (__tableiro[i][j]==BOMBA) fichaGui(i,j,BOOM); |
|||
else fichaGui(i,j,__tableiro[i][j]); |
|||
} |
|||
else fichaGui(i,j,__tableiro[i][j]); |
|||
} |
|||
// Indicar a que xogador lle toca |
|||
sb=glade_xml_get_widget(__gui,"statusbar"); |
|||
i=gtk_statusbar_get_context_id(GTK_STATUSBAR(sb),"turno"); |
|||
gtk_statusbar_pop(GTK_STATUSBAR(sb),i); |
|||
sprintf(msg,"Turno do Xogador %s",nomeXog[__xog]); |
|||
gtk_statusbar_push(GTK_STATUSBAR(sb),i,msg); |
|||
g_free(fn); |
|||
} |
|||
gtk_widget_hide(ad); |
|||
} |
|||
// Novo Xogo |
|||
// |
|||
EXPORT void on_novo_clicked(GtkWidget *w,gpointer p) |
|||
{ |
|||
GtkWidget *fin; |
|||
fin=glade_xml_get_widget(__gui,"fin"); |
|||
gtk_widget_hide(fin); |
|||
iniciaTaboleiro(); |
|||
} |
|||
/* Nomes dos xogadores |
|||
*/ |
|||
EXPORT void on_xogadores_aceptar_clicked(GtkWidget *w,gpointer p) |
|||
{ |
|||
GtkWidget *sb; |
|||
sb=glade_xml_get_widget(__gui,"nombres"); |
|||
gtk_widget_hide(sb); |
|||
sb=glade_xml_get_widget(__gui,"vida"); |
|||
__vida=gtk_spin_button_get_value_as_int(GTK_SPIN_BUTTON(sb)); |
|||
sb=glade_xml_get_widget(__gui,"xogadores_marron"); |
|||
nomeXog[1]=(char *)gtk_entry_get_text(GTK_ENTRY(sb)); |
|||
sb=glade_xml_get_widget(__gui,"xogadores_azul"); |
|||
nomeXog[2]=(char *)gtk_entry_get_text(GTK_ENTRY(sb)); |
|||
changeStatus(); |
|||
} |
|||
/* Acerca de ... |
|||
*/ |
|||
EXPORT void on_acerca_de_activate(GtkWidget *w,gpointer p) |
|||
{ |
|||
GtkWidget *ad; |
|||
ad=glade_xml_get_widget(__gui,"acercade"); |
|||
gtk_widget_show(ad); |
|||
} |
|||
/* Pulsación de tecla |
|||
*/ |
|||
EXPORT gboolean on_Xogos_key_press_event(GtkWidget *widget,GdkEventKey *event,gpointer user_data) |
|||
{ |
|||
int ok=0,f,c; |
|||
switch(event->keyval) |
|||
{ |
|||
case GDK_Up: if ((event->state&1)==0) |
|||
{ |
|||
ok=move(-1,0); |
|||
} |
|||
else ok=bomba(-1,0); |
|||
break; |
|||
case GDK_Down: if ((event->state&1)==0) |
|||
{ |
|||
ok=move(1,0); |
|||
} |
|||
else ok=bomba(1,0); |
|||
break; |
|||
case GDK_Left: if ((event->state&1)==0) |
|||
{ |
|||
ok=move(0,-1); |
|||
} |
|||
else ok=bomba(0,-1); |
|||
break; |
|||
case GDK_Right: if ((event->state&1)==0) |
|||
{ |
|||
ok=move(0,1); |
|||
} |
|||
else ok=bomba(0,1); |
|||
break; |
|||
case GDK_KP_Page_Down: |
|||
case GDK_Page_Down: if ((event->state&1)==1) |
|||
{ |
|||
ok=bomba(1,1); |
|||
} |
|||
break; |
|||
case GDK_KP_Page_Up: |
|||
case GDK_Page_Up: if ((event->state&1)==1) |
|||
{ |
|||
ok=bomba(-1,1); |
|||
} |
|||
break; |
|||
case GDK_KP_Home: |
|||
case GDK_Home: if ((event->state&1)==1) |
|||
{ |
|||
ok=bomba(-1,-1); |
|||
} |
|||
break; |
|||
case GDK_KP_End: |
|||
case GDK_End: if ((event->state&1)==1) |
|||
{ |
|||
ok=bomba(1,-1); |
|||
} |
|||
break; |
|||
} |
|||
if (ok) |
|||
{ |
|||
cambioXogador(); |
|||
} |
|||
return FALSE; |
|||
} |
|||
//--------------------------------------------------------------------- |
|||
// Función Principal |
|||
//--------------------------------------------------------------------- |
|||
int main(int argc,char *argv[]) |
|||
{ |
|||
GtkFileChooser *d; |
|||
gtk_init(&argc,&argv); |
|||
__gui=glade_xml_new("tablero.glade",NULL,NULL); |
|||
glade_xml_signal_autoconnect(__gui); |
|||
d=(GtkFileChooser *)glade_xml_get_widget(__gui,"gardar"); |
|||
gtk_file_chooser_set_do_overwrite_confirmation(d,TRUE); |
|||
iniciaTaboleiro(); |
|||
gtk_main(); |
|||
} |
|||
</source> |
Revisión actual feita o 26 de xuño de 2014 ás 11:13
Escribir un Xogo no que participan dous xogadores nun taboleiro de 8x8. En cada turno un xogador pode moverse ou poñer unha bomba, perdendo o xogador que non poda efectuar o seu movemento. Un xogador non poderá mover si a casilla á que se ten que desplazar está ocupada por unha bomba ou por outro xogador. As bombas impiden o paso tanto o xogador contrario como ó que as puxo, e teñen unha duración de 5 turnos.
Solucións de Xavi
Makefile
Ficheiro de construcción do programa.
FLAGS = `pkg-config --cflags --libs libglade-2.0`
FLAGSC = `pkg-config --cflags libglade-2.0`
bomber: bomber.c
gcc bomber.c -o bomber $(FLAGS) -export-dynamic
Aplicación GTK
E preciso ter a versión 2.8 das Gtk para que funcione o diálogo de acerca de... Si non se ten o GTK+ 2.8 é necesario comentar as liñas <c>
d=(GtkFileChooser *)glade_xml_get_widget(__gui,"gardar"); gtk_file_chooser_set_do_overwrite_confirmation(d,TRUE);
</c>
Na función main.
Interface
Descargar GUI (ficheiro xml tablero.glade)
Descargar Debuxos (Descomprimir na carpeta do programa)
Pseudocódigo
Cando se pulse unha tecla de movemento ou click no rato Segun a Xogada Si e moverse: comprobar que se pode e moverse Si e poñer bomba: comprobar que se pode e poñela Fin Segun Si o xogador efectuou a súa xogada Cambio de xogador Decrementar as bombas, si procede Comprobar que o outro xogador non perdeu Fin-Si
Implementación en C
bomber.c
/* Bomber
*/
#include <stdio.h>
#include <gtk/gtk.h>
#include <gdk/gdkkeysyms.h>
#include <glade/glade.h>
#ifdef __WINDOWS__
#define EXPORT __declspec (dllexport)
#else
#define EXPORT
#endif
// Pezas
#define VACIO 0
#define XOG1 1
#define XOG2 2
#define BOMBA 100
#define BOOM 200
// GUI
GladeXML *__gui=NULL;
// taboleiro
char __tableiro[8][8];
// Xogador ó que lle toca xogar
int __xog=XOG1;
// Vida das bombas
int __vida=0;
// Nomes dos xogadores
char *nomeXog[]={"","Marron","Azul"};
void fichaGui(int fila,int columna,int xogador);
void iniciaTaboleiro(void);
int move_arriba(void);
void obtenCoordenadas(const char *nome,int *f,int *c);
void buscaFicha(int xog,int *f,int *c);
int tenMovemento(int fila,int columna);
void cambioXogador(void);
int move(int df,int dc);
EXPORT void on_xogadores_aceptar_clicked(GtkWidget *w,gpointer p);
EXPORT gboolean on_Xogos_key_press_event(GtkWidget *widget,GdkEventKey *event,gpointer user_data);
EXPORT gboolean on_celda_button_press_event (GtkWidget *widget,
GdkEventButton *event,
gpointer user_data);
/*fichaGui
RECIBE: fila, columna, xogador
DESCRIPCION: Pon no gui a ficha do xogador na fila e columna
indicadas.
*/
void fichaGui(int fila,int columna,int xogador)
{
GtkImage *img;
char buffer[12];
// Obtemos a imaxe da ficha
sprintf(buffer,"image%d",fila*8+columna+1);
img=(GtkImage *) glade_xml_get_widget(__gui,buffer);
// Poñemos ficha na posición
sprintf(buffer,"xog%d.png",xogador);
gtk_image_set_from_file(img,buffer);
}
/*iniciaTaboleiro
DESCRIPCION: Posición inicial do xogo
*/
void iniciaTaboleiro(void)
{
int i,j;
GtkImage *img;
GtkWidget *sb;
char nome[8];
int c;
int id;
i=0;
c=1;
while(i<8)
{
j=0;
while(j<8)
{
__tableiro[i][j]=VACIO;
sprintf(nome,"image%d",c);
img=(GtkImage *) glade_xml_get_widget(__gui,nome);
gtk_image_set_from_file(img,"xog0.png");
j++;
c++;
}
i++;
}
__tableiro[0][0]=XOG1;
// Poñer ficha no GUI
fichaGui(0,0,XOG1);
__tableiro[7][7]=XOG2;
// Poñer ficha no GUI
fichaGui(7,7,XOG2);
__xog=XOG1;
sb=glade_xml_get_widget(__gui,"nombres");
gtk_widget_show(sb);
}
/* buscaFicha
RECIBE: Xogador a buscar (__xog) dirección para a fila (f) e para a columna (c)
DESCRIPCION: Busca a ficha indicada no taboleiro e a almacena en f e c
*/
void buscaFicha(int xog,int *f,int *c)
{
*f=0;
*c=0;
while(((*f)<8)&&(__tableiro[*f][*c]!=xog))
{
while(((*c)<8)&&(__tableiro[*f][*c]!=xog))
{
(*c)++;
}
if ((*c)==8)
{
*c=0;
(*f)++;
}
}
}
void decrementaBombas(void)
{
int f,c;
f=0;
while(f<8)
{
c=0;
while(c<8)
{
if (__tableiro[f][c]>BOMBA)
{
__tableiro[f][c]--;
if (__tableiro[f][c]==BOMBA) fichaGui(f,c,BOOM);
}
else if (__tableiro[f][c]==BOMBA)
{
__tableiro[f][c]=VACIO;
fichaGui(f,c,VACIO);
}
c++;
}
f++;
}
}
/* podeMover
RECIBE: xogador a comprobar
DEVOLVE: 1 si o xogador pode mover, 0 si non.
*/
int podeMover(int xog)
{
int f,c,ok=0;
buscaFicha(__xog,&f,&c);
if (tenMovemento(f-1,c)||tenMovemento(f+1,c)||
tenMovemento(f,c+1)||tenMovemento(f,c-1)||
tenMovemento(f-1,c-1)||tenMovemento(f-1,c+1)||
tenMovemento(f+1,c-1)||tenMovemento(f+1,c+1)) ok=1;
return ok;
}
/* tenMovemento
RECIBE: fila e columna
DEVOLVE: 1 si se pode mover a esa fila e columna, 0 noutro caso
*/
int tenMovemento(int fila,int columna)
{
int ok=0;
if ((fila>=0)&&(columna>=0)&&(fila<8)&&(columna<8)&&
(__tableiro[fila][columna]==VACIO)) ok=1;
return ok;
}
/* Move a ficha do xogador que lle toca
*/
int move(int df,int dc)
{
int ok=0;
int f,c;
/*
1.- Buscar a ficha (f,c)
2.- Si pode mover o sitio que lle toca
Quitar a ficha de donde esta
Poñela no seu sitio
ok=1
Fin-Si
*/
buscaFicha(__xog,&f,&c);
if (tenMovemento(f+df,c+dc))
{
__tableiro[f][c]=__tableiro[f][c]-__xog;
fichaGui(f,c,__tableiro[f][c]);
__tableiro[f+df][c+dc]=__xog;
fichaGui(f+df,c+dc,__xog);
ok=1;
}
return ok;
}
/* Pon bomba o xogador que lle toca
*/
int bomba(int df,int dc)
{
int ok=0;
int f,c;
/*
1.- Buscar a ficha (f,c)
2.- Si pode mover o sitio que lle toca
Quitar a ficha de donde esta
Poñela no seu sitio
ok=1
Fin-Si
*/
buscaFicha(__xog,&f,&c);
if (tenMovemento(f+df,c+dc))
{
__tableiro[f+df][c+dc]=BOMBA+__vida;
fichaGui(f+df,c+dc,BOMBA);
ok=1;
}
return ok;
}
/* Visualiza o turno na barra de estado
*/
void changeStatus(void)
{
GtkWidget *sb;
char buffer[128];
int id;
sb=glade_xml_get_widget(__gui,"statusbar");
id=gtk_statusbar_get_context_id(GTK_STATUSBAR(sb),"turno");
sprintf(buffer,"Turno: %s",nomeXog[__xog]);
gtk_statusbar_push(GTK_STATUSBAR(sb),id,buffer);
}
/*obtenCoordenadas
RECIBE: O nome da casilla
As direccións de memoria onde deixar a fila (f) e a columna (c)
DESCRIPCION: Obten as coordenadas da casilla a partir do nome
*/
void obtenCoordenadas(const char *nome,int *f,int *c)
{
int num;
// Obter o número da casilla do nome
num=atoi(&nome[8])-1;
// Calcular fila e columna
*f=num/8;
*c=num%8;
}
/* dialogoFin
*/
void dialogoFin(void)
{
GtkWidget *fin;
char buffer[1024];
int gan,f1,f2;
if (__xog==XOG2) gan=XOG1;
else gan=XOG2;
sprintf(buffer,"<big><b>Felicitacións %s</b></big>",nomeXog[gan]);
fin=glade_xml_get_widget(__gui,"msg");
gtk_label_set_markup(GTK_LABEL(fin),buffer);
fin=glade_xml_get_widget(__gui,"fin");
gtk_widget_show(fin);
}
void cambioXogador(void)
{
int f,c;
if (__xog==XOG1) __xog=XOG2;
else __xog=XOG1;
if (__vida>0) decrementaBombas();
if (!podeMover(__xog))
{
buscaFicha(__xog,&f,&c);
fichaGui(f,c,BOOM);
dialogoFin();
}
changeStatus();
}
//---------------------------------------------------------------------
// Xestores de Sinais
//---------------------------------------------------------------------
EXPORT gboolean on_celda_button_press_event (GtkWidget *widget,
GdkEventButton *event,
gpointer user_data)
{
const char *nome;
int f,c,fx,cx;
int ok=0;
if (event->type==GDK_BUTTON_PRESS)
{
// Obtemos as coordenadas do nome
nome=gtk_widget_get_name(widget);
obtenCoordenadas(nome,&f,&c);
// Si a casilla está valeira
if (__tableiro[f][c]==VACIO)
{
// Localizamos o xogador
buscaFicha(__xog,&fx,&cx);
switch(event->button)
{
case 1: // Si o xogador está nunha casilla contigua
// arriba, abaixo, na dereita ou na esquerda
if ((abs(fx-f)<=1)&&(abs(cx-c)<=1)&&((f==fx)||(c==cx)))
{
__tableiro[fx][cx]=__tableiro[fx][cx]-__xog;
fichaGui(fx,cx,__tableiro[fx][cx]);
__tableiro[f][c]=__xog;
fichaGui(f,c,__xog);
ok=1;
}
break;
case 3: // Si o xogador está en calquera casilla do redor
if ((abs(fx-f)<=1)&&(abs(cx-c)<=1))
{
__tableiro[f][c]=BOMBA+__vida;
fichaGui(f,c,BOMBA);
ok=1;
}
break;
}
if (ok) cambioXogador();
}
}
return FALSE;
}
EXPORT void on_gardar_activate(GtkWidget *w,gpointer p)
{
GtkWidget *ad;
gchar *fn;
FILE *f;
ad=glade_xml_get_widget(__gui,"gardar");
if (gtk_dialog_run (GTK_DIALOG(ad)) == GTK_RESPONSE_OK)
{
fn=gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(ad));
f=fopen(fn,"w");
fwrite(&__xog,sizeof(__xog),1,f);
fwrite(&__vida,sizeof(__vida),1,f);
fwrite(nomeXog[1],11,1,f);
fwrite(nomeXog[2],11,1,f);
fwrite(__tableiro,sizeof(__tableiro),1,f);
fclose(f);
g_free(fn);
}
gtk_widget_hide(ad);
}
EXPORT void on_abrir_activate(GtkWidget *w,gpointer p)
{
GtkWidget *ad,*sb;
gchar *fn;
FILE *f;
char msg[128];
int i,j;
ad=glade_xml_get_widget(__gui,"abrir");
if (gtk_dialog_run (GTK_DIALOG(ad)) == GTK_RESPONSE_OK)
{
// Recuperar o ficheiro
fn=gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(ad));
f=fopen(fn,"r");
fread(&__xog,sizeof(__xog),1,f);
fread(&__vida,sizeof(__vida),1,f);
sb=glade_xml_get_widget(__gui,"vida");
gtk_spin_button_set_value(GTK_SPIN_BUTTON(sb),__vida);
// Nome do Xog 1
fread(msg,11,1,f);
// Poñelo no entry
sb=glade_xml_get_widget(__gui,"xogadores_marron");
gtk_entry_set_text(GTK_ENTRY(sb),msg);
nomeXog[1]=(char *)gtk_entry_get_text(GTK_ENTRY(sb));
// Nome do Xog 2
fread(msg,11,1,f);
sb=glade_xml_get_widget(__gui,"xogadores_azul");
gtk_entry_set_text(GTK_ENTRY(sb),msg);
nomeXog[2]=(char *)gtk_entry_get_text(GTK_ENTRY(sb));
fread(__tableiro,sizeof(__tableiro),1,f);
fclose(f);
// Poñer as fichas no gui
for(i=0;i<8;i++)
for(j=0;j<8;j++)
{
if (__vida>0)
{
if (__tableiro[i][j]>BOMBA) fichaGui(i,j,BOMBA);
else if (__tableiro[i][j]==BOMBA) fichaGui(i,j,BOOM);
else fichaGui(i,j,__tableiro[i][j]);
}
else fichaGui(i,j,__tableiro[i][j]);
}
// Indicar a que xogador lle toca
sb=glade_xml_get_widget(__gui,"statusbar");
i=gtk_statusbar_get_context_id(GTK_STATUSBAR(sb),"turno");
gtk_statusbar_pop(GTK_STATUSBAR(sb),i);
sprintf(msg,"Turno do Xogador %s",nomeXog[__xog]);
gtk_statusbar_push(GTK_STATUSBAR(sb),i,msg);
g_free(fn);
}
gtk_widget_hide(ad);
}
// Novo Xogo
//
EXPORT void on_novo_clicked(GtkWidget *w,gpointer p)
{
GtkWidget *fin;
fin=glade_xml_get_widget(__gui,"fin");
gtk_widget_hide(fin);
iniciaTaboleiro();
}
/* Nomes dos xogadores
*/
EXPORT void on_xogadores_aceptar_clicked(GtkWidget *w,gpointer p)
{
GtkWidget *sb;
sb=glade_xml_get_widget(__gui,"nombres");
gtk_widget_hide(sb);
sb=glade_xml_get_widget(__gui,"vida");
__vida=gtk_spin_button_get_value_as_int(GTK_SPIN_BUTTON(sb));
sb=glade_xml_get_widget(__gui,"xogadores_marron");
nomeXog[1]=(char *)gtk_entry_get_text(GTK_ENTRY(sb));
sb=glade_xml_get_widget(__gui,"xogadores_azul");
nomeXog[2]=(char *)gtk_entry_get_text(GTK_ENTRY(sb));
changeStatus();
}
/* Acerca de ...
*/
EXPORT void on_acerca_de_activate(GtkWidget *w,gpointer p)
{
GtkWidget *ad;
ad=glade_xml_get_widget(__gui,"acercade");
gtk_widget_show(ad);
}
/* Pulsación de tecla
*/
EXPORT gboolean on_Xogos_key_press_event(GtkWidget *widget,GdkEventKey *event,gpointer user_data)
{
int ok=0,f,c;
switch(event->keyval)
{
case GDK_Up: if ((event->state&1)==0)
{
ok=move(-1,0);
}
else ok=bomba(-1,0);
break;
case GDK_Down: if ((event->state&1)==0)
{
ok=move(1,0);
}
else ok=bomba(1,0);
break;
case GDK_Left: if ((event->state&1)==0)
{
ok=move(0,-1);
}
else ok=bomba(0,-1);
break;
case GDK_Right: if ((event->state&1)==0)
{
ok=move(0,1);
}
else ok=bomba(0,1);
break;
case GDK_KP_Page_Down:
case GDK_Page_Down: if ((event->state&1)==1)
{
ok=bomba(1,1);
}
break;
case GDK_KP_Page_Up:
case GDK_Page_Up: if ((event->state&1)==1)
{
ok=bomba(-1,1);
}
break;
case GDK_KP_Home:
case GDK_Home: if ((event->state&1)==1)
{
ok=bomba(-1,-1);
}
break;
case GDK_KP_End:
case GDK_End: if ((event->state&1)==1)
{
ok=bomba(1,-1);
}
break;
}
if (ok)
{
cambioXogador();
}
return FALSE;
}
//---------------------------------------------------------------------
// Función Principal
//---------------------------------------------------------------------
int main(int argc,char *argv[])
{
GtkFileChooser *d;
gtk_init(&argc,&argv);
__gui=glade_xml_new("tablero.glade",NULL,NULL);
glade_xml_signal_autoconnect(__gui);
d=(GtkFileChooser *)glade_xml_get_widget(__gui,"gardar");
gtk_file_chooser_set_do_overwrite_confirmation(d,TRUE);
iniciaTaboleiro();
gtk_main();
}