天天看點

C++五子棋(三)——判斷滑鼠有效點選

分析

在滑鼠左鍵點選時,我們不能讓新棋子在已有棋子的位置落下,同時我們還要讓棋子在規定位置落下——棋盤線的交點處。

功能實作

建立資料類型

  • 建立頭檔案chessData.h和源檔案chessData.cpp
  • 在chessData.cpp和main.cpp中分别引用頭檔案chessData.h
  • 将之前在main.cpp中寫的棋盤資料剪貼到chessData.h中
const float BLOCKSIZE = 67.4;
const int BLOCK_GRAD_SIZE = 13;
           
  • 在chessData.h中定義常量 POS_OFFSET,即滑鼠有效點選距離上限
  • 在chessData.h定義結構體 ChessData
struct ChessData{
  //儲存目前遊戲棋盤的情況,空白為0,黑棋為1,白棋為-1
  int chessMap[BLOCK_GRAD_SIZE][BLOCK_GRAD_SIZE];
  //儲存各點的評分情況,用于之後的AI走棋
  int scoreMap[BLOCK_GRAD_SIZE][BLOCK_GRAD_SIZE];
  
  bool playFlag;	//表示下棋放,true黑棋,false白棋(AI)
  
};
           
  • 在main.cpp中添加全局變量game

初始化資料類型

  • 在chessData.h中添加函數聲明
  • 在chessData.cpp
void initChessData(ChessData *data){
  if(!data) return;
  memset(data->chessMap,0,sizeof(data->chessMap));
  memset(data->scoreMap,0,sizeof(data->scoreMap));
  data->playFlag = true;
  
}
           

判斷有效點選

算法原理

C++五子棋(三)——判斷滑鼠有效點選

實作

  • 在main.cpp中添加全局變量
  • 定義函數clickBoard()
//有效點選傳回true,無效點選傳回false
//MOUSEMSG為滑鼠資訊類型
bool clickBoard(MOUSEMSG msg){
  
  //(滑鼠點選坐标 - 邊界長度)/ 格寬 = 行(列)數
  
  //計算列數并取整
  int col = (msg.x - MARGIN_X) / BLOCKSIZE;
  //計算行數取整
  int row = (msg.y - MARGIN_Y) / BLOCKSIZE;
  
  //計算棋子正确坐标,即格子左上角棋子應在的棋盤格線交點處坐标
  int leftTopPosX = MARGIN_X + BLOCKSIZE * col;
  int leftTopPosY = MARGIN_Y + BLOCKSIZE * row;
  
  
}
           
  • 在檔案最上方引用頭檔案math.h用于後期計算
  • 之後要判斷棋子應在四個交點中具體哪一點上,這裡我們用一個do-while循環。繼續添加**clickBoard()**函數的定義
int len;	//用于計算兩點見的距離(根據中學所學兩點間距離公式)
int selectPos = false;	//作為傳回值

do{
  //左上角
  len = sqrt((msg.x - leftTopPosX)*(msg.x - leftTopPosX) + (y - leftTopPosY)*(msg.y - leftTopPosY));
  if(len < POS_OFFSET){
    clickPosRow = row;
    clickPosCol = col;
    if ( game.chessMap[clickPosRow][clickPosCol] == 0 ){
      selectPos = true;
    }
    break;
  }
  
  //右上角
  len = sqrt((msg.x - leftTopPosX - BLOCKSIZE)*(msg.x - leftTopPosX - BLOCKSIZE) + (y - leftTopPosY)*(msg.y - leftTopPosY));
  if(len < POS_OFFSET){
    clickPosRow = row;
    clickPosCol = col + 1;
    if ( game.chessMap[clickPosRow][clickPosCol] == 0 ){
      selectPos = true;
    }
    break;
  }
  
  //左下角
  len = sqrt((msg.x - leftTopPosX)*(msg.x - leftTopPosX) + (y - leftTopPosY - BLOCKSIZE)*(msg.y - leftTopPosY - BLOCKSIZE));
  if(len < POS_OFFSET){
    clickPosRow = row + 1;
    clickPosCol = col;
    if ( game.chessMap[clickPosRow][clickPosCol] == 0 ){
      selectPos = true;
    }
    break;
  }
  
  //右下角
  
  len = sqrt((msg.x - leftTopPosX - BLOCKSIZE)*(msg.x - leftTopPosX - BLOCKSIZE) + (y - leftTopPosY - BLOCKSIZE)*(msg.y - leftTopPosY - BLOCKSIZE));
  if(len < POS_OFFSET){
    clickPosRow = row + 1;
    clickPosCol = col + 1;
    if ( game.chessMap[clickPosRow][clickPosCol] == 0 ){
      selectPos = true;
    }
    break;
  }
  
  
}while(0);

return selectPos;
           

更新底層資料

  • chessData.h
  • chessData.cpp
void updateGameMap(ChessData* data, int row, int col){
  if(!data) return;
  
  if(data->playFlag){
    data->chessMap[row][col] = 1;
  }else{
    data->chessMap[row][col] = -1;
  }
  
  data->playFlag = !data->playFlag;	//換下棋方
  
}
           
  • main.cpp
//玩家走棋
void manGo(){
  chessDown(clickPosRow,clickPosCol,CHESS_BLACK);
  updateGameMap(&game, clickPosRow, clickPosCol);
  
}