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]);
}
}
}
}
}
|