/* * File: gboggle.c * --------------- * This file implements the gboggle.h interface, which provides * the graphics support for the Boggle program. */ /* * General implementation notes * ---------------------------- * This file implements the graphics support functions for the * Boggle program. It makes straightforward use of the extended * graphics library to draw the dice, board, letters, scoreboard, * and so forth. The implementations of the individual functions * are fairly simple, and you should feel free to change these if * you get inspired. For descriptions of the behavior of the * exported functions, please see the interface file. */ #include #include "genlib.h" #include "strlib.h" #include "extgraph.h" #include "gboggle.h" /* * Constants * --------- * These constants define the graphical parameters of the display. * The purpose of each constant should be clear from its name. */ #define Dimension 4 #define CubeSize 0.50 #define CornerRadius 0.125 #define BoardSize (Dimension * CubeSize) #define BorderWidth 0.26 #define BoardX 1.75 #define BoardTopY 3.0 #define DividerLineY (BoardTopY + BorderWidth/2.0) #define ScoreY (DividerLineY + 0.06) #define WordY (BoardTopY - 0.05) #define HumanX 0.05 #define ComputerX (BoardX + BoardSize + BorderWidth) #define LetterFont "Helvetica" #define LetterSize 24 #define ScoreFont "Helvetica" #define ScoreSize 18 #define WordFont "Geneva" #define WordSize 9 #define ColumnWidth 0.53 #define HumanColumns 3 #define ComputerColumns 5 /* * Global table: colorTable * ------------------------ * This table defines the new colors that are used in the * Boggle game. */ typedef struct { string colorName; double red, green, blue; } colorEntryT; static colorEntryT colorTable[] = { {"BoardColor", 1.00, 0.86, 0.05}, /* yellow-orange */ {"DieColor", 0.90, 0.90, 0.90}, /* almost white */ {"LetterColor", 0.01, 0.20, 0.85}, /* dark blue */ {"WordColor", 0.01, 0.50, 0.30}, /* med green-blue */ {"LabelColor", 0.01, 0.45, 0.25}, /* dark green-blue */ }; static int nColors = sizeof colorTable / sizeof colorTable[0]; /* * Private global variables * ------------------------ * numWords -- Array containing number of words for each player * scores -- Array containing score for each player * letters -- Matrix containing the letter cubes * initialized -- Flag indicating colors have been initialized */ static int numWords[2]; static int scores[2]; static char letters[Dimension][Dimension]; static bool initialized = FALSE; /* Private function prototypes */ static void InitColors(void); static void DrawDice(void); static void DrawCube(int row, int col, char ch, bool highlight); static double CubeX(int col); static double CubeY(int row); static void DrawCenteredChar(double centerX, double centerY, char ch); static void DrawScoreboard(void); static void DrawBorder(void); static void UpdateScore(int pointsToAdd, playerT player); static void DrawOneScore(playerT player, int value); void DrawBox(double x, double y, double width, double height); void DrawRoundedBox(double x, double y, double width, double height, double radius); void DrawFilledBox(double x, double y, double width, double height, double density); /* Exported entries */ void DrawBoard(void) { if (!initialized) InitColors(); initialized = TRUE; DrawBorder(); DrawDice(); DrawScoreboard(); SetWindowTitle("Welcome to Boggle!"); scores[Human] = scores[Computer] = 0; numWords[Human] = numWords[Computer] = 0; } void LabelCube(int row, int col, char letter) { letters[row][col] = letter; DrawCube(row, col, letter, FALSE); } void HighlightCube(int row, int col, bool flag) { DrawCube(row, col, letters[row][col], flag); } void RecordNewWord(string word, playerT player) { int row, col, nColumns; double x; SetFont(WordFont); SetPointSize(WordSize); SetPenColor("WordColor"); switch (player) { case Human: nColumns = HumanColumns; x = HumanX; break; case Computer: nColumns = ComputerColumns; x = ComputerX; break; } row = numWords[player] / nColumns; col = numWords[player] % nColumns; MovePen(x + col * ColumnWidth, WordY - row * GetFontHeight()); DrawTextString(word); UpdateScore(StringLength(word) - 3, player); numWords[player]++; } /* Private functions */ /* * Function: InitColors * -------------------- * This function defines the new colors used in the Boggle game. * The colors themselves are defined in the colorTable structure. */ static void InitColors(void) { int i; for (i = 0; i < nColors; i++) { DefineColor(colorTable[i].colorName, colorTable[i].red, colorTable[i].green, colorTable[i].blue); } } /* * Function: DrawDice * ------------------ * This function draws all of the dice in position. The dice * are drawn blank, the client will fill in the letters by * calling the function LabelCube. */ static void DrawDice(void) { int row, col; for (col = 0; col < Dimension; col++) { for (row = 0; row < Dimension; row++) { DrawCube(col, row, ' ', FALSE); } } } /* * Function: DrawCube * ------------------ * This function draws one cube in its position, including the letter * centered in the middle of the cube. If highlight is true, we * reverse the background and letter colors to highlight the cube. */ static void DrawCube(int row, int col, char ch, bool highlight) { SetPenColor((highlight) ? "LetterColor" : "DieColor"); StartFilledRegion(1.0); DrawRoundedBox(CubeX(col), CubeY(row), CubeSize, CubeSize, CornerRadius); EndFilledRegion(); SetPenColor("Black"); DrawRoundedBox(CubeX(col), CubeY(row), CubeSize, CubeSize, CornerRadius); SetPenColor((highlight) ? "DieColor" : "LetterColor"); DrawCenteredChar(CubeX(col) + CubeSize/2.0, CubeY(row) + CubeSize/2.0, ch); } /* * Functions CubeX, CubeY * ---------------------- * These functions return the coordinates of the lower-left corner * of the cube at position (row, col). */ static double CubeX(int col) { return (BoardX + CubeSize * col); } static double CubeY(int row) { return (BoardTopY - CubeSize * (row + 1)); } /* * Function: DrawCenteredChar * -------------------------- * This function draws the letter ch in the center of the cube. * Note that this function centers the char both vertically and * horizontally around the point specified. */ static void DrawCenteredChar(double centerX, double centerY, char ch) { char buffer[2]; buffer[0] = ch; buffer[1] = '\0'; SetFont(LetterFont); SetPointSize(LetterSize); MovePen(centerX - TextStringWidth(buffer) / 2, centerY - GetFontAscent() / 2); DrawTextString(buffer); } /* * Function: DrawScoreboard * ------------------------ * This function sets up the scoreboard by drawing the player * labels and lines underneath them. */ static void DrawScoreboard(void) { SetPenColor("LabelColor"); MovePen(HumanX, DividerLineY); DrawLine(BoardX - BorderWidth - GetCurrentX(), 0); MovePen(ComputerX, DividerLineY); DrawLine(GetWindowWidth() - GetCurrentX(),0); SetFont(ScoreFont); SetPointSize(ScoreSize); MovePen(HumanX, ScoreY); DrawTextString("Me"); MovePen(ComputerX, ScoreY); DrawTextString("Computer"); } /* * Function: DrawBorder * -------------------- * This function draws a simple filled border around the dice * cubes in the yellow color we all so fondly remember from * our childhood. */ static void DrawBorder(void) { double rectSize; rectSize = BoardSize + BorderWidth; SetPenColor("BoardColor"); DrawFilledBox(BoardX - BorderWidth/2, BoardTopY - rectSize + BorderWidth/2, rectSize, rectSize, .5); } /* * Function: UpdateScore * --------------------- * This function updates a player's score by the specified * number of points. Note that we must first erase the old * score before drawing the new one; otherwise we scribble and * create chaos. The scores are kept in an array that is * private to this module. */ static void UpdateScore(int pointsToAdd, playerT player) { SetEraseMode(TRUE); DrawOneScore(player, scores[player]); SetEraseMode(FALSE); scores[player] += pointsToAdd; DrawOneScore(player, scores[player]); } /* * Function: DrawOneScore * ---------------------- * This function draws the specified score for the player. The * implementation uses sprintf instead of IntegerToString to * avoid wasting memory. */ static void DrawOneScore(playerT player, int value) { char buffer[4]; sprintf(buffer,"%d", value); SetFont(ScoreFont); SetPointSize(ScoreSize); SetPenColor("LabelColor"); MovePen(((player == Human) ? HumanX : ComputerX) + 1.25, ScoreY); DrawTextString(buffer); } /* Shape-drawing functions */ void DrawBox(double x, double y, double width, double height) { MovePen(x, y); DrawLine(0, height); DrawLine(width, 0); DrawLine(0, -height); DrawLine(-width, 0); } void DrawRoundedBox(double x, double y, double width, double height, double radius) { double r; r = ((int) (radius * GetXResolution() + 0.5)) / GetXResolution(); if (r > width / 2) r = width / 2; if (r > height / 2) r = height / 2; MovePen(x + r, y); DrawLine(width - 2 * r, 0); DrawArc(r, -90, 90); DrawLine(0, height - 2 * r); DrawArc(r, 0, 90); DrawLine(-(width - 2 * r), 0); DrawArc(r, 90, 90); DrawLine(0, -(height - 2 * r)); DrawArc(r, 180, 90); MovePen(x, y); } void DrawFilledBox(double x, double y, double width, double height, double density) { bool eraseMode; StartFilledRegion(density); DrawBox(x, y, width, height); EndFilledRegion(); eraseMode = GetEraseMode(); SetEraseMode(eraseMode || density < 0.5); DrawBox(x, y, width, height); SetEraseMode(eraseMode); } ÿ