十滴水游戏 C++ 源代码 - 我的一种实现

时间:2022-09-01 23:26:16

用一个链表保存所有的炸弹水滴列表,


x 轴从左到右 递增; y轴从上到下递增;


每次刷新所有炸弹的状态,如果和水滴碰撞了,则该炸弹消失,出现4个新水滴炸弹,将新炸弹用新链表存储,和老的炸弹链表合并,


为什么要用新链表来保存,stl的list不支持在遍历的时候插入新项


利用矩形和圆形是否相交 判断来判断相撞,水滴看做纯圆形


利用组合的次数和当前剩余的4滴水的数目作为评价剩余水滴局面好坏的标准



#ifndef _POS_H_


#define _POS_H_


struct Pos
{




Pos()
{
}

Pos( int iX, int iY ) : iXPos( iX ), iYPos( iY )  
{
}



int iXPos;

int iYPos;
};


#endif




屏幕上的水滴


#ifndef _DROP_H_


#define _DROP_H_


#include "Pos.h"


struct  Drop
{
void assign( const Pos& stCurPos,  int iDropCount  )
{
stCenter = stCurPos;
iDropCount = iDropCount;
}

bool operator == ( const Drop& other  )
{
return ( stCenter.iXPos == other.stCenter.iXPos 
&& stCenter.iYPos == other.stCenter.iYPos
&& iDropCount == other.iDropCount );
}

bool operator != ( const Drop& other  )
{
return !( *this == other );
}

void setDropCount( int iDC )
{
iDropCount = iDC;
}


Pos stCenter;

int iDropCount;
};




#endif




炸弹类



#ifndef _BOMB_H_


#define _BOMB_H_


#include "Pos.h"


#include "CommData.h"






struct   Bomb
{


public:

void assign( const Pos& stCurPos, Direction d  );


int  move( int iMaxX, int iMaxY, int iWidth, int iHeight   );

int outOfGrid(  int iMaxX, int iMaxY,  int iWidth, int iHeight );

public:


Pos stCenter;

Direction iDirection; //  0 left, 1 right, 2 up, 3 down 
 
};








#endif



#include "Bomb.h"


#include <iostream>


using namespace std;
  

void Bomb::assign( const Pos& stCurPos,  Direction d  )
{
stCenter =  stCurPos;
iDirection = d;
}


int  Bomb::move( int iMaxX, int iMaxY, int iWidth, int iHeight  )
{
stCenter.iXPos += iDirectionPlus[ 2 * iDirection ];

stCenter.iYPos += iDirectionPlus[ 2 * iDirection + 1 ];

//cout << "stCenter.iXPos is " << stCenter.iXPos 
// << ", stCenter.iYPos is " << stCenter.iYPos   << endl;

return outOfGrid( iMaxX, iMaxY , iWidth, iHeight );
}

int Bomb::outOfGrid(  int iMaxX, int iMaxY, int iWidth, int iHeight  )
{
if ( stCenter.iXPos <= 0 )
{
return 1;
}
else if ( stCenter.iXPos >= iMaxX - iWidth / 2  )
{
return 2;
}
else if ( stCenter.iYPos <= 0 )
{
return 3;
}
else if ( stCenter.iYPos >= iMaxY - iHeight / 2  )
{
return 4;
}

return 0;
}


数据常量定义



#ifndef _COMM_DATA_H_


#define _COMM_DATA_H_


 
 
const int iStep = 1;


const int iDirectionPlus[]  = { 0, 0, -iStep, 0, iStep, 0, 0, -iStep, 0, iStep  } ;


enum Direction { No_Direction = 0, Left , Right, Up, Down };


enum  ComboEffect { No_Effect,  Double  , Tripple, Excellent,  HolyShit, GodLike  };


const int iColumn = 6;


const int iRow = 6;


const int iScale = 1;

const int iDropWidth = iStep * iScale * 24;

const int iDropHeight = iStep * iScale * 12;
 
const int iBombWidth = iStep * iScale * 6;

const int iBombHeight = iStep * iScale * 6;

const int iXStartPos = 0;

const int iYStartPos = 0;

const int iBombLimit = 5; // 5滴水时爆炸




const int iBombDropCount = 1;
 
 




#endif


工具函数


#ifndef _UTIL_H_


#define _UTIL_H_


#include "Pos.h"


#define MY_ABS(x)   ((x)>0?(x):-(x))


int interRect( const Pos& stCenter1, int iWidth1, int iHeight1, 
const Pos& stCenter2, int iWidth2, int iHeight2  );


int interRectCircle( const Pos& stCenter1, int iWidth1, int iHeight1, 
const Pos& stCenter2, int iR );

#endif





#include "Util.h"




using namespace std;



#include "Util.h"




using namespace std;


int interRect( const Pos& stCenter1, int iWidth1, int iHeight1, 
const Pos& stCenter2, int iWidth2, int iHeight2  )
{
if (   MY_ABS(  (  stCenter1.iXPos -  stCenter2.iXPos ) * 2  ) <  iWidth1 +  iWidth2
&&   MY_ABS(  (  stCenter1.iYPos -  stCenter2.iYPos ) * 2  ) <  iHeight1 +  iHeight2 )
{
return 1;
}

return 0;
}


int interRectCircle( const Pos& stCenter1, int iWidth1, int iHeight1, 
const Pos& stCenter2, int iR )
{
int iXabsDouble =  MY_ABS( (  stCenter1.iXPos -  stCenter2.iXPos ) ) * 2 ;
int iYabsDouble =  MY_ABS( (  stCenter1.iYPos -  stCenter2.iYPos ) ) * 2 ;

//首先判断是否在矩形中心周围的  w + 2 * iR 宽度的大矩形内

if (   iXabsDouble    <  iWidth1 + 2 * iR
&&  iYabsDouble   <  iHeight1 +  2 * iR )
{
//在大矩形内,查看是否在鸡毛蒜皮的扩展矩形内

if ( iXabsDouble   < iWidth1  || iYabsDouble   < iHeight1 )
{
return 1;
}
 
//不在扩展矩形内,只能算距离了,是否在  1 / 4 圆内

if ( (  iXabsDouble  - iWidth1    )  * ( iXabsDouble  - iWidth1    ) 
+ ( iYabsDouble  - iHeight1    )  * ( iYabsDouble  - iHeight1    )  < 4 * iR * iR )
{
return 1;
}
}

return 0;
}









游戏状态定义


#ifndef _GAME_STATE_H_


#define _GAME_STATE_H_


#include "Bomb.h"


#include "Drop.h"


#include "CommData.h"


#include <list>


using namespace std;


class GameState
{


public:


void init( const Pos& stOrig, int iBombLimit, int iColumn, int iRow, 
int iDropWidth,int iDropHeight,  int iBombWidth , int iBombHeight );


int putOne( Drop * pCurGrid, int iIndex  );

void printAll();

void printGrid( Drop * pGrid , int iTotal, int iColumn   );

private:


void clearAll();


void getGridDrop( const Pos& stPos, int& iIndex  );

void updateAll();

private:


//原点位置,从左到右递增X,从上到下递增Y

Pos stOrigPos;

int iBombLimit;


int iColumn;

int iRow;

int iMaxX;

int iMaxY;


int iDropWidth;

int iDropHeight;

int iBombWidth;

int iBombHeight;

Drop * pGrid;

//当前的炸弹列表

list<Bomb> bombList;

//当前要展示的爆炸效果的位置列表

list<Pos> explodeList;

//当前要展示的撞地效果的位置列表

list<Pos> hitGroundList;

//组合效果

int  iCombo;


};

#include "GameState.h"


#include <iostream>


#include "Util.h"


using namespace std;


void  GameState::init( const Pos& stOrig, int iLimit, int iC, int iR, 
int iDW, int iDH,  int iBW, int iBH )
{
stOrigPos = stOrig;
iBombLimit = iLimit;
iColumn = iC;
iRow = iR;

iMaxX = stOrigPos.iXPos + iColumn * iDW;
iMaxY = stOrigPos.iYPos + iRow * iDH;


//cout << "iMaxX  is " << iMaxX  << endl;

//cout << "iMaxY is " << iMaxY << endl;


iDropWidth = iDW;
iDropHeight = iDH;

iBombWidth = iBW;
iBombHeight = iBH;

}

void  GameState::getGridDrop( const Pos& stPos, int& iIndex )
{
int iXIndex =  ( stPos.iXPos - stOrigPos.iXPos ) / iDropWidth;

int iYIndex =  ( stPos.iYPos - stOrigPos.iYPos ) / iDropHeight;

iIndex = iColumn * iYIndex + iXIndex;

}

void GameState::printAll()
{
// 打印所有的雨滴

cout << "the rain drop are as follows "  << endl;

printGrid(   pGrid ,  iColumn * iRow  ,   iColumn   );

//打印所有的炸弹

list<Bomb>::iterator itr = bombList.begin();

cout << "the bomb are as follows : "  << endl;

for ( ; itr != bombList.end() ; ++itr ) 
{
cout << "( " <<  itr->stCenter.iXPos << " ,  " 
<< itr->stCenter.iYPos   << " )  " << endl;
}

//打印所有的爆炸效果

list<Pos>::iterator itr1 = explodeList.begin();

cout << "the explodeList  are as follows : "  << endl;

for ( ; itr1 != explodeList.end() ; ++itr1 ) 
{
cout << "( " <<  itr1->iXPos << " ,  " 
<< itr1->iYPos   << " )  " << endl;
}

explodeList.clear();

//打印所有的撞地效果

itr1 = hitGroundList.begin();

cout << "the hitGroundList  are as follows : "  << endl;

for ( ; itr1 != hitGroundList.end() ; ++itr1 ) 
{
cout << "( " <<  itr1->iXPos << " ,  " 
<< itr1->iYPos   << " )  " << endl;
}

hitGroundList.clear();
}

void GameState::updateAll()
{
//更新炸弹列表所有的状态

int iMoveResult = 0;

int iCurIndex = 0;

Bomb stCurBomb;

list<Bomb> bombNew;

list<Bomb>::iterator itr = bombList.begin();

//iDropWidth should lager than  iBombLimit  !!!!!!

int iMin = iDropHeight > iDropWidth ? iDropWidth : iDropHeight;

int iR = iMin / ( iBombLimit - 1 );
 

for ( ; itr != bombList.end() ;  )
{
iMoveResult = itr->move( iMaxX, iMaxY, 
iBombWidth,  iBombHeight );

//检查是否撞上了雨滴

if ( iMoveResult == 0 )
{
getGridDrop( itr->stCenter, iCurIndex  );

Drop &stCurDrop = pGrid[ iCurIndex ];

//cout << "iCurIndex is " << iCurIndex  <<  ", stCurBomb.stCenter.iXPos is " 
// << stCurBomb.stCenter.iXPos  <<  ", stCurBomb.stCenter.iYPos is " 
// << stCurBomb.stCenter.iYPos    << endl;

int iCurDropCount = stCurDrop.iDropCount;

//if (  iCurDropCount > 0 
// && interRect( itr->stCenter, iBombWidth, iBombHeight,  
// stCurDrop.stCenter,  iDropWidthScale *  iCurDropCount  , 
// iDropHeightScale   *  iCurDropCount )  )
if (  iCurDropCount > 0 
&& interRectCircle( itr->stCenter, iBombWidth, iBombHeight,  
stCurDrop.stCenter,  iR *  iCurDropCount / 2  )  )
{
// 撞上了,递增之

//cout << "iCurIndex is " << iCurIndex  <<  ", stCurBomb.stCenter.iXPos is " 
//<< itr->stCenter.iXPos  <<  ", stCurBomb.stCenter.iYPos is " 
//<< itr->stCenter.iYPos   << ", iR is " <<  iR *  iCurDropCount / 2  << endl;

iCurDropCount +=  iBombDropCount;

//cout << "iCurDrop is " << iCurDrop 
// << ", iBombLimit is " << iBombLimit   << endl;

bombList.erase(  itr++ );

if (  iCurDropCount < iBombLimit )
{
stCurDrop.iDropCount = iCurDropCount;

//炸弹被吸收
}
else
{
//cout << "bomb explode  iCurIndex  is " << iCurIndex
// << ", stCurDrop.stCenter's iXPos is " << stCurDrop.stCenter.iXPos
// << ", stCurDrop.stCenter's iYPos is " << stCurDrop.stCenter.iYPos
// << endl;

iCombo++;

stCurDrop.setDropCount( 0 );

//炸弹被吸收 产生4个炸弹

for ( int i =   Left; i <=  Down; ++i  )
{
stCurBomb.assign( stCurDrop.stCenter,  Direction( i ) );

bombNew.push_back( stCurBomb );
}
}
}
else // 没有撞上雨滴,位置变化了
{
itr++;
}
}
else // if ( iMoveResult > 0  )
{
// //没有装上雨滴,撞地上了,展示撞地效果

//cout << "seq : " << itr->iBombId << " hit ground , iMoveResult is  "
// << iMoveResult << endl;

hitGroundList.push_back( itr->stCenter );

bombList.erase(  itr++ );



}
}

if ( !bombNew.empty() )
{
bombList.splice(  bombList.end(), bombNew );
}
}
 
int GameState::putOne( Drop * pCurGrid, int iIndex  )
{
pGrid = pCurGrid;

clearAll();

Drop stDrop = pCurGrid[ iIndex ];

Bomb stCurBomb;

if ( stDrop.iDropCount + iBombDropCount >= iBombLimit )
{
iCombo++ ;

pCurGrid[ iIndex ].setDropCount( 0 ) ;

for ( int i =  Left; i <=  Down; ++i  )
{
stCurBomb.assign( stDrop.stCenter,   Direction( i ) );

bombList.push_back( stCurBomb );
}
}

//printAll();

while (  !bombList.empty() )
{
//cout << "begin one loop " << endl;

updateAll();

//printAll();
}

//打印Combo等效果列表

int iCurCombo = iCombo;

cout << "iCombo is " << int( iCombo ) << endl;

iCombo  =  0;

return iCurCombo;
}

void GameState::printGrid( Drop * pInputGrid , int iTotal, int iColumnInput   )
{
for ( int i = 0; i < iTotal; ++i )
{
if ( (  i + 1 )  %  iColumnInput == 0 )
{
cout << pInputGrid[ i ].iDropCount   << endl;
}
else
{
cout << pInputGrid[ i ].iDropCount << " "; 
}
}

cout << endl;
}

void GameState::clearAll()
{
bombList.clear();

//当前要展示的爆炸效果的位置列表

explodeList.clear();

//当前要展示的撞地效果的位置列表

hitGroundList.clear();

//组合效果

iCombo = 0;

}

 








#endif
 


入口函数


#include <iostream>


#include "GameState.h"


using namespace std;






int iInputGrid [] = { 
4, 4, 4, 3, 0, 0, 
2, 2, 4, 3, 4, 2,
3, 2, 0, 0, 0, 3, 
0, 1, 3, 2, 1, 3,
2, 2, 1, 4, 1, 4,
3, 2, 1, 3, 4, 0 };




void evaluateGrid( Drop * pGrid, int iTotal, int iTotalBomb, int iBombLimit,   int& iResult )
{
iResult =  iTotalBomb * 100;

int iDropCount = 0;

for ( int i = 0; i < iTotal; ++i  )
{
iDropCount = pGrid[ i ].iDropCount;

if ( iDropCount  == iBombLimit - 1 )
{
// 对于4滴的水,给分高一点

iResult += iDropCount * 2;
}
else
{
iResult += iDropCount;
}
}
}


int main( int argc, char **argv )
{
 
int iTotal = sizeof ( iInputGrid ) / sizeof ( int ) ;

Drop * pInitGrid = new Drop[ iTotal ];

int i = 0;


for (  ; i < iTotal ; ++i  )
{
pInitGrid[i].stCenter.iXPos = ( 2 * ( i  % iColumn )  + 1 ) *   iDropWidth / 2    ;

pInitGrid[i].stCenter.iYPos = ( 2 * ( i  /  iRow ) + 1 ) *  iDropHeight / 2      ;

pInitGrid[i].iDropCount = iInputGrid[ i ];

//pInitGrid[i].iHeight = iDropHeight;

//pInitGrid[i].iWidth = iDropWidth;

//cout << " i is " << i << ",  pInitGrid[i].stCenter.iXPos  is " <<  pInitGrid[i].stCenter.iXPos 
// << ",  pInitGrid[i].stCenter.iYPos  is " <<  pInitGrid[i].stCenter.iYPos  << endl;


}

Drop * pGrid = new Drop[ iTotal ];

int iMaxResult = 0;

int iMaxPos = 0;

GameState stState;

stState.init(  Pos( iXStartPos, iYStartPos ), iBombLimit, iColumn, iRow, iDropWidth, iDropHeight,
iBombWidth, iBombHeight   );

i = 0;

int iResult = 0;
 

for (  ; i <  iTotal  ; ++i  )
{
memcpy( pGrid, pInitGrid,  iTotal * sizeof ( Drop )   );

if ( pGrid[ i ].iDropCount + iBombDropCount >= iBombLimit )
{
int iTotalBomb = stState.putOne( pGrid, i );

evaluateGrid( pGrid, iTotal, iTotalBomb, iBombLimit,  iResult );

cout <<  "evaluateGrid return : " <<  iResult << endl;
 
if ( iMaxResult < iResult )
{
iMaxResult = iResult;

iMaxPos = i;
}
}
}

cout << "iMaxPos is " << iMaxPos << ", iMaxResult is " << iMaxResult    << endl;

delete []pGrid;

delete []pInitGrid;


return 0;
}




inc.mk


CC= gcc
CXX = g++
CFLAGS = -Wall -g -DDEBUG_LOG_ARGS -Wno-deprecated


.%.d: %.cpp
@echo "update $@ ..."; \
echo -en $< | sed s/\.cpp/\.o:/ > $@; \
$(CC) $(INCLUDE) -MM $< | sed '1s/.*.://' >> $@;


%.o: %.cpp
$(CXX) $(CFLAGS) $(INCLUDE) -o $@ -c $<


.%.d: %.c
@echo "update $@ ..."; \
echo -en $< | sed s/\.c/\.o:/ > $@; \
$(CC) $(INCLUDE) -MM $< | sed '1s/.*.://' >> $@;


%.o: %.c
$(CC) $(CFLAGS) $(INCLUDE) -o $@ -c $<


#----------------------------------------------------------------------------------



makefile


include ./Inc.mk


EXE = ./a.out


all : $(EXE)


INCLUDE := $(INCLUDE) 
LIBS   :=  


CPPS    =  $(wildcard *.cpp)
OBJS   :=  $(patsubst %.cpp, %.o, $(CPPS)) 
DEPS    =  $(patsubst %.o, .%.d, $(OBJS)) 


#####################################################################################


$(EXE): $(OBJS)
$(CXX) $(CFLAGS) -o $@ $^ $(LIBS)


install:
echo "install. do nothing..."
echo $(CPPS)
echo $(OBJS)
echo $(DEPS)


clean:
rm -vf *.o .*.d $(EXE) $(EXEX) $(OBJS) $(OBJSEX)


-include $(DEPS)