minesweeper.c
来自「开发linux应用-用gtk+和gdk开发linux图形用户界面应用--的实例」· C语言 代码 · 共 849 行 · 第 1/2 页
C
849 行
/* * File: Minesweeper.c * Auth: Eric Harlow * * Similar to the windows minesweeper game. */#include <gtk/gtk.h>#include <stdlib.h>#include <time.h>#include "misc.h"#include "bitmaps.h"#include "digits.h"void SetStartButtonIcon (gchar **xpm_data);/* * --- Want the buttons to be a particular size. */#define BUTTON_WIDTH 18#define BUTTON_HEIGHT 19/* * --- Each of the digits showing the number of bombs * has a colorful bitmap showing the count. This * array make the looking up of the digits happen * very quickly. */gpointer digits[] = { NULL, xpm_one, xpm_two, xpm_three, xpm_four, xpm_five, xpm_six, xpm_seven, xpm_eight};/* * --- These are the available button states. * * Unknown - Empty. Don't know what it could be. * Flagged - User has put a flag on it, suspecting * there's a bomb underneath. * Question - not implemented. * Down - Button has been pressed. */enum { BUTTON_UNKNOWN, BUTTON_FLAGGED, BUTTON_QUESTION, BUTTON_DOWN};/* * --- data structure to keep track of the minesweeper buttons. */typedef struct { int buttonState; /* --- Column to place the button --- */ GtkWidget *widget; /* --- Handle to the button --- */ int nBombsNearby; /* --- How many are near this cell? --- */ int bHasBomb; /* --- Does it have a bomb? --- */ int nRow; /* --- Row of button --- */ int nCol; /* --- Column of button --- */} typMinesweeperButton;/* * --- Default values for the size of the grid * and number of bombs. */static int nRows = 10;static int nCols = 10;static int nTotalBombs = 10;/* * --- Use a 2-d array for the grid. This is just * the maximum size. */#define MAX_ROWS 35#define MAX_COLS 35/* * Globals. *//* --- Just allocate the MAX for now. This really should be dynamic, * but using a two dimensional array is easy when dealing with a grid. */typMinesweeperButton mines[MAX_COLS][MAX_ROWS];/* --- Flags for the game --- */int bGameOver = FALSE; /* --- Game is over? --- */int bResetGame = FALSE; /* --- Game is over? --- */int nBombsLeft; /* --- Undiscovered bombs --- */GtkWidget *table = NULL; /* --- Table with the grid in it. --- */GtkWidget *button_start; /* --- Start button --- */GtkWidget *label_bombs; /* --- Label showing # of bombs left --- */GtkWidget *label_time; /* --- Label showing # of bombs left --- */GtkWidget *vbox; /* --- main window's vbox --- *//* * --- Prototypes. */void DisplayHiddenInfo (typMinesweeperButton *mine);void CreateMinesweeperButtons (GtkWidget *table, int c, int r, int flag);void FreeChildCallback (GtkWidget *widget);/* * CheckForWin * * Check to see if the game has been won. Game has been won when the * number of unclicked squares equals the number of total bombs. */void CheckForWin (){ int i, j; int nMines = 0; /* --- Run through all the squares --- */ for (i = 0; i < nCols; i++) { for (j = 0; j < nRows; j++) { /* --- If square is unclicked or has a flag on it... --- */ if (mines[i][j].buttonState == BUTTON_UNKNOWN || mines[i][j].buttonState == BUTTON_FLAGGED) { /* --- Could be a bomb. --- */ nMines ++; } } } /* --- As many bombs as there are squares left? --- */ if (nMines == nTotalBombs) { /* --- Stop the game. We have a winner. --- */ StopTimer (); SetStartButtonIcon ((gchar **) xpm_winner); bGameOver = TRUE; }}/* * AddImageToMine * * Change the image on the button to be that of the xpm. * * mine - square on the grid * xpm - image data */void AddImageToMine (typMinesweeperButton *mine, char *xpm[]){ GtkWidget *widget; /* --- Create a widget from the xpm file --- */ widget = CreateWidgetFromXpm (table, (gchar **) xpm); /* --- Put the bitmap in the button --- */ gtk_container_add (GTK_CONTAINER (mine->widget), widget); /* --- deref image so when button is destroyed, image is destroyed. --- */ gdk_pixmap_unref ((GdkPixmap *) widget);}/* * UpdateSeconds * * Refresh the seconds display in the toolbar. * * nSeconds - how many seconds to display. */void UpdateSeconds (int nSeconds){ char buffer[44]; /* --- Change the label to show new time --- */ sprintf (buffer, "Time: %d", nSeconds); gtk_label_set (GTK_LABEL (label_time), buffer);}/* * DisplayBombCount * * Show number of bombs remaining. */void DisplayBombCount (){ char buffer[33]; /* --- You have XX bombs left --- */ sprintf (buffer, "Bombs: %d", nBombsLeft); gtk_label_set (GTK_LABEL (label_bombs), buffer);}/* * FreeChild * * Free all the children of the widget * This is called when the button has to display a new image. * The old image is destroyed here. */void FreeChild (GtkWidget *widget) { /* --- Free button children --- */ gtk_container_foreach ( GTK_CONTAINER (widget), (GtkCallback) FreeChildCallback, NULL);}/* * delete_event * * The window is closing down, end the gtk loop * */void delete_event (GtkWidget *widget, gpointer *data){ gtk_main_quit ();}/* * ShowBombs * * They clicked on a bomb, so now we have to show them were the * bombs really are. (At least those they didn't find already.) * We display the bombs they didn't find as well as the bombs * they think they found that were not bombs. */ void ShowBombs (typMinesweeperButton *minefound){ int i, j; typMinesweeperButton *mine; GtkWidget *widget_x; /* --- Run through all the squares --- */ for (i = 0; i < nCols; i++) { for (j = 0; j < nRows; j++) { /* --- Get the datastructure --- */ mine = &mines[i][j]; /* --- If there's a button here and there's a bomb --- */ /* --- underneath --- */ if (mine->buttonState == BUTTON_UNKNOWN && mine->bHasBomb) { /* --- Display the bomb. --- */ DisplayHiddenInfo (mine); /* --- If they marked it as a bomb and there is * no bomb here... --- */ } else if (mine->buttonState == BUTTON_FLAGGED && !mine->bHasBomb) { /* --- Free the flag --- */ FreeChild (mine->widget); /* --- Show the X at the location --- */ AddImageToMine (mine, xpm_bigx); } } }}/* * OpenNearbySquares * * Open up all squares around this square. * * col, row - position to open up the square * Open all squares near this one - X represents * the current square. * * |---|---|---- * | | | | * ------------- * | | X | | * ------------- * | | | | * |---|---|---- */void OpenNearbySquares (int col, int row){ int i, j; /* --- Look one column back and one column ahead --- */ for (i = MAX (col-1, 0); i <= MIN (col+1, nCols-1); i++) { /* --- Check one row back and one row ahead --- */ for (j = MAX (row-1, 0); j <= MIN (row+1, nRows-1); j++) { /* --- Display what's underneath --- */ DisplayHiddenInfo (&mines[i][j]); } }}/* * DisplayHiddenInfo * * Display what's hidden underneath the button. * Could be a bomb - * Could be a square with a count of the bombs * nearby. * Could be an empty square */void DisplayHiddenInfo (typMinesweeperButton *mine){ char buffer[88]; GtkWidget *widget; /* --- If it's already down, just return --- */ if (mine->buttonState == BUTTON_DOWN) { gtk_toggle_button_set_state (GTK_TOGGLE_BUTTON (mine->widget), TRUE); return; } /* --- If the button is flagged, don't fix it for them --- */ if (mine->buttonState == BUTTON_FLAGGED) { /* --- They said there's a bomb here - so don't * open it up even if logically, there * can't be a bomb. */ gtk_toggle_button_set_state (GTK_TOGGLE_BUTTON (mine->widget), FALSE); } else { /* --- Put the button in the "down" state --- */ mine->buttonState = BUTTON_DOWN; gtk_toggle_button_set_state (GTK_TOGGLE_BUTTON (mine->widget), TRUE); /* --- If there's a bomb at the location --- */ if (mine->bHasBomb) { /* --- Show the bomb at the location --- */ AddImageToMine (mine, xpm_bomb); /* --- No bombs, but there are bombs near this one --- */ } else if (mine->nBombsNearby) { /* --- Show the count of nearby bombs. --- */ AddImageToMine (mine, digits[mine->nBombsNearby]); } else { /* --- Hmm. Clicked here, but no bombs and no count. --- */ /* Open up all squares near here - may cascade. --- */ OpenNearbySquares (mine->nCol, mine->nRow); } }}/* * ResetGame * * Reset the game so it can be replayed. Reset bomb * count and create a nice empty field of bombs. */void ResetGame (int nGridColumns, int nGridRows, int nBombs, int bNewButtons){ /* --- Reset the number of bombs in grid --- */ nTotalBombs = nBombs; /* --- Reset the number of bombs undiscovered --- */ nBombsLeft = nBombs; /* --- Create the Minesweeper buttons. --- */ CreateMinesweeperButtons (table, nGridColumns, nGridRows, bNewButtons); /* --- Stop the timer. --- */ StopTimer (); UpdateSeconds (0); SetStartButtonIcon ((gchar **) xpm_smile);}/* * FreeChildCallback * * Free the widget. */void FreeChildCallback (GtkWidget *widget){ gtk_widget_destroy (widget);}/* * SetStartButtonIcon * * Set the start button to have the image based on * the data passed in. Usually, this is going to be * either the happy face or the frown. */void SetStartButtonIcon (gchar **xpm_data){ GtkWidget *widget; /* --- Create a widget from the xpm --- */ widget = CreateWidgetFromXpm (button_start, xpm_data); /* --- Free any children the button has --- */ FreeChild (button_start);
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?