|
DataMuseum.dkPresents historical artifacts from the history of: DKUUG/EUUG Conference tapes |
This is an automatic "excavation" of a thematic subset of
See our Wiki for more about DKUUG/EUUG Conference tapes Excavated with: AutoArchaeologist - Free & Open Source Software. |
top - metrics - downloadIndex: T b
Length: 27424 (0x6b20) Types: TextFile Names: »board.c«
└─⟦b20c6495f⟧ Bits:30007238 EUUGD18: Wien-båndet, efterår 1987 └─⟦this⟧ »EUUGD18/X/Dragon/board.c«
/****************************************************************************** * Dragon - a version of Mah-Jongg for X Windows * * Author: Gary E. Barnes March 1989 * * board.c - Deals with the Mah-Jongg board. Setup and execution. ******************************************************************************/ #define _BOARD_C_ #include "main.h" #include "board.h" extern long random(); \f void Write_Game( file ) FILE *file; /****************************************************************************** * file - Specifies a file open for write * * Called to write out the current game context for later rereading. ******************************************************************************/ { (void)fwrite( (char*)&Score, 1, sizeof(Score), file ); (void)fwrite( (char*)&Board_Tiles[0][0], 1, sizeof(Board_Tiles), file ); } /* Write_Game */ \f void Read_Game( file ) FILE *file; /****************************************************************************** * file - Specifies a file open for reading * * Called to read in a new current game context. ******************************************************************************/ { Click1 = Board_Position_NULL; Click2 = Board_Position_NULL; (void)fread( (char*)&Score, 1, sizeof(Score), file ); (void)fread( (char*)&Board_Tiles[0][0], 1, sizeof(Board_Tiles), file ); } /* Read_Game */ \f static int Pick_Tile( Avail ) char *Avail; /****************************************************************************** * Avail - Specifies an [NTILES] array of available tiles. Unavailable * slots contain NO_TILE. * * Called to pick a random tile from the Available tiles. ******************************************************************************/ { register char *t; register int k; /*--Pick a random starting place. */ k = (int)random() % NTILES; t = &Avail[k]; /*--Search until we find a non-NO_TILE slot. */ while (*t == NO_TILE) { ++t; if (++k == NTILES) { t = &Avail[0]; k = 0; } } /*--Return the tile we found and zap the slot. */ k = *t; *t = NO_TILE; return k; } /* Pick_Tile */ \f void Set_Tile_Controls() /****************************************************************************** * Called whenever the board has been reset or resized. We recalculate all of * the drawing controls for the tiles. ******************************************************************************/ { register Board_Position bp; int row, col; /*--Now set up the control information for all of the tiles. The special * tiles are easy. */ DEBUG_CALL(Set_Tile_Controls); if (Board_Tiles[SPEC4].level > 0) { Board_Tiles[SPEC4].x = Board_Tile0_X + 6 * (Tile_Width + 1) + (Tile_Width + 1) / 2 + 4 * Side_X; Board_Tiles[SPEC4].y = Board_Tile0_Y + 3 * (Tile_Height + 1) + (Tile_Height + 1) / 2 - 3 * Side_Y; } if (Board_Tiles[SPEC3].level > 0) { Board_Tiles[SPEC3].x = Board_Tile0_X + 0 * (Tile_Width + 1); Board_Tiles[SPEC3].y = Board_Tile0_Y + 3 * (Tile_Height + 1) + (Tile_Height + 1) / 2; } if (Board_Tiles[SPEC2].level > 0) { Board_Tiles[SPEC2].x = Board_Tile0_X + 13 * (Tile_Width+1); Board_Tiles[SPEC2].y = Board_Tile0_Y + 3 * (Tile_Height+1) + (Tile_Height + 1) / 2; } if (Board_Tiles[SPEC1].level > 0) { Board_Tiles[SPEC1].x = Board_Tile0_X + 14 * (Tile_Width+1); Board_Tiles[SPEC1].y = Board_Tile0_Y + 3 * (Tile_Height+1) + (Tile_Height + 1) / 2; } /*--Do the more regular tiles. */ for (row = 0; row <= 7; ++row) { for (col = 12; col >= 1; --col) { bp = &Board_Tiles[row][col]; /*--Skip any tiles that don't exist. */ if (bp->level == 0) { continue; } /*--Set up the face x/y coordinates. */ bp->x = Board_Tile0_X + col * (Tile_Width + 1); bp->y = Board_Tile0_Y + row * (Tile_Height + 1); } } DEBUG_RETURN(Set_Tile_Controls); } /* Set_Tile_Controls */ \f static void Pick1( bp, Avail ) register Board_Position bp; char *Avail; { bp->tiles[0] = Pick_Tile( Avail ); bp->level = 1; } static void Pick2( bp, Avail ) register Board_Position bp; char *Avail; { bp->tiles[0] = Pick_Tile( Avail ); bp->tiles[1] = Pick_Tile( Avail ); bp->level = 2; } static void Pick3( bp, Avail ) register Board_Position bp; char *Avail; { bp->tiles[0] = Pick_Tile( Avail ); bp->tiles[1] = Pick_Tile( Avail ); bp->tiles[2] = Pick_Tile( Avail ); bp->level = 3; } static void Pick4( bp, Avail ) register Board_Position bp; char *Avail; { bp->tiles[0] = Pick_Tile( Avail ); bp->tiles[1] = Pick_Tile( Avail ); bp->tiles[2] = Pick_Tile( Avail ); bp->tiles[3] = Pick_Tile( Avail ); bp->level = 4; } \f void Setup_New_Game() /****************************************************************************** * Called to generate an all-new game. ******************************************************************************/ { register Board_Position bp; char Avail[NTILES]; int row, col, i; /*--Clear the board. */ DEBUG_CALL(Setup_New_Game); bp = &Board_Tiles[0][0]; for (row = 0; row < NROWS; ++row) { for (col = 0; col < NCOLS; ++col) { bp->tiles[0] = NO_TILE; bp->tiles[1] = NO_TILE; bp->tiles[2] = NO_TILE; bp->tiles[3] = NO_TILE; bp->level = 0; } } /*--Mark all tiles as available. */ i = 0; for (row = 0; row < 4; ++row) { Avail[i++] = row + 1; Avail[i++] = row + 5; for (col = 8; col < NFACES; ++col) { Avail[i++] = 1 + col % NFACES; } } if (i != NTILES) { (void)fprintf( stderr, "NTILES gak!\n" ); } /*--Fill in the "odd" tile slots. */ Pick1( &Board_Tiles[SPEC1], Avail ); Pick1( &Board_Tiles[SPEC2], Avail ); Pick1( &Board_Tiles[SPEC3], Avail ); Pick1( &Board_Tiles[SPEC4], Avail ); for (col = 1; col <= 12; ++col) { Pick1( &Board_Tiles[0][col], Avail ); Pick1( &Board_Tiles[7][col], Avail ); } for (row = 1; row <= 6; ++row) { Pick1( &Board_Tiles[row][ 3], Avail ); Pick1( &Board_Tiles[row][10], Avail ); } for (row = 2; row <= 5; ++row) { Pick1( &Board_Tiles[row][ 2], Avail ); Pick1( &Board_Tiles[row][11], Avail ); } for (row = 3; row <= 4; ++row) { Pick1( &Board_Tiles[row][ 1], Avail ); Pick1( &Board_Tiles[row][12], Avail ); } /*--Now do the next square at level 2. */ for (col = 4; col <= 9; ++col) { Pick2( &Board_Tiles[1][col], Avail ); Pick2( &Board_Tiles[6][col], Avail ); } for (row = 2; row <= 5; ++row) { Pick2( &Board_Tiles[row][4], Avail ); Pick2( &Board_Tiles[row][9], Avail ); } /*--Now do the next square at level 3. */ for (col = 5; col <= 8; ++col) { Pick3( &Board_Tiles[2][col], Avail ); Pick3( &Board_Tiles[5][col], Avail ); } for (row = 3; row <= 4; ++row) { Pick3( &Board_Tiles[row][5], Avail ); Pick3( &Board_Tiles[row][8], Avail ); } /*--Now do the final square at level 4. */ for (row = 3; row <= 4; ++row) { for (col = 6; col <= 7; ++col) { Pick4( &Board_Tiles[row][col], Avail ); } } /*--Now set up the control information for all of the tiles. */ Set_Tile_Controls(); Score = NTILES; DEBUG_RETURN(Setup_New_Game); } /* Setup_New_Game */ \f /*ARGSUSED*/ void Restart_Game( w, event, params, num_params ) Widget w; XEvent *event; String *params; Cardinal *num_params; /****************************************************************************** * Called when the RESTART button is pressed. Restart the game. ******************************************************************************/ { int row; int col; register Board_Position bp; /*--Reset levels and remove hilites. */ DEBUG_CALL(Restart_Game); Click1 = Board_Position_NULL; Click2 = Board_Position_NULL; Score = NTILES; bp = &Board_Tiles[0][0]; for (row = 0; row < NROWS; ++row) { for (col = 0; col < NCOLS; ++bp,++col) { if (bp->tiles[3] != NO_TILE) { bp->level = 4; } else if (bp->tiles[2] != NO_TILE) { bp->level = 3; } else if (bp->tiles[1] != NO_TILE) { bp->level = 2; } else if (bp->tiles[0] != NO_TILE) { bp->level = 1; } else { bp->level = 0; } } } /*--Finish setting up and then redraw everything. */ Set_Tile_Controls(); XClearArea( XtDisplay(Board), XtWindow(Board), 0, 0, 0, 0, TRUE ); DEBUG_RETURN(Restart_Game); } /* Restart_Game */ \f static void Set_Tile_Draw( row, col ) int row; int col; /****************************************************************************** * row - Specifies the row of the tile * col - Specifies the column of the tile * * Called to set the "draw" flag on a tile. We also recursively set the * draw flag on anyone that needs to be redrawn because we are being redrawn. ******************************************************************************/ { register Board_Position bp = &Board_Tiles[row][col]; /*--If we don't exist or if we are already being redrawn then stop. */ DEBUG_CALL(Set_Tile_Draw); if (bp->level == 0 || bp->draw) { return; } /*--Redraw us. Redraw anyone to our left that has a height greater than ours * because their shadow/tile-face overlaps us. */ bp->draw = TRUE; if (col > 0 && Board_Tiles[row][col-1].level > bp->level) { Set_Tile_Draw( row, col-1 ); } /*--Redraw anyone below us that has a level greater than ours because their * shadow/tile-face overlaps us. */ if (row < 7 && Board_Tiles[row+1][col].level > bp->level) { Set_Tile_Draw( row+1, col ); } /*--Redraw anyone below-to-the-left of us. */ if (row < 7 && col > 0 && Board_Tiles[row+1][col-1].level > 0) { Set_Tile_Draw( row+1, col-1 ); } /*--Redraw anyone above-to-the-left of us that has a level greater than ours * because their tile-face overlaps our tile-edge. */ if (row > 0 && col > 0 && Board_Tiles[row-1][col-1].level != bp->level) { Set_Tile_Draw( row-1, col-1 ); } /*--If we are certain specific tiles then we may need to set specific other * tiles. */ if (row == 3 || row == 4) { if (col == 6 || col == 7) { Set_Tile_Draw( SPEC4row, SPEC4col ); } else if (col == 1) { Set_Tile_Draw( SPEC3row, SPEC3col ); } } DEBUG_RETURN(Set_Tile_Draw); } /* Set_Tile_Draw */ \f static void Remove_Tile( bp, row, col ) register Board_Position bp; int row; int col; /****************************************************************************** * Called to remove the top tile of the indicated Board_Position. ******************************************************************************/ { /*--If the tile just went away then clear the area and allow the window * background to shine through. */ DEBUG_CALL(Remove_Tiles); if (bp->level == 1) { if (Tile_Control & SHADOW) { XClearArea( XtDisplay(Board), XtWindow(Board), bp->x, bp->y - Side_Y - Shadow_Y, Tile_Width + Side_X + 2 + Shadow_X, Tile_Height + Side_Y + 2 + Shadow_Y, FALSE ); } else { XClearArea( XtDisplay(Board), XtWindow(Board), bp->x, bp->y - Side_Y, Tile_Width + Side_X + 2, Tile_Height + Side_Y + 2, FALSE ); } } else { int sidex = Side_X * bp->level; int sidey = Side_Y * bp->level; if (Tile_Control & SHADOW) { XClearArea( XtDisplay(Board), XtWindow(Board), bp->x + sidex, bp->y - sidey - Shadow_Y, Tile_Width + 2 + Shadow_X, Tile_Height+ 2 + Shadow_Y, FALSE ); } else { XClearArea( XtDisplay(Board), XtWindow(Board), bp->x + sidex, bp->y - sidey, Tile_Width + 2, Tile_Height+ 2, FALSE ); } Set_Tile_Draw( row, col ); } --bp->level; /*--Schedule the surrounding tiles for redrawing. */ if (col == SPEC1col) { if (row == SPEC4row) { Set_Tile_Draw( 3, 6 ); Set_Tile_Draw( 3, 7 ); Set_Tile_Draw( 4, 6 ); Set_Tile_Draw( 4, 7 ); return; } else if (row == SPEC3row) { Set_Tile_Draw( 3, 1 ); Set_Tile_Draw( 4, 1 ); return; } else if (row == SPEC2row) { Set_Tile_Draw( SPEC1row, SPEC1col ); Set_Tile_Draw( 3, 12 ); Set_Tile_Draw( 4, 12 ); return; } else { Set_Tile_Draw( SPEC2row, SPEC2col ); Set_Tile_Draw( 3, 12 ); Set_Tile_Draw( 4, 12 ); return; } } if (col == 1 && (row == 3 || row == 4)) { Set_Tile_Draw( SPEC3row, SPEC3col ); } if (col == 12 && (row == 3 || row == 4)) { Set_Tile_Draw( SPEC2row, SPEC2col ); } if (row > 0) { Set_Tile_Draw( row - 1, col + 1 ); Set_Tile_Draw( row - 1, col ); if (col > 0 && Board_Tiles[row-1][col].level == 0) { Set_Tile_Draw( row - 1, col - 1 ); } } Set_Tile_Draw( row, col+1 ); if (col > 0) { Set_Tile_Draw( row, col - 1 ); } if (row < 7) { Set_Tile_Draw( row + 1, col ); if (col > 0) { Set_Tile_Draw( row + 1, col - 1 ); } } DEBUG_RETURN(Remove_Tile); } /* Remove_Tile */ \f static void Touch_Tile( bp, row, col, event ) register Board_Position bp; register XButtonEvent *event; /****************************************************************************** * Called when we click on a specific tile. We decide what to do. For a * single click we hilite the tile unless we already have two tiles hilited. * For a "double" click with two tiles hilited we will remove both of the * tiles. ******************************************************************************/ { /*--If there is no Click1 then this guy becomes it. */ DEBUG_CALL(Touch_Tile); if (Click1 == Board_Position_NULL) { Click1 = bp; Click1_Row = row; Click1_Col = col; Hilite_Tile( row, col ); DEBUG_RETURN(Touch_Tile); return; } /*--If there is no Click2 then this guy becomes it unless he is already Click1. */ if (Click1 != bp) { if (Click2_Row == row && Click2_Col == col && Click2_Time + Dragon_Resources.Double_Click_Time >= event->time) { Click2 = bp; } if( Click2 == Board_Position_NULL) { Click2 = bp; Click2_Row = row; Click2_Col = col; Click2_Time = event->time; Hilite_Tile( row, col ); DEBUG_RETURN(Touch_Tile); return; } /*--If this guy is not one Click1 and not Click2 then we have an error. */ if (Click2 != bp) { XBell( XtDisplay(Board), 0 ); DEBUG_RETURN(Touch_Tile); return; } } /*--If he double-clicks then remove both tiles. */ if (Click2 != Board_Position_NULL && Click2_Time + Dragon_Resources.Double_Click_Time >= event->time) { One_Button_Hint = FALSE; Remove_Tile( Click1, Click1_Row, Click1_Col ); Click1 = Board_Position_NULL; Remove_Tile( Click2, Click2_Row, Click2_Col ); Click2 = Board_Position_NULL; Score -= 2; Draw_All_Tiles(); DEBUG_RETURN(Touch_Tile); return; } /*--2nd click on any tile means turn-it-off. */ if (Click1 == bp) { int s; Hilite_Tile( Click1_Row, Click1_Col ); Click1 = Click2; s = Click1_Row; Click1_Row = Click2_Row; Click2_Row = s; s = Click1_Col; Click1_Col = Click2_Col; Click2_Col = s;; Click2 = Board_Position_NULL; } else { Click2 = Board_Position_NULL; Hilite_Tile( Click2_Row, Click2_Col ); } Click2_Time = event->time; DEBUG_RETURN(Touch_Tile); } /* Touch_Tile */ \f /*ARGSUSED*/ void Tile_Remove( w, event, params, num_params ) Widget w; XButtonEvent *event; String *params; Cardinal *num_params; /****************************************************************************** * Called when the remove-selected-tile-pair mouse button is pressed. ******************************************************************************/ { DEBUG_CALL(Tile_Remove); if (Click1 != Board_Position_NULL && Click2 != Board_Position_NULL) { Click2_Time = event->time; Touch_Tile( Click2, Click2_Row, Click2_Col, event ); } DEBUG_RETURN(Tile_Remove); } /* Tile_Remove */ \f static Boolean Touch( bp, event ) register Board_Position bp; register XButtonEvent *event; /****************************************************************************** * Return TRUE if this XButtonEvent touched this Board_Position. ******************************************************************************/ { int face_x = bp->x + bp->level * Side_X; int face_y = bp->y - bp->level * Side_Y; /*--Does this tile exist? */ DEBUG_CALL(Touch); if (bp->level == 0) { DEBUG_RETURN(Touch); return FALSE; } /*--Did we touch the face? */ if (event->x >= face_x && event->x <= face_x + Tile_Width + 1 && event->y >= face_y && event->y <= face_y + Tile_Height + 1) { DEBUG_RETURN(Touch); return TRUE; } /*--Did we touch the side? */ if (event->x >= bp->x && event->x <= bp->x + Tile_Width + 1 && event->y >= bp->y && event->y <= bp->y + Tile_Height + 1) { DEBUG_RETURN(Touch); return TRUE; } /*--Guess not. */ DEBUG_RETURN(Touch); return FALSE; } /* Touch */ \f /*ARGSUSED*/ void Tile_Press( w, event, params, num_params ) Widget w; register XButtonEvent *event; String *params; Cardinal *num_params; /****************************************************************************** * Called when the Board receives a BtnDown event. ******************************************************************************/ { register Board_Position bp; int x; int y; int row; int col; /*--Figure out a rough row/col coordinate for the click. */ DEBUG_CALL(Tile_Press); y = event->y - Board_Tile0_Y; if (y < 0) { return; } row = y / (Tile_Height + 1); if (row > 7) { return; } x = event->x - Board_Tile0_X; if (x < 0) { return; } col = x / (Tile_Width + 1); if (col < 0 || row > 14) { goto Touched; } /*--See if we are a special tile. */ if (col == 0) { if (Touch( bp = &Board_Tiles[SPEC3], event )) { Touch_Tile( bp, SPEC3row, SPEC3col, event ); goto Touched; } goto Touched; } else if (col == 13) { if (Touch( bp = &Board_Tiles[SPEC2], event )) { Touch_Tile( bp, SPEC2row, SPEC2col, event ); goto Touched; } if (Touch( bp = &Board_Tiles[4][12], event )) { Touch_Tile( bp, 4, 12, event ); goto Touched; } if (Touch( bp = &Board_Tiles[3][12], event )) { Touch_Tile( bp, 3, 12, event ); goto Touched; } goto Touched; } else if (col == SPEC1col) { if (Touch( bp = &Board_Tiles[SPEC1], event )) { Touch_Tile( bp, SPEC1row, SPEC1col, event ); goto Touched; } if (Touch( bp = &Board_Tiles[SPEC2], event )) { Touch_Tile( bp, SPEC2row, SPEC2col, event ); goto Touched; } goto Touched; } else if ((row == 3 || row == 4) && (col == 6 || col == 7)) { if (Touch( bp = &Board_Tiles[SPEC4], event )) { Touch_Tile( bp, SPEC4row, SPEC4col, event ); goto Touched; } } /*--See if the x/y falls exactly into somebody else's tile face. */ if (col > 0 && row < 7) { if (Touch( bp = &Board_Tiles[row+1][col-1], event )) { Touch_Tile( bp, row+1, col-1, event ); goto Touched; } } if (row < 7) { if (Touch( bp = &Board_Tiles[row+1][col], event )) { Touch_Tile( bp, row+1, col, event ); goto Touched; } } if (col > 0) { if (Touch( bp = &Board_Tiles[row][col-1], event )) { Touch_Tile( bp, row, col-1, event ); goto Touched; } } /*--We don't have a touch on a neighbor so it must be us. */ if (Touch( bp = &Board_Tiles[row][col], event )) { Touch_Tile( bp, row, col, event ); goto Touched; } Touched : DEBUG_RETURN(Tile_Press); } /* Tile_Press */ \f static Boolean Tile_Not_Free( row, col ) int row; int col; /****************************************************************************** * Returns TRUE if the tile has neither a left nor a right side free. ******************************************************************************/ { /*--The 4 in the center can be covered by SPEC4. */ if (row == 3 || row == 4) { if ((col == 6 || col == 7) && Board_Tiles[SPEC4].level > 0) { return TRUE; } else if (col == 1 && Board_Tiles[SPEC3].level > 0 && Board_Tiles[row][col+1].level > 0) { return TRUE; } else if (col == 12 && Board_Tiles[SPEC2].level > 0 && Board_Tiles[row][col-1].level > 0) { return TRUE; } } /*--If a tile has a neighbor then he isn't free. */ if (Board_Tiles[row][col-1].level >= Board_Tiles[row][col].level && Board_Tiles[row][col+1].level >= Board_Tiles[row][col].level) { return TRUE; } /*--Check the special tiles. */ if (col == SPEC1col) { /*--Tiles 1, 3, and 4 are always free. */ if (row != SPEC2row) { return FALSE; } /*--Tile 2 is free if tile 1 is gone or if its two normal neighbors are gone.*/ if (Board_Tiles[SPEC1].level > 0 && (Board_Tiles[3][12].level > 0 || Board_Tiles[4][12].level > 0)) { return TRUE; } } return FALSE; } /* Tile_Not_Free */ \f /*ARGSUSED*/ void Tile_Release( w, event, params, num_params ) Widget w; XEvent *event; String *params; Cardinal *num_params; /****************************************************************************** * Called when the Board receives a BtnUp event. ******************************************************************************/ { extern int Cheating; /*--If there is a Click2 and if the tile type does not match with Click1 then * unhilite Click2. */ DEBUG_CALL(Tile_Release); if (!Cheating && Click1 != Board_Position_NULL && Click2 != Board_Position_NULL) { int tile1, tile2; tile1 = Click1->tiles[Click1->level-1]; tile2 = Click2->tiles[Click2->level-1]; if (/* Do tile faces match for those types that must match exactly? */ ((tile1 > 8 || tile2 > 8) && tile1 != tile2) || /* Are both tiles seasons? */ (tile1 <= 4 && tile2 > 4) || /* Are both tiles flowers? */ (tile1 >= 5 && tile1 <= 8 && (tile2 < 5 || tile2 > 8))) { /* They don't match. */ if (Dragon_Resources.Sticky_Tile) { /* Simply remove tile 2 from selected tiles. */ Hilite_Tile( Click2_Row, Click2_Col ); } else { /* Remove tile 1 from selection and make tile 2 => tile 1.*/ Hilite_Tile( Click1_Row, Click1_Col ); Click1 = Click2; Click1_Row = Click2_Row; Click1_Col = Click2_Col; Click2_Col = 0; /* Prevent dbl-clk removing 1 tile. */ } Click2 = Board_Position_NULL; Click2_Time = 0; } } /*--If this tile has a left or a right neighbor then he isn't allowed. */ if (!Cheating) { if (Click2 != Board_Position_NULL && Tile_Not_Free( Click2_Row, Click2_Col)) { Hilite_Tile( Click2_Row, Click2_Col ); Click2 = Board_Position_NULL; Click2_Time = 0; } if (Click1 != Board_Position_NULL && Tile_Not_Free( Click1_Row, Click1_Col)) { Hilite_Tile( Click1_Row, Click1_Col ); Click1 = Board_Position_NULL; } } DEBUG_RETURN(Tile_Release); } /* Tile_Release */ \f static void Next_Tile( Click, row, col ) int Click; int *row; int *col; /****************************************************************************** * Returns the "next" tile past row/col that exists and is "free". Returns 0,0 * when we run out of tiles. ******************************************************************************/ { int tile1, tile2; /*--Loop until we give up. Advance the column. Advance the row on column * overflow. Give up on row overflow. */ DEBUG_CALL(Next_Tile); for (;;) { ++*col; if (*col > 14) { *col = 1; ++*row; if (*row > 7) { *row = 0; *col = 0; break; } } /*--Check this tile. If it doesn't exist or isn't free then ignore it. */ if (Board_Tiles[*row][*col].level == 0) { continue; } if (Tile_Not_Free( *row, *col )) { continue; } /*--If moving Click1 then return now. */ if (Click == 1) { break; } /*--Continue the search if this tile does not match Click1. */ tile1 = Click1->tiles[Click1->level-1]; tile2 = Board_Tiles[*row][*col].tiles[Board_Tiles[*row][*col].level-1]; if (/* Do tile faces match for those types that must match exactly? */ ((tile1 > 8 || tile2 > 8) && tile1 != tile2) || /* Are both tiles seasons? */ (tile1 <= 4 && tile2 > 4) || /* Are both tiles flowers? */ (tile1 >= 5 && tile1 <= 8 && (tile2 < 5 || tile2 > 8))) { /* They don't match. */ continue; } break; } DEBUG_RETURN(Next_Tile); } /* Next_Tile */ \f /*ARGSUSED*/ void Hints( w, event, params, num_params ) Widget w; XButtonEvent *event; String *params; Cardinal *num_params; /****************************************************************************** * If Click1 not present then search for the "first" remaining tile otherwise * use Click1 as our current "base" tile. * If Click1 present but not Click2 then search for any match for Click1. * If Click2 not present either then search for the first remaining tile past * Click1 otherwise search for the first remaining tile past Click2. * Keep searching for a new Click2 until we hit a matching tile or until we * run out. Exit on match with new tile as Click2. * Advance Click1 and start a new search for Click2. If we run out on Click1 * then remove Click1. ******************************************************************************/ { /*--If we have a Click1 but no Click2 then search for a Click2. */ if (Click1 != Board_Position_NULL && Click2 == Board_Position_NULL) { One_Button_Hint = TRUE; Click2_Row = 0; Click2_Col = 0; for (;;) { Next_Tile( 2, &Click2_Row, &Click2_Col ); if (Click2_Col == 0) { One_Button_Hint = FALSE; Hilite_Tile( Click1_Row, Click1_Col ); Click1 = Board_Position_NULL; DEBUG_RETURN(Hints); return; } if (Click2_Row != Click1_Row || Click2_Col != Click1_Col) { Click2 = &Board_Tiles[Click2_Row][Click2_Col]; Hilite_Tile( Click2_Row, Click2_Col ); DEBUG_RETURN(Hints); return; } } } /*--Find a Click1 to work with if we don't already have one. */ DEBUG_CALL(Hints); if (Click1 == Board_Position_NULL) { Click1_Row = 0; Click1_Col = 0; Next_Tile( 1, &Click1_Row, &Click1_Col ); if (Click1_Col == 0) { DEBUG_RETURN(Hints); return; } Hilite_Tile( Click1_Row, Click1_Col ); Click1 = &Board_Tiles[Click1_Row][Click1_Col]; } /*--Find our starting position for Click2 if we don't have one. */ if (Click2 == Board_Position_NULL) { Click2_Row = Click1_Row; Click2_Col = Click1_Col; } else { Hilite_Tile( Click2_Row, Click2_Col ); Click2 = Board_Position_NULL; } /*--Loop until we get something. */ for (;;) { Next_Tile( 2, &Click2_Row, &Click2_Col ); if (Click2_Col != 0) { if (Click2_Row != Click1_Row || Click2_Col != Click1_Col) { Click2 = &Board_Tiles[Click2_Row][Click2_Col]; Hilite_Tile( Click2_Row, Click2_Col ); DEBUG_RETURN(Hints); return; } } else { Hilite_Tile( Click1_Row, Click1_Col ); Click1 = Board_Position_NULL; if (One_Button_Hint) { One_Button_Hint = FALSE; return; } Next_Tile( 1, &Click1_Row, &Click1_Col ); if (Click1_Col == 0) { DEBUG_RETURN(Hints); return; } Hilite_Tile( Click1_Row, Click1_Col ); Click1 = &Board_Tiles[Click1_Row][Click1_Col]; Click2_Row = Click1_Row; Click2_Col = Click1_Col; } } } /* Hints */