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

📄 asedoc.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"
 */

/* Copyright (C) James Matthews, 2001. 
 * 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) James Matthews, 2001"
 */

// aseDoc.cpp : implementation of the CAseDoc class
//

#include "stdafx.h"
#include "ase.h"

#include "nodeview.h"

#include "aseDoc.h"
#include "aseView.h"
#include "mainfrm.h"

#include <cmath>

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

/////////////////////////////////////////////////////////////////////////////
// CAseDoc

IMPLEMENT_DYNCREATE(CAseDoc, CDocument)

BEGIN_MESSAGE_MAP(CAseDoc, CDocument)
	//{{AFX_MSG_MAP(CAseDoc)
	ON_COMMAND(ID_RUNTOBREAKPOINT, OnRunToBreakpoint)
	ON_UPDATE_COMMAND_UI(ID_RUNTOBREAKPOINT, OnUpdateRunToBreakpoint)
	ON_COMMAND(ID_EXECUTEASTAR, OnExecuteAStar)
	ON_COMMAND(ID_STEPASTAR, OnStepAStar)
	ON_COMMAND(ID_VIEW_AROUTE, OnViewARoute)
	ON_UPDATE_COMMAND_UI(ID_VIEW_AROUTE, OnUpdateViewARoute)
	ON_COMMAND(ID_PATHING_CONTINUOUSUPDATE, OnPathingContinuousUpdate)
	ON_UPDATE_COMMAND_UI(ID_PATHING_CONTINUOUSUPDATE, OnUpdatePathingContinuousUpdate)
	ON_COMMAND(ID_VIEW_SEARCHSPACE, OnViewSearchspace)
	ON_UPDATE_COMMAND_UI(ID_VIEW_SEARCHSPACE, OnUpdateViewSearchspace)
	//}}AFX_MSG_MAP
	ON_COMMAND_RANGE(ID_WEIGHT0, ID_ENEMYPOSITION, OnBrushType)	
	ON_UPDATE_COMMAND_UI_RANGE(ID_WEIGHT0, ID_ENEMYPOSITION, OnUpdateUIBrushType)	
	ON_COMMAND_RANGE(ID_PATHING_BREAKPOINTS_POINT, ID_PATHING_BREAKPOINTS_NEWCHILD, OnBreakpointType)	
	ON_UPDATE_COMMAND_UI_RANGE(ID_PATHING_BREAKPOINTS_POINT, ID_PATHING_BREAKPOINTS_NEWCHILD, OnUpdateUIBreakpointType)	

	ON_COMMAND(ID_VIEW_LOF, OnViewLineOfFire)
	ON_UPDATE_COMMAND_UI(ID_VIEW_LOF, OnUpdateUIViewLineOfFire)
	ON_COMMAND(ID_VIEW_THREATS, OnViewThreats)
	ON_UPDATE_COMMAND_UI(ID_VIEW_THREATS, OnUpdateUIViewThreats)
	ON_COMMAND(ID_THREATCOSTS_DISTANCETOTHREAT, OnThreatDistanceBasedCosts)
	ON_UPDATE_COMMAND_UI(ID_THREATCOSTS_DISTANCETOTHREAT, OnUpdateUIThreatDistanceBasedCosts)
	ON_COMMAND(ID_VIEW_APPROX_LOF, OnViewApproximatedLinesOfFire)
	ON_UPDATE_COMMAND_UI(ID_VIEW_APPROX_LOF, OnUpdateUIViewApproximatedLinesOfFire)
	ON_COMMAND(ID_THREATCOSTS_THREATCOUNT, OnThreatCountBasedCosts)
	ON_UPDATE_COMMAND_UI(ID_THREATCOSTS_THREATCOUNT, OnUpdateUIThreatCountBasedCosts)
	ON_COMMAND(ID_THREATCOSTS_APPROXLUT, OnThreatFromApproxTableCosts)
	ON_UPDATE_COMMAND_UI(ID_THREATCOSTS_APPROXLUT, OnUpdateUIThreatFromApproxTableCosts)

	ON_COMMAND_RANGE(ID_MOVEMENT_MANHATTAN, ID_MOVEMENT_DIAGONAL, OnMovementType)	
	ON_UPDATE_COMMAND_UI_RANGE(ID_MOVEMENT_MANHATTAN, ID_MOVEMENT_DIAGONAL, OnUpdateUIMovementType)	
	ON_COMMAND_RANGE(ID_MOVEMENTCOSTS_CELL, ID_MOVEMENTCOSTS_RELATIVE, OnMovementCosts)	
	ON_UPDATE_COMMAND_UI_RANGE(ID_MOVEMENTCOSTS_CELL, ID_MOVEMENTCOSTS_RELATIVE, OnUpdateUIMovementCosts)	

	ON_COMMAND_RANGE(ID_THREATCOSTS_NONE, ID_THREATCOSTS_LOFWITHMEMORY, OnThreatCosts)	
	ON_UPDATE_COMMAND_UI_RANGE(ID_THREATCOSTS_NONE, ID_THREATCOSTS_LOFWITHMEMORY, OnUpdateUIThreatCosts)	
	ON_COMMAND_RANGE(ID_THREATMOVEMENT_0, ID_THREATMOVEMENT_2, OnThreatMovement)	
	ON_UPDATE_COMMAND_UI_RANGE(ID_THREATMOVEMENT_0, ID_THREATMOVEMENT_2, OnUpdateUIThreatMovement)	
END_MESSAGE_MAP()

/////////////////////////////////////////////////////////////////////////////
// CAseDoc construction/destruction

CAseDoc::CAseDoc()
: m_TerrainBoard(ASE_BOARDX, ASE_BOARDY),
  m_ThreatBoard(ASE_BOARDX, ASE_BOARDY, &m_TerrainBoard),
  m_SearchSpaceBoard(ASE_BOARDX, ASE_BOARDY, &m_TerrainBoard),
  m_LOSApproximationBoard(ASE_BOARDX, ASE_BOARDY, &m_TerrainBoard, &m_ThreatBoard),
  // movement type
  m_bMovementDiagonal(false),
  // movement costs
  m_bMovementCostsVectorBased(false),
  m_bMovementCostsRelative(false),
  // threat costs
  m_bThreatCostsNone(true),
  m_bThreatCostsSimple(false),
  m_bThreatLineOfFireWithAimingCosts(false),
  m_bThreatCountCosts(false),
  m_bDistanceToThreatCosts(false),
  m_bThreatCostsFromApproximatedTable(false),
  // views
  m_bSearchSpace(true),
  m_bThreatPositions(true),
  m_bThreatLinesOfFire(true),
  m_bDrawApproximatedLinesOfFire(false),
  m_bDrawRoute(true)
{
	m_bContinualUpdate        = false;
	m_uBrushType              = 0;
}

CAseDoc::~CAseDoc()
{
}

BOOL CAseDoc::OnNewDocument()
{
	if (!CDocument::OnNewDocument())
		return FALSE;

  m_TerrainBoard.Clear();
  m_ThreatBoard.Clear();
  m_SearchSpaceBoard.Clear();

	m_cStart.x = -1;
	m_cEnd.x = -1;
	m_cBreakpoint.x = -1;
	m_iBreakData = -1;
	m_bStepped = false;

	m_cAStar.Reset();
	m_bDrawRoute = false;

	return TRUE;
}

BOOL CAseDoc::OnOpenDocument(LPCTSTR lpszPathName) 
{
	if (!CDocument::OnOpenDocument(lpszPathName))
		return FALSE;
	
	m_bStepped = false;
	m_cBreakpoint.x = -1;
	m_iBreakData = -1;
	
	m_cAStar.Reset();
	m_bDrawRoute = false;

  m_SearchSpaceBoard.Clear();

	return TRUE;
}


/////////////////////////////////////////////////////////////////////////////
// CAseDoc serialization

void CAseDoc::Serialize(CArchive& ar)
{
	int x = ASE_BOARDX, y = ASE_BOARDY;

	if (ar.IsStoring()) 
    {
		  ar << x;
		  ar << y;
		  ar << m_cStart;
		  ar << m_cEnd;

      m_TerrainBoard.WriteBoard(ar);
      // writes threats after original board, so remain compatible
      m_ThreatBoard.WriteBoard(ar);
	  } 
  else 
    {
		  ar >> x;
		  ar >> y;
		  ar >> m_cStart;
		  ar >> m_cEnd;

      m_TerrainBoard.ReadBoard(ar);
      // reads threats after original board, to remain compatible
      m_ThreatBoard.Clear();

      // test whether any threat data might be included - dirty
      CFile* file;
      file = ar.GetFile();

      unsigned long bytesAvailable;
      bytesAvailable = static_cast<unsigned long>(file->GetLength() - file->GetPosition());
      if ( bytesAvailable > 0 )
        {
          m_ThreatBoard.ReadBoard(ar);
        }

      // disable button
      m_bDrawApproximatedLinesOfFire = false;

      m_ThreatBoard.InitializeLinesOfFire();
      m_LOSApproximationBoard.Clear();
	  }
}


void CAseDoc::SetStatusBarText(const char* aText)
  {
  	CMainFrame* pMfm = STATIC_DOWNCAST(CMainFrame, AfxGetMainWnd());
    CStatusBar* statusbar = pMfm->GetStatusBar();

    statusbar->SetPaneText(0, aText);
  }


/////////////////////////////////////////////////////////////////////////////
// CAseDoc diagnostics

#ifdef _DEBUG
void CAseDoc::AssertValid() const
{
	CDocument::AssertValid();
}

void CAseDoc::Dump(CDumpContext& dc) const
{
	CDocument::Dump(dc);
}
#endif //_DEBUG

/////////////////////////////////////////////////////////////////////////////
// CAseDoc commands

int CAseDoc::AS_Valid(_asNode *parent, _asNode *node, int data, void *pointer) 
{
	int x       = node->GetX();
  int y       = node->GetY();
	CAseDoc *me = reinterpret_cast<CAseDoc *>(pointer);

  if ( !me->GetTerrainBoard()->IsValidTerrainMove(parent->GetX(), parent->GetY(), x, y) )
    return false;

  // check for invalid diagonal movement
  if ( !me->DoesUseDiagonalMovement() )
    {
		  int px = parent->GetX();
		  int py = parent->GetY();

      return (   ( px == x )
              || ( py == y )
             );
    }
  else
    return true;
}


void CAseDoc::NodeAdded(_asNode *node, int data) 
{
	if (m_cBreakpoint.x == -1 && m_iBreakData == -1) return;


  //! \todo rewrite to single expression
	if (   node->GetX() == m_cBreakpoint.x 
      && node->GetY() == m_cBreakpoint.y
     ) 
    {
		  m_bBreakpointHit = true;
		  m_pcBreakNode = node;
	  } 
	
	if (data == m_iBreakData) {
		m_bBreakpointHit = true;
		m_pcBreakNode = node;
	}
}

CNodeView *CAseDoc::GetNodeView()
{
	POSITION pos;
	pos = GetFirstViewPosition();

	CNodeView *nv = reinterpret_cast<CNodeView *>(GetNextView(pos));

	return nv;
}

CAseView *CAseDoc::GetAseView()
{
	CMainFrame* pMfm = STATIC_DOWNCAST(CMainFrame, AfxGetMainWnd());
	CAseView *view = reinterpret_cast<CAseView *>(pMfm->GetRightPane());
	
	return view;
}


void CAseDoc::SelectMovementCostFunctions()
  {
    // set appropriate terrain cost function
    if ( DoesUseRelativeMovementCosts() )
      {
    	  m_cAStar.udTerrainCost      = ASE_Costs::CellBasedRelativeMovementCosts;
        m_cAStar.udTerrainHeuristic = ASE_Costs::CellBasedRelativeMovementHeuristic;
      }
    else
    if ( DoesUseVectorBasedMovementCosts() )
      {
    	  m_cAStar.udTerrainCost      = ASE_Costs::VectorBasedNormalMovementCosts;
        m_cAStar.udTerrainHeuristic = ASE_Costs::VectorBasedNormalMovementHeuristic;
      }
    else // cell based
      {
    	  m_cAStar.udTerrainCost      = ASE_Costs::CellBasedNormalMovementCosts;
        m_cAStar.udTerrainHeuristic = ASE_Costs::CellBasedNormalMovementHeuristic;
      }
  }


void CAseDoc::SelectThreatCostFunctions()
  {
    // no prediction of remaining threat costs
    const char* pStatusBarText;

    m_cAStar.udThreatHeuristic = ASE_Costs::ThreatsAnyModeAnyMovementHeuristic;
    pStatusBarText = "A* search: traditional shortest path";

    // select cost function as follows
    // - approximated lof table
    // - distance + count
    // - distance
    // - count
    // - no distance, no count
    // - none
    // and for each of these categories, distinguish aiming, vector/cell based

    if ( DoesUseThreatCostsFromApproxTable() )
       {
        if ( DoesUseAimingThreatCosts() )
          {
            if ( DoesUseVectorBasedMovementCosts() )
              {
                m_cAStar.udThreatCost = ASE_Costs::VectorBasedThreatsApproximateLOFAimingCosts;
              }
            else
              {
                m_cAStar.udThreatCost = ASE_Costs::CellBasedThreatsApproximateLOFAimingCosts;
              }
            pStatusBarText = "A* search: tactical, using costs from approximated small lookup table, taking into account aiming";
          } 
        else
          {
            if ( DoesUseVectorBasedMovementCosts() )
              {
                m_cAStar.udThreatCost = ASE_Costs::VectorBasedThreatsApproximateLOFSimpleCosts;
              }
            else
              {
                m_cAStar.udThreatCost = ASE_Costs::CellBasedThreatsApproximateLOFSimpleCosts;
              }
            pStatusBarText = "A* search: tactical, using costs from approximated small lookup table";
          } 
       }
    else
    if (   ( DoesUseDistanceToThreatCosts() )
        && ( DoesUseThreatCountCosts() )
       )
      {
        if ( DoesUseAimingThreatCosts() )
          {
            if ( DoesUseVectorBasedMovementCosts() )
              {
                m_cAStar.udThreatCost = ASE_Costs::VectorBasedDistanceAndCountBasedAimingCosts;
              }
            else
              {
                m_cAStar.udThreatCost = ASE_Costs::CellBasedDistanceAndCountBasedAimingCosts;
              }
            pStatusBarText = "A* search: tactical, using exact distance and threat count costs, taking into account aiming";
          }
        else
          {
            if ( DoesUseVectorBasedMovementCosts() )
              {
                m_cAStar.udThreatCost = ASE_Costs::VectorBasedDistanceAndCountBasedSimpleCosts;
              }
            else
              {
                m_cAStar.udThreatCost = ASE_Costs::CellBasedDistanceAndCountBasedSimpleCosts;
              }
            pStatusBarText = "A* search: tactical, using exact distance and threat count costs";
          }
      }
    else
    if ( DoesUseDistanceToThreatCosts() )
      {
        if ( DoesUseAimingThreatCosts() )
          {
            if ( DoesUseVectorBasedMovementCosts() )
              {
                m_cAStar.udThreatCost = ASE_Costs::VectorBasedDistanceBasedAimingCosts;
              }
            else
              {
                m_cAStar.udThreatCost = ASE_Costs::CellBasedDistanceBasedAimingCosts;
              }
            pStatusBarText = "A* search: tactical, using exact distance to threat costs, taking into account aiming";
          }
        else
          {
            if ( DoesUseVectorBasedMovementCosts() )
              {
                m_cAStar.udThreatCost = ASE_Costs::VectorBasedDistanceBasedSimpleCosts;
              }
            else
              {
                m_cAStar.udThreatCost = ASE_Costs::CellBasedDistanceBasedSimpleCosts;
              }
            pStatusBarText = "A* search: tactical, using exact distance to threat costs";
          }
      }
    else
    if ( DoesUseThreatCountCosts() )
      {
        if ( DoesUseAimingThreatCosts() )
          {
            if ( DoesUseVectorBasedMovementCosts() )
              {
                m_cAStar.udThreatCost = ASE_Costs::VectorBasedCountBasedAimingCosts;
              }
            else
              {
                m_cAStar.udThreatCost = ASE_Costs::CellBasedCountBasedAimingCosts;
              }
            pStatusBarText = "A* search: tactical, using exact threat count costs, taking into account aiming";
          }
        else
          {
            if ( DoesUseVectorBasedMovementCosts() )
              {
                m_cAStar.udThreatCost = ASE_Costs::VectorBasedCountBasedSimpleCosts;
              }
            else
              {
                m_cAStar.udThreatCost = ASE_Costs::CellBasedCountBasedSimpleCosts;
              }
            pStatusBarText = "A* search: tactical, using exact threat count costs";
          }
      }
    else
    if ( DoesUseThreatCosts() )
      {
        if ( DoesUseAimingThreatCosts() )
          {
            if ( DoesUseVectorBasedMovementCosts() )
              {
                m_cAStar.udThreatCost = ASE_Costs::VectorBasedThreatsAimingCosts;
              }
            else
              {
                m_cAStar.udThreatCost = ASE_Costs::CellBasedThreatsAimingCosts;
              }
            pStatusBarText = "A* search: tactical, using exact simple threat line-of-fire costs, taking into account aiming";
          }
        else
          {
            if ( DoesUseVectorBasedMovementCosts() )
              {
                m_cAStar.udThreatCost = ASE_Costs::VectorBasedThreatsSimpleCosts;
              }
            else
              {
                m_cAStar.udThreatCost = ASE_Costs::CellBasedThreatsSimpleCosts;
              }
            pStatusBarText = "A* search: tactical, using exact simple threat line-of-fire costs";
          }
      }
    else
      {
        m_cAStar.udThreatCost = ASE_Costs::ThreatsNoCosts;
      }

    SetStatusBarText(pStatusBarText);
  }


bool CAseDoc::SetupAStar(bool stepped/* = false*/)
{
	if (m_cStart.x == -1 || m_cEnd.x == -1) {
		MessageBox("Please ensure that both the start and end points are specified.\nA red and green square denote the start and end points, respectively.", "A* Explorer", MB_ICONERROR);
		return false;
	}

	CNodeView *nv = GetNodeView();
	GetAseView()->RemoveHighlight();

  assert( m_TerrainBoard.GetNumberOfRows() == ASE_BOARDX );
	m_cAStar.SetRows(ASE_BOARDX);
	m_cAStar.udValid = AS_Valid;

  ASE_Costs::SetTerrainBoard(GetTerrainBoard());
  ASE_Costs::SetThreatBoard(GetThreatBoard());
  ASE_Costs::SetLOFApproximationBoard(GetLOSApproximationBoard());

  SelectMovementCostFunctions();
  SelectThreatCostFunctions();

  if ( m_bThreatCostsFromApproximatedTable )
    {
      GetLOSApproximationBoard()->ComputeLinesOfFireApproximation();
    }

	m_cAStar.udNotifyList = CNodeView::OnUpdateList;

⌨️ 快捷键说明

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