예제 #1
0
파일: mahjong.c 프로젝트: emulvaney/mahjong
void makeMove(Piece *p1, Piece *p2)
{
  p1->mode = NORMAL; moves[n_moves++] = *p1; p1->value = BLANK;
  p2->mode = NORMAL; moves[n_moves++] = *p2; p2->value = BLANK;
  updatePiece(p1);
  updatePiece(p2);
  n_pairs_remaining--;
  giveHelp(0);
}
예제 #2
0
파일: mahjong.c 프로젝트: emulvaney/mahjong
void undoMove()
{
  if(n_moves)
  {
    Piece *p1 = &moves[--n_moves];
    Piece *p2 = &moves[--n_moves];
    board[p1->x][p1->y][p1->z].value = p1->value;
    board[p2->x][p2->y][p2->z].value = p2->value;
    selectPiece(NULL);
    updatePiece(p1);
    updatePiece(p2);
    n_pairs_remaining++;
  }
}
예제 #3
0
void Position::undoMove() {
	Move theMove;
	theMove = movesMade.list[movesMade.totalMoves - 1];
	toMove = -toMove;

	//Move piece back
	board[theMove.fromSpace] = theMove.piece;
	updatePiece(theMove.toSpace, theMove.fromSpace, toMove);

	//If a piece was captured, put it back, you!
	if (theMove.capture != 0) {
		//If it was an en passant capture
		if (theMove.enPassant) {
			board[theMove.toSpace + 10*toMove] = -PAWN*toMove;
			addPiece(theMove.toSpace +10*toMove, -toMove);
			board[theMove.toSpace] = EMPTY;
		}
		else {
			board[theMove.toSpace] = theMove.capture;
			addPiece(theMove.toSpace, -toMove);
		}
	}
	else board[theMove.toSpace] = EMPTY;

	//reupdate king positions
	if (abs(theMove.piece) == KING){
		if (theMove.piece == KING) whiteKing = theMove.fromSpace;
		else blackKing = theMove.fromSpace;
	}

	if (theMove.castle != 0) {
		if (toMove == WHITE) {
			if (theMove.castle == 1) {
				board[96] = EMPTY; board[98] = ROOK;
				updatePiece(96, 98, WHITE);
			}
			else {
				board[94] = EMPTY; board[91] = ROOK;
				updatePiece(94, 91, WHITE);
			}
		}
		else {
			if (theMove.castle == 1) {
				board[26] = EMPTY; board[28] = -ROOK;
				updatePiece(26, 28, BLACK);
			}
			else {
				board[24] = EMPTY; board[21] = -ROOK;
				updatePiece(24, 21, BLACK);
			}
		}
	}

	if (toMove == BLACK) totalMoves--;
	halfMoves--;
	castleWK = WKhistory[halfMoves];
	castleBK = BKhistory[halfMoves];
	castleWQ = WQhistory[halfMoves];
	castleBQ = BQhistory[halfMoves];
	enPassant = enPassantHistory[halfMoves];
	fiftyMove = fiftyMoveHistory[halfMoves];
	hash = hashHistory[halfMoves];

	movesMade.remove_last();
}
예제 #4
0
bool Position::doMove(Move &theMove) {
	
	//save history
	updateHistory();

	//First up: move the piece on the board, update piecelist
	board[theMove.toSpace] = theMove.piece;
	board[theMove.fromSpace] = EMPTY;
	updatePiece(theMove.fromSpace, theMove.toSpace, toMove);
	updatePieceHash(theMove.fromSpace, theMove.toSpace, theMove.piece);

	//If it is a capture, let's delete the dead guy from the proper piecelist
	if (theMove.capture != 0) {
		//For enpassant captures
		if(theMove.enPassant == true) {
			removePiece(enPassant + 10*toMove, -toMove);
			updatePieceHash(enPassant + 10*toMove, 0, theMove.capture);
			board[enPassant + 10*toMove] = EMPTY;
		}
		else {
			removePiece(theMove.toSpace, -toMove);
			updatePieceHash(theMove.toSpace, 0, theMove.capture);
		}

		//If a rook is captured, update castle info.
		if(abs(theMove.capture) == ROOK) {
			if (castleWK && theMove.toSpace == 98) {
				castleWK = false;
				hash = hash ^ castleKeys[0];
			}
			else if (castleWQ && theMove.toSpace == 91) {
				castleWQ = false;
				hash = hash ^ castleKeys[1];
			}
			else if (castleBK && theMove.toSpace == 28) {
				castleBK = false;
				hash = hash ^ castleKeys[2];
			}
			else if (castleBQ && theMove.toSpace == 21) {
				hash = hash ^ castleKeys[3];
				castleBQ = false;
			}
		}
	}

	//Speaking of en passant captures...
	if (enPassant != 0) hash = hash ^ enpassantKeys[enPassant%10 - 1];
	if (theMove.jump) {
		enPassant = theMove.fromSpace - 10*toMove;
		hash = hash ^ enpassantKeys[enPassant%10 - 1];
	}
	else enPassant = 0;

	//For promotions, we must bring a piece to LIFE!
	if (theMove.promotion != 0) {
		board[theMove.toSpace] = theMove.promotion*toMove;
		updatePieceHash(0, theMove.toSpace, theMove.promotion*toMove);
		updatePieceHash(theMove.toSpace, 0, theMove.piece);
	}
	
	//Castling. Hooray. Move the rooks, update piecelists.
	if (theMove.castle != 0) {
		if (theMove.castle == 1) {
			if (toMove == WHITE) {
				board[98] = EMPTY; board[96] = ROOK;
				updatePiece(98, 96, WHITE);
				updatePieceHash(98, 96, ROOK);
			}
			else {
				board[28] = EMPTY; board[26] = -ROOK;
				updatePiece(28, 26, BLACK);
				updatePieceHash(28, 26, -ROOK);
			}
		}
		else {
			if (toMove == WHITE) {
				board[91] = EMPTY; board[94] = ROOK;
				updatePiece(91, 94, WHITE);
				updatePieceHash(91, 94, ROOK);
			}
			else {
				board[21] = EMPTY; board[24] = -ROOK;
				updatePiece(21, 24, BLACK);
				updatePieceHash(21, 24, -ROOK);
			}
		}
	}

	//Update king locations
	if (abs(theMove.piece) == KING) {
		if (toMove == WHITE) {
			whiteKing = theMove.toSpace;
			if (castleWK) {
				castleWK = false; 
				hash = hash ^ castleKeys[0];
			}
			if (castleWQ) {
				castleWQ = false;
				hash = hash ^ castleKeys[1];
			}
		}
		else {
			blackKing = theMove.toSpace;
			if (castleBK) {
				castleBK = false;
				hash = hash ^ castleKeys[2];
			}
			if (castleBQ) {
				castleBQ = false;
				hash = hash ^ castleKeys[3];
			}
		}
	}

	//Update castling rights for rook moves
	if (theMove.piece == ROOK) {
		if (theMove.fromSpace == 91 && castleWQ) {
			castleWQ = false;
			hash = hash ^ castleKeys[1];
		}
		else if (theMove.fromSpace == 98 && castleWK){
			castleWK = false;
			hash = hash ^ castleKeys[0];
		}
	}
	else if (theMove.piece == -ROOK) {
		if (theMove.fromSpace == 21 && castleBQ){
			castleBQ = false;
			hash = hash ^ castleKeys[3];
		}
		else if (theMove.fromSpace == 28 && castleBK){
			castleBK = false;
			hash = hash ^ castleKeys[2];
		}
	}

	//Adjust fifty move rule counter
	if (abs(theMove.piece) == PAWN || theMove.capture != 0) fiftyMove = 0;
	else fiftyMove++;

	if (toMove == BLACK) totalMoves++;
	halfMoves++;
	bool check = inCheck();
	toMove = -toMove;
	hash = hash ^ blackKey;

	//update moves made and history
	movesMade.add(theMove);
	return check;
}
예제 #5
0
파일: mahjong.c 프로젝트: emulvaney/mahjong
int main(int argc, char *argv[])
{
  {
    int i;

    if((argc - 1) % 2)
      goto help;

    for(i = 1; i < argc - 1; i += 2)
      if(!editing && (!strcmp(argv[i], "-e") || !strcmp(argv[i], "--edit")))
	editing = argv[i+1];
      else if(!layout_title[0] && (!strcmp(argv[i], "-t") || !strcmp(argv[i], "--title")))
      {
	bzero(layout_title, 55);
	strncpy(layout_title, argv[i+1], 54);
      }
      else
      {
help:
	printf("usage: mahjong [--edit <layout> [--title <layout title>]]\n");
	return 0;
      }
  }

  srand(time(NULL));
  allegro_init();

  {
    int x, y, z;
    for(x = 16; x--;)
    for(y =  9; y--;)
    for(z =  3; z--;)
      pieceInit(board[x][y][z], x, y, z);
  }

  set_color_depth(SCREEN_DEPTH);

  if(set_gfx_mode(GFX_AUTODETECT_WINDOWED,
      SCREEN_WIDTH,   SCREEN_HEIGHT,
      SCREEN_WIDTH*2, SCREEN_HEIGHT) < 0)
  {
    fprintf(stderr, "fatal: %s\n", allegro_error);
    exit(1);
  }

#ifdef ALLEGRO_WINDOWS
  set_display_switch_callback(SWITCH_IN, update);
#endif

  left_view =
    create_sub_bitmap(screen, 0, 0, SCREEN_WIDTH, SCREEN_HEIGHT);
  right_view =
    create_sub_bitmap(screen, SCREEN_WIDTH, 0, SCREEN_WIDTH, SCREEN_HEIGHT);

  // init colors
    BACKGROUND_COLOR = makecol32(0x2F, 0x5F, 0x2F); // soft green
      SELECTED_COLOR = makecol32(0x00, 0xDF, 0x00); // green
  OLD_SELECTED_COLOR = makecol32(0x00, 0xBF, 0xBF); // cyan

  // load data
  {
    DATAFILE *data = load_datafile("#");
    new_game   = data[NEW_GAME_BMP].dat;
    undo       = data[UNDO_BMP].dat;
    help       = data[HELP_BMP].dat;
    quit       = data[QUIT_BMP].dat;
    tile       = data[TILE_BMP].dat;
    number[ 0] = data[BLACK1_BMP].dat;
    number[ 2] = data[BLACK2_BMP].dat;
    number[ 4] = data[BLACK3_BMP].dat;
    number[ 6] = data[BLACK4_BMP].dat;
    number[ 8] = data[BLACK5_BMP].dat;
    number[10] = data[BLACK6_BMP].dat;
    number[12] = data[BLACK7_BMP].dat;
    number[14] = data[BLACK8_BMP].dat;
    number[16] = data[BLACK9_BMP].dat;
    number[ 1] = data[RED1_BMP].dat;
    number[ 3] = data[RED2_BMP].dat;
    number[ 5] = data[RED3_BMP].dat;
    number[ 7] = data[RED4_BMP].dat;
    number[ 9] = data[RED5_BMP].dat;
    number[11] = data[RED6_BMP].dat;
    number[13] = data[RED7_BMP].dat;
    number[15] = data[RED8_BMP].dat;
    number[17] = data[RED9_BMP].dat;
    suit[0]    = data[SPADE_BMP].dat;
    suit[1]    = data[CLUB_BMP].dat;
    suit[2]    = data[DIAMOND_BMP].dat;
    suit[3]    = data[HEART_BMP].dat;
    layouts[0] = data[BLOCK_LYT].dat;
    layouts[1] = data[FLAT_LYT].dat;
    layouts[2] = data[FROGGER_LYT].dat;
    layouts[3] = data[PRECIOUS_LYT].dat;
    layouts[4] = data[PTRAD_LYT].dat;
    layouts[5] = data[PYRAMID_LYT].dat;
    layouts[6] = data[STEPS_LYT].dat;
    layouts[7] = data[THETA_LYT].dat;
  }

  scroll_screen(SCREEN_WIDTH, 0);
  current_view = right_view;

  install_timer();
  install_mouse();
  install_keyboard();
  show_mouse(current_view);

  text_mode(BACKGROUND_COLOR);

  if(!editing)
  {
    defaultLayout();

    if(alert("Our Own Version of Mahjong Solitaire, v0.1.4", NULL,
	     "Copyright (c) 2001 Eric Mulvaney, Michelle Bondy",
	     "Play", "Edit", 0, 0) == 2
	&& file_select_ex("Please select layout file to edit:", path, "lyt",
	    PATH_LENGTH-1, OLD_FILESEL_WIDTH, OLD_FILESEL_HEIGHT))
    {
      int x, y, z;

      editing = path;

      for(x = 16; x--;)
      for(y =  9; y--;)
      for(z =  3; z--;)
	board[x][y][z].value = EMPTY;
    }
  }

  mouse_callback = editing ? mouse_handler_for_editing : mouse_handler;

  if(editing)
  {
    Layout data;
    FILE *file = fopen(editing, "r");

    if(file)
    {
      if(fread(&data, sizeof(Layout), 1, file))
      {
	int x, y, z;

	if(!layout_title[0])
	  memcpy(layout_title, data.title, 55);

	for(x = 16; x--;)
	for(y =  9; y--;)
	for(z = (data.board[x][y] > 3) ? 3 : data.board[x][y]; z--;)
	{
	  board[x][y][z].value = BLANK;
	  if(!--n_pieces_left)
	    goto skip;
	}
      }
skip:
      fclose(file);
    }

    update();
  }

  click_ready = 0;
  while(1) // game loop
  {
    if(click_ready)
    {
      int x = click_x - (BOARD_XOFF - 2 * EDGE_WIDTH );
      int y = click_y - (BOARD_YOFF - 2 * EDGE_HEIGHT);
      int z;

      for(z = 3; x > 0 && y > 0 && z--; x -= EDGE_WIDTH, y -= EDGE_HEIGHT)
      {
	int i = x / FACE_WIDTH;
	int j = y / FACE_HEIGHT;

	if(i >= 16 || j >= 9)
	  continue;

	if(editing)
	{
	  if(click_ready == 1 && board[i][j][z].value == EMPTY)
	  {
	    if((z == 0 || board[i][j][z-1].value != EMPTY) && n_pieces_left)
	    {
	      n_pieces_left--;
	      board[i][j][z].value = BLANK;
	      updatePiece(&board[i][j][z]);
	      goto event_handled;
	    }
	  }
	  else if(click_ready == 2 && board[i][j][z].value != EMPTY)
	  {
	    if(z == 2 || board[i][j][z+1].value == EMPTY)
	    {
	      board[i][j][z].value = EMPTY;
	      n_pieces_left++;
	      updatePiece(&board[i][j][z]);
	      goto event_handled;
	    }
	  }
	}
	else if(selectPiece(&board[i][j][z]))
	{
	  if(!n_pairs_remaining)
	  {
	    if(current_view != left_view)
	      update();

	    if(alert("Congratulations!	You won!",
		     "Play another?",
		     NULL, "Yes", "No", 0, 0) == 1)
	      newGame();
	    else
	      return 0;
	  }

	  goto event_handled;
	}
      }

      if(click_y < BUTTON_YOFF + BUTTON_HEIGHT && click_y > BUTTON_YOFF)
      {
	if(editing)
	{
	  if(click_x > NEW_GAME_BUTTON_X1 && click_x < NEW_GAME_BUTTON_X2)
	  {
	    if(n_pieces_left == 144)
	      goto event_handled;

	    if(current_view != left_view)
	      update();

	    if(alert("Are you sure you want to clear the current Layout?",
		     NULL, NULL, "Yes", "No", 0, 0) == 1)
	    {
	      int x, y, z;
	      for(x = 16; x--;)
	      for(y =  9; y--;)
	      for(z =  3; z--;)
		board[x][y][z].value = EMPTY;
	      n_pieces_left = 144;
	      update();
	    }
	  }
	  else if(click_x > QUIT_BUTTON_X1 && click_x < QUIT_BUTTON_X2)
	  {
	    int ync;

	    if(current_view != left_view)
	      update();

	    if(n_pieces_left)
	      ync = alert3("WARNING: Layout is incomplete.",
			   NULL,
			   "Do you wish to save before exiting?",
			   "Yes", "No", "Cancel", 0, 0, 0);
	    else
	      ync = alert3("Do you wish to save before exiting?",
		    NULL, NULL, "Yes", "No", "Cancel", 0, 0, 0);

	    if(ync == 2)
	      return 0;
	    else if(ync == 1)
	    {
	      Layout data;
	      FILE *file;

	      memcpy(data.title, layout_title, 55);

	      data.complete = (n_pieces_left) ? 0 : 1;

	      if((file = fopen(editing, "w")))
	      {
		for(x = 16; x--;)
		for(y =  9; y--;)
		{
		  if	 (board[x][y][2].value == BLANK) data.board[x][y] = 3;
		  else if(board[x][y][1].value == BLANK) data.board[x][y] = 2;
		  else if(board[x][y][0].value == BLANK) data.board[x][y] = 1;
		  else					 data.board[x][y] = 0;
		}

		if(fwrite(&data, sizeof(Layout), 1, file))
		{
		  fclose(file);
		  return 0;
		}
		else
		  fclose(file);
	      }

	      if(alert("WARNING: Save failed!",
		       NULL,
		       "Do you still wish to exit?",
		       "Yes", "No", 0, 0) == 1)
		return 0;
	    }
	  }
	}
	else if(click_x > NEW_GAME_BUTTON_X1 && click_x < NEW_GAME_BUTTON_X2)
	  newGame();
	else if(click_x > UNDO_BUTTON_X1 && click_x < UNDO_BUTTON_X2)
	  undoMove();
	else if(click_x > HELP_BUTTON_X1 && click_x < HELP_BUTTON_X2)
	  giveHelp(1);
	else if(click_x > QUIT_BUTTON_X1 && click_x < QUIT_BUTTON_X2)
	{
	  if(current_view != left_view)
	    update();

	  if(alert("Are you sure you want to quit?",
	      NULL, NULL, "Yes", "No", 0, 0) == 1)
	    return 0;
	}
      }

event_handled:

      click_ready = 0;
    }
    else
      rest(100);
  }

  return 0;
}
예제 #6
0
파일: mahjong.c 프로젝트: emulvaney/mahjong
int selectPiece(Piece *p)
{
  static Piece *s1 = NULL, *s2 = NULL;

  if(!p) // reset
  {
    if(s1) { s1->mode = NORMAL; updatePiece(s1); s1 = NULL; }
    if(s2) { s2->mode = NORMAL; updatePiece(s2); s2 = NULL; }
    return 0;
  }

  if(p->value >= EMPTY
     || (p->x > 0 && p->x < 15
	  && board[p->x-1][p->y][p->z].value < EMPTY
	  && board[p->x+1][p->y][p->z].value < EMPTY)
     || (p->z < 2
	  && board[p->x][p->y][p->z+1].value < EMPTY))
    return 0;

  if(!s1)
  {
    s1 = p;
    s1->mode = SELECTED;
    updatePiece(s1);
  }
  else if(p == s1)
  {
    s1->mode = NORMAL;
    if(s2)
    {
      s2->mode = SELECTED;
      updatePiece(s2);
    }
    updatePiece(s1);
    s1 = s2;
    s2 = NULL;
  }
  else if(pieceMatch(*p, *s1))
  {
    if(s2)
    {
      s2->mode = SELECTED;
      updatePiece(s2);
    }
    makeMove(p, s1);
    s1 = s2;
    s2 = NULL;
  }
  else
  {
     p->mode = SELECTED;
    s1->mode = OLD_SELECTED;
    if(s2 && p != s2)
    {
      s2->mode = NORMAL;
      updatePiece(s2);
    }
    updatePiece(p);
    updatePiece(s1);
    s2 = s1;
    s1 = p;
  }

  return 1;
}