连连看算法,我的一种实现

来源:互联网 发布:android读取串口数据 编辑:程序博客网 时间:2024/05/22 05:33

#include <string>
#include <iostream>
#include <set>
#include <map>
#include <sys/time.h>
using namespace std;

struct Point
{
 int iX;
 int iY;
 int iKind;
 
 Point( ) : iX( 0 ), iY( 0 ),iKind( 0 )
 {
 }
 
 Point( int x, int y  ) : iX( x ), iY( y ),iKind( 0 )
 {
 }
};

bool canConnectDirect( const Point& p1, const Point& p2,
 int iMaxCol, int iMaxRow, Point *  pstArr )
{
 bool bFound = false;
 if ( p2.iX == p1.iX )
 {
  // 横坐标相同,看iY
  // 向上
  int i = p1.iY - 1;
  int iP1X = p1.iX;
  for ( ; i >= 1 ; --i )
  {
   if (  pstArr[ iP1X +  i * ( iMaxCol + 2 )  ].iKind > 0   )
   {
    if ( i == p2.iY )
    {
     bFound = true;
    }
    break;
   }
  }
  
  if ( !bFound )
  {
   // 向下
   i = p1.iY + 1;
   int iP1X = p1.iX;
   for ( ; i <= iMaxRow ; ++i )
   {
    if (  pstArr[ iP1X +  i * ( iMaxCol + 2 )  ].iKind > 0   )
    {
     if ( i == p2.iY )
     {
      bFound = true;
     }
     break;
    }
   }
  }
 }
 else if ( p2.iY == p1.iY )
 {
  // 纵坐标相同,看iX
  // 向左
  int j = p1.iX - 1 ;
  int iP1Y = p1.iY;
  for ( ; j >= 1 ; --j )
  {
   if ( pstArr[ j  +  iP1Y * ( iMaxCol + 2 ) ].iKind  > 0   )
   {
    if ( j == p2.iX )
    {
     bFound = true;
    }
    break;
   }
  }
  if ( !bFound )
  {
   // 向右
   j = p1.iX + 1 ;
   for ( ; j <= iMaxCol ; ++j )
   {
    if (  pstArr[ j +  iP1Y * ( iMaxCol + 2 ) ].iKind > 0  )
    {
     if ( j == p2.iX )
     {
      bFound = true;
     }
     break;
    }
   }
  }
 }
 
 return bFound;
}


int getAllConnectPoint( const Point& p1,  int iMaxCol,
 int iMaxRow, Point *  pstArr, set<int>& setDirect,
 const set<int>& setDetected )
{
 // 向左
 int j = p1.iX - 1 ;
 int iP1Y = p1.iY;
 for ( ; j >= 0 ; --j )
 {
  if (  pstArr[ j  + iP1Y * ( iMaxCol + 2 ) ].iKind > 0 )
  {
   break;
  }
  else
  {
   int iSetPos = j * 10000 +  iP1Y;
   if ( setDetected.empty()
    || setDetected.find( iSetPos ) == setDetected.end()  )
   {
    setDirect.insert( iSetPos );
   }
  }
 }
 // 向右
 j = p1.iX + 1 ;
 for ( ; j <= iMaxCol + 1 ; ++j )
 {
  if (  pstArr[ j + iP1Y * ( iMaxCol + 2 )  ].iKind > 0 )
  {
   break;
  }
  else
  {
   int iSetPos = j * 10000 +  iP1Y;
   if ( setDetected.empty()
    || setDetected.find( iSetPos ) == setDetected.end()  )
   {
    setDirect.insert( iSetPos );
   }
  }
 }
 // 向上
 int i = p1.iY - 1;
 int iP1X = p1.iX;
 for ( ; i >= 0 ; --i )
 {
  if (  pstArr[ iP1X + i * ( iMaxCol + 2 ) ].iKind > 0 )
  {
   break;
  }
  else
  {
   int iSetPos = iP1X * 10000 +  i;
   if ( setDetected.empty()
    || setDetected.find( iSetPos ) == setDetected.end()  )
   {
    setDirect.insert( iSetPos );
   }
  }
 }
 // 向下
 i = p1.iY + 1;
 iP1X = p1.iX;
 for ( ; i <= iMaxRow + 1 ; ++i )
 {
  if (  pstArr[ iP1X + i * ( iMaxCol + 2 )  ].iKind > 0 )
  {
   break;
  }
  else
  {
   int iSetPos = iP1X * 10000 +  i;
   if (  setDetected.empty()
    || setDetected.find( iSetPos ) == setDetected.end()  )
   {
    setDirect.insert( iSetPos  );
   }
  }
 }
}

void printSet( const set<int>& curSet )
{
 set<int>::const_iterator itr = curSet.begin();
 for ( ; itr != curSet.end(); ++itr )
 {
  cout << "(" << *itr / 10000  << ","  << *itr % 10000  <<   ")"<< "\t";
 }
 cout << endl;
}

bool canConnect( const Point& p1, const Point& p2,
 int iMaxCol, int iMaxRow, Point *  pstArr )
{
 // 直接连通的情况
 bool bCan = canConnectDirect( p1, p2, iMaxCol, iMaxRow, pstArr );
 if ( bCan )
 {
  return bCan;
 }
 
 // 看拐一个弯,1级连通的情况
 set<int> setDetected;
 set<int> setP1Direct;
 getAllConnectPoint(  p1,  iMaxCol,  iMaxRow,
  pstArr, setP1Direct, setDetected );
 if ( setP1Direct.empty() )
 {
  return false;
 }
 //cout << "P1 : ( " << p1.iX  << "," << p1.iY  << " )'s set is "<< endl;
 
 //printSet(  setP1Direct );
 
 set<int> setP2Direct;
 getAllConnectPoint(  p2,  iMaxCol,  iMaxRow,
  pstArr, setP2Direct, setDetected );
  
 if ( setP2Direct.empty() )
 {
  return false;
 }
 
 //cout << "P2: ( " << p2.iX  << "," << p2.iY  << " )'s set is "<< endl;
 
 //printSet(  setP2Direct );
 
 // 取交集
 set<int> interSet;
 set<int>::iterator itr = interSet.begin();
 set_intersection( setP1Direct.begin(), setP1Direct.end(),
        setP2Direct.begin(), setP2Direct.end(),  inserter( interSet, itr ) );
 if ( ! interSet.empty() )
 {
  return true;
 }
 setDetected = setP1Direct;
 // 1级连不同,看拐两个弯,2级连通的情况
 set<int>::iterator itr1 = setP1Direct.begin();
 set<int> setTmp;
 for ( ; itr1 != setP1Direct.end(); ++itr1 )
 {
  setTmp.clear();
  getAllConnectPoint(  Point( *itr1 / 10000, *itr1 % 10000 ) ,   iMaxCol,  iMaxRow,
   pstArr, setTmp, setDetected );
   
  if ( setTmp.empty() )
  {
   continue;
  }
  
  //cout << "itr1: ( " << *itr1 / 10000  << "," << *itr1 % 10000 << " )'s set is "<< endl;
 
  //printSet(  setTmp );
  
  itr = interSet.begin();
  set_intersection( setTmp.begin(), setTmp.end(),
   setP2Direct.begin(), setP2Direct.end(),  inserter( interSet, itr ) );
  if ( ! interSet.empty() )
  {
   return true;
  }
  setDetected.insert( setTmp.begin(), setTmp.end() );
 }
 return false;
}

bool printArr( int iWidth, int iHeight, Point *  pstArr )
{
 int iCol = 1;
 int iRow = 1;
 
 for ( iRow = 1; iRow <= iHeight; ++iRow )
 {
  for ( iCol = 1; iCol <= iWidth; ++iCol )
  {
   cout << pstArr[ iCol + iRow * ( iWidth + 2 ) ].iKind << "\t";
  }
  cout << endl;
 }
}

int main( int argc , char **argv )
{

 int iWidth = 10;
 int iHeight = 10;
 int i = 0;
 Point *  pstArr  = new Point[ ( iWidth + 2 )  * ( iHeight + 2 ) ];
 map<int, Point*> mapPt;
 
 int iMaxKind = 15;
 int iCol = 0;
 int iRow = 0;
 int iKind = 0;
 srand( time( NULL ) );
 
 struct timeval tvStart, tvEnd;
 gettimeofday( &tvStart, NULL );
 
 for ( int iRunCount = 0; i < atoi( argv[1] ) ; ++i )
 {
 

  // 随机生成一个连连看棋局

 

 //   1 - width 为col的取值范围  1 - height 为 row的取值范围
 for ( iCol = 1; iCol <= iWidth   ; ++iCol  )
 {
  for ( iRow = 1; iRow <= iHeight   ; ++iRow )
  {
   int iCurPos = iCol + iRow * ( iWidth + 2 );
   if ( pstArr[ iCurPos ].iKind > 0 )
   {
    continue;
   }
   
   iKind = rand() % iMaxKind + 1;
   
   pstArr[ iCurPos ].iX = iCol;
   pstArr[ iCurPos ].iY = iRow;
   pstArr[ iCurPos ].iKind = iKind;
   
   int iResultCol = rand() % iWidth + 1 ;
   int iResultRow = rand() % iHeight + 1 ;
   
   while ( pstArr[ iResultCol + iResultRow * ( iWidth + 2 ) ].iKind != 0 )
   {
    iResultCol = rand() % iWidth + 1 ;
    iResultRow = rand() % iHeight + 1 ;
   }
   
   int iArrPos = 0;
   iArrPos = iResultCol + iResultRow *  ( iWidth + 2 );
   pstArr[ iArrPos ].iX = iResultCol;
   pstArr[ iArrPos ].iY = iResultRow;
   pstArr[ iArrPos ].iKind = iKind;
   
   
   
   //cout << "iPos is " << iCol << "," <<  iRow  << ", result is " << iResultCol << "," << iResultRow  << endl;
  }
 }
 //printArr( iWidth, iHeight, pstArr );
 //cout << "===========================================" << endl;
 
 int iEraseCount = 1;
 map<int, set<Point*> > mapKind;
 // 将所有的同花色的位置,保存到一个map中,为的是下面匹配的时候只在同花色之间进行匹配
 for ( iRow = 1; iRow <= iHeight; ++iRow )
 {
  for ( iCol = 1; iCol <= iWidth; ++iCol )
  {
   //cout << " iCol + iRow * ( iWidth + 2 ) is " << iCol + iRow * ( iWidth + 2 )  << endl;
   int iArrPos = iCol + iRow * ( iWidth + 2 );
   int iKind = pstArr[ iArrPos ].iKind;
   if ( iKind > 0  )
   {
    //cout << "map Kind:" << iKind << " insert ( " << iCol << "," << iRow  << ")" << endl;
    mapKind[  iKind ].insert(  &( pstArr[ iArrPos ] ) );
   }
  }
 }
 Point stEmpty;

// 循环匹配,直到没有可以匹配的花色为止,如果此时仍然有不为0的为止,则表示死锁了


 for ( ;  iEraseCount > 0 ;   )
 {
  iEraseCount = 0;
  
  for ( iCol = 1; iCol <= iWidth; ++iCol )
  {
   for ( iRow = 1; iRow <= iHeight; ++iRow )
   {
    //cout << " iCol + iRow * ( iWidth + 2 ) is " << iCol + iRow * ( iWidth + 2 )  << endl;
    int iArrPos = iCol + iRow * ( iWidth + 2 );
    int iCurKind = pstArr[ iArrPos ].iKind;
    if ( iCurKind > 0 )
    {

    // 找到同花色的为止链表


     set<Point*>& curSet = mapKind[ iCurKind ];
     if (  curSet.size() > 1 )
     {
      set<Point*>::iterator itr = curSet.begin();
      bool bErased = false;

// 和当前位置iArrPos看能否连上,每次只连一个


      for ( ; itr != curSet.end() ; )
      {
       if ( *itr == &pstArr[ iArrPos ] )
       {
        ++itr;
        continue;
       }
       
       bool bConnect = canConnect(  pstArr[ iArrPos ],
        *( *itr ), iWidth, iHeight, pstArr );
        
       if ( bConnect )
       {
        bErased = true;
        ++iEraseCount;
        /*
        cout << "Point ( " <<  iCol <<  ","  << iRow << ")   and Point ( "
         << (*itr)->iX << "," 
         << (*itr)->iY << ") can  connect "   << endl;
         */
        *( *itr ) = stEmpty;
        // 每次只清除和当前位置对应的1个位置
        curSet.erase( itr );
        break;
       }
       else
       {
        itr++;
       }
      }
      
      if ( bErased )
      {
       // 删除了对应的pos
       pstArr[ iArrPos ] = stEmpty;
       curSet.erase( &pstArr[ iArrPos ]  );
      }
      
     }
    }
   }
  }
  //cout << "after one loop"  << endl;
 }
 
 
 }
 
 //printArr( iWidth, iHeight, pstArr );
 
 gettimeofday( &tvEnd, NULL );
 int iCost = ( tvEnd.tv_sec - tvStart.tv_sec ) * 1000  + ( tvEnd.tv_usec - tvStart.tv_usec ) / 1000;
 cout << argv[1] << " times cost " << iCost << " ms "  << endl;
 delete [] pstArr;
 
 
 return 0;
}

g++ -DDEBUG  -g main.cpp
./a.out  3000

 

gdb ./a.out  core

 

 

原创粉丝点击