header
main about me projects resume code samples
This class is used to find closed piece chain links on the board.  Starting at a given piece focal point, the object's algorithms search
all locations that are touching the focal point.  Each piece linked to the focal piace or linked to a piece that is a part of the initial chain is checked.
If a path streaches from the starting point back to the starting point, then all pieces along that path are considered to be part of a completed chain.

The function SearchForLinks is called to run the link check.

//----------------------------------------------------------------------------
// All content © 2006 DigiPen (USA) Corporation, all rights reserved.
//----------------------------------------------------------------------------
using System;
using System.Collections;

namespace Hexcentric
{
   //************************************************************************
   /// 
   /// Used to find closed piece chain links on the board.  Starting at a given piece focal point, the object's algorithms search
   /// all locations that are touching the focal point.  Each piece linked to the focal piace or linked to a piece that is a part of the initial chain is checked.
   /// If a path streaches from the starting point back to the starting point, then all pieces along that path are considered to be part of a completed chain.
   /// 
   //************************************************************************
   public class CLinkFinder
   {
      //************************************************************************
      //# Member data:
      //************************************************************************

      // Check is true if the link finder should set pieces 
      // inside the loop to be removed.
      bool m_bRemoveInner; 

      // Temporarily stores the board and start position being checked.  
      // This way I don't have to pass the reference all over the place.
      CBaseBoard m_clBoardCheck = null;
      SBoardLoc m_stStartPos;

      // Stores index of the piece segment of the m_stStartPos currently being checked for a link.
      // Any segment that joins the current chain will get this value added to its link start array.
      // So this will be set 6 time in SearchForLinks, once for each segment.
      int m_iCurrStartSeg;


      //************************************************************************
      /// 
      // Default constructor.  Pieces enclosed by a chain are not set to be removed.
      /// 
      //************************************************************************
      public CLinkFinder()
      {
         m_bRemoveInner = false; 
         m_clBoardCheck = null;
      }


      //************************************************************************
      /// 
      /// Set weither the pieces inside a linked loop should be marked for removal.
      /// 
      /// 
      ///  name="bRemoveInner">Value should be true if the inside loops should be marked, false if not.end 
      //************************************************************************
      public void SetRemoveInner(bool bRemoveInner)
      {
         m_bRemoveInner = bRemoveInner;
      }


      //************************************************************************
      /// 
      /// Check the board passed for links.  The position to start the check from
      /// is the position passed.  Starting at that position, check the pieces
      /// it is touching for links.  Only links attached to the piece at the position passed
      /// should be set.  Sets segments in the link to show what kind of removal they need.
      /// 
      /// 
      ///  name="rPosStartCheck">Position to start the link check from.end 
      ///  name="clBoardCheck">Board to check.end 
      /// 
      /// returnsValue is true if a link was found, false if not.returns
      //************************************************************************
      public bool SearchForLinks(ref SBoardLoc rPosStartCheck,
                                 CBaseBoard clBoardCheck)
      {
         // Copy the board ref, then starting at the first segment of the piece passed, look for links.
         m_clBoardCheck = clBoardCheck;
         m_stStartPos = rPosStartCheck;

         bool bLinkFound = false;
         for(int iLoop = 0; 6 > iLoop; ++iLoop)
         {
            m_iCurrStartSeg = iLoop;
            if(CheckForLink(iLoop, ref m_stStartPos))
            {
               bLinkFound = true;
            }
            // Chain not formed, remove the m_iCurrStartSeg value from any board segments that contain it in 
            // their link start values.
            else
            {
               m_clBoardCheck.ResetSegLinkStartVal(m_iCurrStartSeg);
            }
         }

         // Reset the board ref, so we don't acccidentally use it again.
         m_clBoardCheck = null;

         // Return weither a link was found and set.
         return bLinkFound;
      }


   //************************************************************************
   /// 
   /// Given a hex segment index, get the index of the segment touching it.  (0-5).
   /// 
   /// 
   ///  name="iSeg">Segment to find out which segment touches.end 
   /// 
   /// returnsThe segment index that touches the given segment index.returns
   //************************************************************************
   public static int GetSegTouching(int iSeg)
   {
      int iMatchingSeg = iSeg+3;
      if(5 < iMatchingSeg)
         iMatchingSeg = iMatchingSeg - 6;
      return iMatchingSeg;
   }


   //************************************************************************
   /// 
   /// Checks if the segment passed for the piece passed links up to 
   /// the segment of the piece that is touching it.  If there
   /// is an attachment, the two pieces get set to the attached state.
   /// 
   /// 
   ///  name="iSegCheck">Segment index to check in the hexagon.end 
   ///  name="rPiecePos">Board space position to perform the check at.end 
   /// 
   /// returnsValue is true if there was a attachment, false if notreturns
   //************************************************************************
   private bool CheckPiecesForMatch(int iSegCheck, 
                                    ref SBoardLoc rPiecePos)
   {
      SBoardLoc stConnectingPoint = new SBoardLoc();
      CBaseBoard.GetPosHexTouching(iSegCheck, ref rPiecePos, ref stConnectingPoint);

      CHexBoardSeg clHoldSeg = m_clBoardCheck.GetSeg(stConnectingPoint.iC, stConnectingPoint.iR);
      CHexBoardSeg clInitSeg = m_clBoardCheck.GetSeg(rPiecePos.iC, rPiecePos.iR);

      // If it is a valid hexagon, and the pieces match, then the segment are linked
      if(null != clHoldSeg && clHoldSeg.m_bHoldsPiece)
      {
         int iSegTouching = GetSegTouching(iSegCheck);
	         if(((CBaseHex)(clHoldSeg.m_clSegObj)).GetSegType(iSegTouching) == 
                     ((CBaseHex)(clInitSeg.m_clSegObj)).GetSegType(iSegCheck))
                  {
	             // Segments matched, end.
	             return true;
	          }
      }

      // Hexagons don't match, end.
      return false;
   }


      //************************************************************************
      /// 
      /// Checks if the segment passed for the piece passed links up to 
      /// the segment of the piece that is touching it.
      /// 
      /// 
      ///  name="iSegCheck">Segment in the hexagon to check.end 
      ///  name="rPiecePos">Location of the piece to check for.end 
      ///  name="clBoard">Board to check.end 
      /// 
      /// returnsValue is true if there was a attachment, false if notreturns
      //************************************************************************
      public bool CheckPiecesForMatch(int iSegCheck, 
                                      ref SBoardLoc rPiecePos,
                                      CBaseBoard clBoard)
      {
         SBoardLoc stConnectingPoint = new SBoardLoc();
         CBaseBoard.GetPosHexTouching(iSegCheck, ref rPiecePos, ref stConnectingPoint);

         CHexBoardSeg clHoldSeg = clBoard.GetSeg(stConnectingPoint.iC, stConnectingPoint.iR);
         CHexBoardSeg clInitSeg = clBoard.GetSeg(rPiecePos.iC, rPiecePos.iR);

         // If it is a valid hexagon, and the pieces match, then the segment are linked.
         if(null != clHoldSeg && clHoldSeg.m_bHoldsPiece)
         {
            int iSegTouching = GetSegTouching(iSegCheck);
            if(((CBaseHex)(clHoldSeg.m_clSegObj)).GetSegType(iSegTouching) == 
               ((CBaseHex)(clInitSeg.m_clSegObj)).GetSegType(iSegCheck))
            {
               // Segments matched, end.
	       return true;
            }
         }

         // Hexagons don't match, end.
         return false;
      }

      //************************************************************************
      /// 
      /// Given a piece location and a segment index in that piece, this checks the board
      /// segment that is touching the given segment.  If a piece is in that segment, then
      /// this retrives the segment value of that piece that is touching the given pieces' segment.
      /// 
      /// 
      ///  name="iSegCheck">Segment to get the touching value for.end 
      ///  name="rPiecePos">Piece to get the touching value for.end 
      ///  name="clBoard">Board to check.end 
      ///  name="rTouchingVal">Set to the touching value, if any.end 
      /// 
      /// returnsValue is true if there was a touching value, false if not.returns
      //************************************************************************
      public bool GetTouchingSegVal(int iSegCheck, 
                                    ref SBoardLoc rPiecePos,
                                    CBaseBoard clBoard,
                                    ref int rTouchingVal)
      {
         SBoardLoc stConnectingPoint = new SBoardLoc();
         CBaseBoard.GetPosHexTouching(iSegCheck, ref rPiecePos, ref stConnectingPoint);

         CHexBoardSeg clHoldSeg = clBoard.GetSeg(stConnectingPoint.iC, stConnectingPoint.iR);
         CHexBoardSeg clInitSeg = clBoard.GetSeg(rPiecePos.iC, rPiecePos.iR);

         // If there is a piece stored, get the segment value and end.
         if(null != clHoldSeg && clHoldSeg.m_bHoldsPiece)
         {
            int iSegTouching = GetSegTouching(iSegCheck);
            rTouchingVal = ((CBaseHex)(clHoldSeg.m_clSegObj)).GetSegType(GetSegTouching(iSegCheck));
            return true;
         }

         // No touching segment, end.
         return false;
      }


      //************************************************************************
      /// 
      /// Checks the given piece and segment within the piece for a link.
      /// 
      /// 
      ///  name="iSegCheck">Segment in the piece to check.end 
      ///  name="rPiecePos">Board space position of the piece to check.end 
      /// 
      /// returnsValue is true if a link is found, false if not.returns
      //************************************************************************
      private bool CheckForLink(int iSegCheck,
                               ref SBoardLoc rPiecePos)
      {
         bool bLinkFound = false;

         // Store the pointer to the piece being checked.
         CBaseHex clCurrPiece = (CBaseHex)(m_clBoardCheck.GetSegContent(ref rPiecePos));
         int iCurrSegType = clCurrPiece.GetSegType(iSegCheck);

         // Count of how many times the segment passed in has found a matching segment in the 
         // hexagon
         int iTimesSet = 0;

         // Loop through each of the segments and check for links.
         for(int iCurrSeg = iSegCheck+1; iSegCheck != iCurrSeg; ++iCurrSeg)
         {
            // Loop back to the first hex segment.
            if(6 == iCurrSeg)
               iCurrSeg = 0;	
		
            // If the special case where 0 == cSegCheck isn't true, look for links.
            if(!(0 == iSegCheck && 0 == iCurrSeg))
            {
               // Found another piece of the same type on the hexagon, 
               // and that piece is touching a hexagon segment of the same type.
               // Check for a link.
               if(iCurrSegType == clCurrPiece.GetSegType(iCurrSeg) && 
                  CheckPiecesForMatch(iCurrSeg, ref rPiecePos))
               {
                  SBoardLoc stPieceToCheck = new SBoardLoc();
                  CBaseBoard.GetPosHexTouching(iCurrSeg, ref rPiecePos, ref stPieceToCheck);

                  ++iTimesSet;

                  // Set the piece being linked to with the current start segment value.
                  // Don't do this if it is the start piece iteself.
                  if(m_stStartPos.iC != rPiecePos.iC || m_stStartPos.iR != rPiecePos.iR)
                      m_clBoardCheck.GetSeg(rPiecePos.iC, rPiecePos.iR).AddLinkStart(m_iCurrStartSeg);

                  // The next piece to check is actually the starting point,
                  // so that means a loop has occured,YAHOOO.
                  if(stPieceToCheck.iC == m_stStartPos.iC && stPieceToCheck.iR == m_stStartPos.iR)
                  {
                      clCurrPiece.SetLinkState(iCurrSeg, iCurrSegType);
                      clCurrPiece.SetLinkState(iSegCheck, iCurrSegType);					
                      bLinkFound = true;
                  }
                  // It hasn't made a full loop yet, continue checking.
                  else
                  {
                     // Check if any of the segments in the next hex has a link
                     // If so, we form a link, Woo hoo.
                     if(((CBaseHex)(m_clBoardCheck.GetSegContent(ref stPieceToCheck))).HasLinkState(iCurrSegType))
                     {
                        clCurrPiece.SetLinkState(iCurrSeg, iCurrSegType);
                        clCurrPiece.SetLinkState(iSegCheck, iCurrSegType);						
                        bLinkFound = true;
                     }
                     // Check the next hex for a link.
                     else 
                     {
                        // Set with a link value and continue to check.
                        clCurrPiece.SetLinkState(iCurrSeg, iCurrSegType);
                        clCurrPiece.SetLinkState(iSegCheck, iCurrSegType);
                        if(CheckForLink(GetSegTouching(iCurrSeg), ref stPieceToCheck))
                        {
                           // Link found.
                           bLinkFound = true;
                        }	
                        // Not linked, remove its link value.
                        else
                        {
                           // Reset the passed seg because the links it was checking didn't pan out.
                           --iTimesSet;
                           if(0 == iTimesSet)
                              clCurrPiece.SetLinkState(iSegCheck, -1);
                           clCurrPiece.SetLinkState(iCurrSeg, -1);
                        }
                     }
                  }
               }
            }
            // Special case where cSegCheck == 0 and the loop is finished.
            else
            {
               iCurrSeg = -1;
            }
         }

         // Return whether any links where created
         return bLinkFound;
      }


      //************************************************************************
      /// 
      /// Checks the board for completed links that contain some link effect, like a fire item,
      /// and stores which links contain which link events. 
      /// 
      /// 
      ///  name="clEffects">Used to store the link effect data that occures, if any.end 
      ///  name="clBoardCheck">Board to check for link effects.end 
      //************************************************************************
      public void CheckForLinkEffects(CLinkedEffects clEffects,
                                      CBaseBoard clBoardCheck)
      {
         // Stores all the different link start values found in the links.
         ArrayList clLinkStarts = new ArrayList();
         SBoardLoc stCurrInd = new SBoardLoc(0,0);
         do
         {
            CHexBoardSeg clHoldSeg = clBoardCheck.GetSeg(stCurrInd.iC, stCurrInd.iR);
            if(null != clHoldSeg && null != clHoldSeg.m_clSegObj && ((CBaseHex)(clHoldSeg.m_clSegObj)).HasAnyLink())
            {
               //Increment the count.
               ++clEffects.m_iNumPieces;

               EObjectTypes eType = clHoldSeg.m_clSegObj.Type;
               // Add a fire event.
               if(EObjectTypes.FIRE_ITEM == eType)
               {
                  for(int iInd = 0; iInd < 3; ++iInd)
                  {
                     if(-1 != clHoldSeg.m_aLinkStart[iInd])
                     {
                        if(-1 == clLinkStarts.IndexOf(clHoldSeg.m_aLinkStart[iInd]))
                           clLinkStarts.Add(clHoldSeg.m_aLinkStart[iInd]);

                        clEffects.AddFireEvent(clHoldSeg.m_aLinkStart[iInd]);
                     }
                  }
               }
               else
               {
               for(int iInd = 0; iInd < 3; ++iInd)
               {
                  if(-1 != clHoldSeg.m_aLinkStart[iInd])
                  {
                     if(-1 == clLinkStarts.IndexOf(clHoldSeg.m_aLinkStart[iInd]))
                        clLinkStarts.Add(clHoldSeg.m_aLinkStart[iInd]);
                  }
               }
            }
	 }
      }while(clBoardCheck.NextIndexStandard(ref stCurrInd));

      // If the the piece placed to form the link is an event object itself, set every link
      // start value stored to have the current piece's event, and set it to contain them as well.
      CHexBoardSeg clSeg = clBoardCheck.GetSeg(m_stStartPos.iC, m_stStartPos.iR);
      if(EObjectTypes.FIRE_ITEM == clSeg.m_clSegObj.Type)
      {
         for(int iSet = 0; iSet < clLinkStarts.Count; ++iSet)
         {
            clEffects.AddFireEvent((int)clLinkStarts[iSet]);
            clSeg.AddLinkStart((int)clLinkStarts[iSet]);
         }
      }
   }

}

}