⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 ase_threatboard.cpp

📁 A*算法的演示程序
💻 CPP
📖 第 1 页 / 共 2 页
字号:
/* Copyright (C) William van der Sterren, 2002. 
 * All rights reserved worldwide.
 *
 * This software is provided "as is" without express or implied
 * warranties. You may freely copy and compile this source into
 * applications you distribute provided that the copyright text
 * below is included in the resulting source code, for example:
 * "Portions Copyright (C) William van der Sterren, 2002"
 */

/***************************************************************************  
 *                                                                            
 *     purpose: threat and line-of-fire lookup table and overlay
*/

#include "stdafx.h"
#include "ase_threatboard.h"

#include "ase_terrain.h"

#include <vector>
#include <algorithm> // though MSVC6 doesn't feature min/max there
using namespace std;

#include <cmath>
#include <cassert>


#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif


ASE_ThreatBoard::ASE_ThreatBoard(unsigned int            aNumberOfRows, 
                                 unsigned int            aNumberOfColumns,
                                 const ASE_TerrainBoard* theTerrain
                                )
  : ASE_Board(aNumberOfRows, aNumberOfColumns, 16, m_ThreatBrushes),
    m_RiskModus(eAnyLineOfFire),
    m_kTerrainBoard(theTerrain),
    m_kThreatLineOfFire(1),
    m_kThreatPosition(15),
    m_RiskFactor(4),
    m_LineOfFireReach(32),
    m_ThreatMovement(0),
    m_ThreatBrushes(0),
    m_kBaseRisk(0.15f),
    m_kMaxLOFCount(6)
  {
    assert( m_kTerrainBoard );
    assert( GetNumberOfColumns() == m_kTerrainBoard->GetNumberOfColumns() );
    assert( GetNumberOfRows()    == m_kTerrainBoard->GetNumberOfRows() );

    FillOutPalette();

    // prepare the line-of-fire template
    m_PieTemplate.PrepareScan(m_LineOfFireReach);
  }


ASE_ThreatBoard::~ASE_ThreatBoard()
  {
    delete[] m_ThreatBrushes;

    RemoveAllThreats();
  }


void ASE_ThreatBoard::FillOutPalette()
  {
    assert( m_ThreatBrushes     == 0 );
    assert( GetNumberOfValues() >  2 );
    /*!
        fill out brush table as follows:
        part1: line-of-fire
               3 x GetNumberOfValues()
                 clear terrain, all values
                 terrain 1, all values
                 terrain 2, all values
    */

    unsigned int totalnumber;
    unsigned int steps;
    steps       = GetNumberOfValues();
    totalnumber = 3 * steps;

    m_ThreatBrushes = new COLORREF[totalnumber];

    COLORREF startrgb;
    COLORREF endrgb;
    float step_r, step_g, step_b;
    float r, g, b;

    int idx;
    idx = 0;

    // fill out first steps entries
    startrgb = RGB(255,255,224); 
    endrgb   = RGB(255,255,128); 
    step_r   = static_cast<float>(GetRValue(endrgb) - GetRValue(startrgb));
    step_g   = static_cast<float>(GetGValue(endrgb) - GetGValue(startrgb));
    step_b   = static_cast<float>(GetBValue(endrgb) - GetBValue(startrgb));
    step_r  /= (steps - 1);
    step_g  /= (steps - 1);
    step_b  /= (steps - 1);

    r = GetRValue(startrgb);
    g = GetGValue(startrgb);
    b = GetBValue(startrgb);

    unsigned int step;
    for ( step = 0; step < steps; ++step, ++idx )
      {
        m_ThreatBrushes[idx] = RGB(r,g,b);
        r += step_r;
        g += step_g;
        b += step_b;
        r = min(255.0f, max(0.0f, r));
        g = min(255.0f, max(0.0f, g));
        b = min(255.0f, max(0.0f, b));
      }

    // fill out second steps entries
    startrgb = RGB(192,192,168);
    endrgb   = RGB(192,192, 96);
    step_r   = static_cast<float>(GetRValue(endrgb) - GetRValue(startrgb));
    step_g   = static_cast<float>(GetGValue(endrgb) - GetGValue(startrgb));
    step_b   = static_cast<float>(GetBValue(endrgb) - GetBValue(startrgb));
    step_r  /= (steps - 1);
    step_g  /= (steps - 1);
    step_b  /= (steps - 1);

    r = GetRValue(startrgb);
    g = GetGValue(startrgb);
    b = GetBValue(startrgb);
    for ( step = 0; step < steps; ++step, ++idx )
      {
        m_ThreatBrushes[idx] = RGB(r,g,b);
        r += step_r;
        g += step_g;
        b += step_b;
        r = min(255.0f, max(0.0f, r));
        g = min(255.0f, max(0.0f, g));
        b = min(255.0f, max(0.0f, b));
      }

    // fill out third steps entries
    startrgb = RGB(128,128,112);
    endrgb   = RGB(128,128, 64);
    step_r   = static_cast<float>(GetRValue(endrgb) - GetRValue(startrgb));
    step_g   = static_cast<float>(GetGValue(endrgb) - GetGValue(startrgb));
    step_b   = static_cast<float>(GetBValue(endrgb) - GetBValue(startrgb));
    step_r  /= (steps - 1);
    step_g  /= (steps - 1);
    step_b  /= (steps - 1);

    r = GetRValue(startrgb);
    g = GetGValue(startrgb);
    b = GetBValue(startrgb);
    for ( step = 0; step < steps; ++step, ++idx )
      {
        m_ThreatBrushes[idx] = RGB(r,g,b);
        r += step_r;
        g += step_g;
        b += step_b;
        r = min(255.0f, max(0.0f, r));
        g = min(255.0f, max(0.0f, g));
        b = min(255.0f, max(0.0f, b));
      }
  }


int   ASE_ThreatBoard::GetMaxThreatReach() const
  {
    return static_cast<int>(m_LineOfFireReach);
  }


void  ASE_ThreatBoard::MarkThreatPosition(int aRow, int aCol)
  {
    unsigned int idx;
    idx = GetIndexForRowColumn(aRow, aCol);

    // mark cell on the board
    if ( GetCellValue(idx) == m_kThreatPosition )
      return;

    SetCellValue(idx, m_kThreatPosition);

    // create threat
    ASE_Threat* threat;
    threat = new ASE_Threat(idx);
    AddThreat(threat);
 
    ComputeLinesOfFire();
  }


void  ASE_ThreatBoard::ClearThreatPosition(int aRow, int aCol)
  {
    unsigned int idx;
    idx = GetIndexForRowColumn(aRow, aCol);

    // mark cell on the board
    if ( GetCellValue(idx) == 0 )
      return;

    // remove threat
    if ( GetCellValue(idx) == m_kThreatPosition )
      RemoveThreat(idx);

    // mark cell on the board
    SetCellValue(idx, 0);

    ComputeLinesOfFire();
  }


bool  ASE_ThreatBoard::IsThreatPosition(int aRow, int aCol) const
  {
    return ( m_kThreatPosition == GetCellValue(aRow, aCol) );
  }


bool  ASE_ThreatBoard::IsThreatPosition(unsigned int anIndex) const
  {
    return ( m_kThreatPosition == GetCellValue(anIndex) );
  }


void      ASE_ThreatBoard::SetRiskModus(RiskModus aRiskModus)
  {
    assert(   ( aRiskModus == eAnyLineOfFire                 )
           || ( aRiskModus == eMinLineOfFireDistance         )
           || ( aRiskModus == eMinLineOfFireCount            )
           || ( aRiskModus == eMinLineOfFireCountAndDistance )
          );
    m_RiskModus = aRiskModus;
  }


ASE_ThreatBoard::RiskModus ASE_ThreatBoard::GetRiskModus() const
  {
    return m_RiskModus;
  }


COLORREF ASE_ThreatBoard::GetCellColorForOffset(unsigned int anIndex, CellValue anOffset) const
  {
    assert( !IsEmptyCell(anIndex) );

    CellValue value;
    value = GetCellValue(anIndex);

    unsigned int idx;
    idx  = anOffset * GetNumberOfValues();
    idx += static_cast<unsigned int>(value);

    return m_ThreatBrushes[idx];
  }


COLORREF ASE_ThreatBoard::GetLineOfFireColor() const
  {
    return m_ThreatBrushes[GetNumberOfValues() * (m_kThreatLineOfFire - 1)];
  }


unsigned int ASE_ThreatBoard::GetAssumedThreatMovement() const
  {
    return m_ThreatMovement;
  }


void         ASE_ThreatBoard::SetAssumedThreatMovement(unsigned int theAssumedThreatMovement)
  {
    m_ThreatMovement = theAssumedThreatMovement;
  }


void ASE_ThreatBoard::ClearLinesOfFire()
  {
    const unsigned int maxidx = GetNumberOfColumns() * GetNumberOfRows();

    for ( unsigned int idx = 0; idx < maxidx; ++idx )
      {
        if ( GetCellValue(idx) != m_kThreatPosition )
          {
            SetCellValue(idx, 0);
          } 
      }
  }


void ASE_ThreatBoard::InitializeLinesOfFire()
  {
    // clear old threats
    RemoveAllThreats();

    // locate new threats
	  for ( unsigned int idx = 0; 
          idx < (GetNumberOfRows() * GetNumberOfColumns()); 
          ++idx
        )
      {
        if ( GetCellValue(idx) == m_kThreatPosition )
          {
            ASE_Threat* threat;
            threat = new ASE_Threat(idx);
            AddThreat(threat);
          }
		  }
    ComputeLinesOfFire();
  }


void ASE_ThreatBoard::ComputeLinesOfFire()
  {
    ClearLinesOfFire();

	  for ( unsigned int r = 0; r < GetNumberOfRows(); ++r ) 
      {
    	  for ( unsigned int c = 0; c < GetNumberOfColumns(); ++c ) 
          {
            if ( GetCellValue(r, c) == m_kThreatPosition )
              {
                ComputeLinesOfFireForMovingThreat(r, c, m_ThreatMovement);
              }
          }
		  }

    // select appropriate cell value function
    typedef CellValue (ASE_ThreatBoard::*MemberFnDetermineRisk)(unsigned int anIndex) const;
    MemberFnDetermineRisk pMemberFunction;

    if ( m_RiskModus == eAnyLineOfFire )
      pMemberFunction = DetermineLineOfFireRiskAnyLOF;
    else
    if ( m_RiskModus == eMinLineOfFireDistance )
      pMemberFunction = DetermineLineOfFireRiskMinDistance;
    else
    if ( m_RiskModus == eMinLineOfFireCount )
      pMemberFunction = DetermineLineOfFireRiskLOFCount;
    else
    if ( m_RiskModus == eMinLineOfFireCountAndDistance )
      pMemberFunction = DetermineLineOfFireRiskDistanceLOFCount;
    else
      {
        assert( !"unsupported risk modus" );
      }

    // now start marking lines of fire
    ThreatList::const_iterator threat;
    for ( threat = m_Threats.begin(); threat != m_Threats.end(); ++threat )
      {
        const ASE_Threat::PositionsUnderFire* positionsunderfire;
        positionsunderfire = (*threat)->GetPositionsUnderFire();
        assert( !positionsunderfire->empty() );

        ASE_Threat::PositionsUnderFire::const_iterator position;
        for ( position =  positionsunderfire->begin(); 
              position != positionsunderfire->end();
              ++position
            )
          {
            if ( IsEmptyCell(*position) )
              {
                // call member function via pointer to member function
                SetCellValue(*position, (this->*pMemberFunction)(*position));
              }
          }
      }
  }


void ASE_ThreatBoard::ComputeLinesOfFireForMovingThreat
                   (unsigned int   aRow, 
                    unsigned int   aCol, 
                    unsigned int   aMaximumMovement
                   )
  {
    CoordPairList theReachablePositions;
    theReachablePositions.reserve( (2 + aMaximumMovement) * (2 + aMaximumMovement) );
    ConstructPossibleThreatPositions(aRow, aCol, aMaximumMovement, theReachablePositions);
    assert( !theReachablePositions.empty() );

    CoordPairList theCoveredPositions;
    theCoveredPositions.reserve((m_LineOfFireReach+aMaximumMovement) * (m_LineOfFireReach+aMaximumMovement) * 4);

    CoordPairList::const_iterator position;
    for ( position =  theReachablePositions.begin();
          position != theReachablePositions.end();
          ++position
        )
      {
        ComputeLinesOfFireFromCell(position->x, position->y, theCoveredPositions);
      }
    assert( !theCoveredPositions.empty() );

    // now set these locations as under fire by this threat
    ASE_Threat::PositionsUnderFire positionsUnderFire;
    positionsUnderFire.reserve(theCoveredPositions.size());

    CoordPairList::const_iterator coveredposition;
    for ( coveredposition =  theCoveredPositions.begin();
          coveredposition != theCoveredPositions.end();
          ++coveredposition
        )

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -