Initial commit of Command & Conquer Generals and Command & Conquer Generals Zero Hour source code.
This commit is contained in:
parent
2e338c00cb
commit
3d0ee53a05
6072 changed files with 2283311 additions and 0 deletions
196
Generals/Code/GameEngine/Include/Common/SparseMatchFinder.h
Normal file
196
Generals/Code/GameEngine/Include/Common/SparseMatchFinder.h
Normal file
|
@ -0,0 +1,196 @@
|
|||
/*
|
||||
** Command & Conquer Generals(tm)
|
||||
** Copyright 2025 Electronic Arts Inc.
|
||||
**
|
||||
** This program is free software: you can redistribute it and/or modify
|
||||
** it under the terms of the GNU General Public License as published by
|
||||
** the Free Software Foundation, either version 3 of the License, or
|
||||
** (at your option) any later version.
|
||||
**
|
||||
** This program is distributed in the hope that it will be useful,
|
||||
** but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
** GNU General Public License for more details.
|
||||
**
|
||||
** You should have received a copy of the GNU General Public License
|
||||
** along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// //
|
||||
// (c) 2001-2003 Electronic Arts Inc. //
|
||||
// //
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// FILE: SparseMatchFinder.h /////////////////////////////////////////////////////////////////////////
|
||||
// Author: Steven Johnson, March 2002
|
||||
// Desc:
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#pragma once
|
||||
|
||||
#ifndef __SparseMatchFinder_H_
|
||||
#define __SparseMatchFinder_H_
|
||||
|
||||
// INCLUDES ///////////////////////////////////////////////////////////////////////////////////////
|
||||
#include "Common/BitFlags.h"
|
||||
#include "Common/STLTypedefs.h"
|
||||
|
||||
#if defined(_DEBUG) || defined(_INTERNAL)
|
||||
#define SPARSEMATCH_DEBUG
|
||||
#else
|
||||
#undef SPARSEMATCH_DEBUG
|
||||
#endif
|
||||
|
||||
//-------------------------------------------------------------------------------------------------
|
||||
template<class MATCHABLE, class BITSET>
|
||||
class SparseMatchFinder
|
||||
{
|
||||
private:
|
||||
|
||||
//-------------------------------------------------------------------------------------------------
|
||||
// TYPEDEFS
|
||||
//-------------------------------------------------------------------------------------------------
|
||||
|
||||
struct HashMapHelper
|
||||
{
|
||||
size_t operator()(const BITSET& p) const
|
||||
{
|
||||
/// @todo srj -- provide a better hash function for BITSET
|
||||
size_t result = 0;
|
||||
|
||||
for (int i = 0; i < p.size(); ++i)
|
||||
if (p.test(i))
|
||||
result += (i + 1);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
Bool operator()(const BITSET& a, const BITSET& b) const
|
||||
{
|
||||
return (a == b);
|
||||
}
|
||||
};
|
||||
|
||||
//-------------------------------------------------------------------------------------------------
|
||||
typedef std::hash_map< BITSET, const MATCHABLE*, HashMapHelper, HashMapHelper > MatchMap;
|
||||
|
||||
//-------------------------------------------------------------------------------------------------
|
||||
// MEMBER VARS
|
||||
//-------------------------------------------------------------------------------------------------
|
||||
|
||||
mutable MatchMap m_bestMatches;
|
||||
|
||||
//-------------------------------------------------------------------------------------------------
|
||||
// METHODS
|
||||
//-------------------------------------------------------------------------------------------------
|
||||
|
||||
//-------------------------------------------------------------------------------------------------
|
||||
inline static Int countConditionIntersection(const BITSET& a, const BITSET& b)
|
||||
{
|
||||
return a.countIntersection(b);
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------------------------------------
|
||||
inline static Int countConditionInverseIntersection(const BITSET& a, const BITSET& b)
|
||||
{
|
||||
return a.countInverseIntersection(b);
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------------------------------------
|
||||
const MATCHABLE* findBestInfoSlow(const std::vector<MATCHABLE>& v, const BITSET& bits) const
|
||||
{
|
||||
const MATCHABLE* result = NULL;
|
||||
Int bestYesMatch = 0; // want to maximize this
|
||||
Int bestYesExtraneousBits = 999; // want to minimize this
|
||||
|
||||
#ifdef SPARSEMATCH_DEBUG
|
||||
Int numDupMatches = 0;
|
||||
AsciiString curBestMatchStr, dupMatchStr;
|
||||
#endif
|
||||
|
||||
for (std::vector<MATCHABLE>::const_iterator it = v.begin(); it != v.end(); ++it)
|
||||
{
|
||||
for (Int i = it->getConditionsYesCount()-1; i >= 0; --i)
|
||||
{
|
||||
const BITSET& yesFlags = it->getNthConditionsYes(i);
|
||||
|
||||
// the best match has the most "yes" matches and the smallest number of "no" matches.
|
||||
// if there are ties, then prefer the model with the smaller number of irrelevant 'yes' bits.
|
||||
// (example of why tiebreaker is necessary: if we want to match FRONTCRUSHED,
|
||||
// it would tie with both FRONTCRUSHED and FRONTCRUSHED|BACKCRUSHED, since they
|
||||
// both match a single YES bit.)
|
||||
Int yesMatch = countConditionIntersection(bits, yesFlags);
|
||||
Int yesExtraneousBits = countConditionInverseIntersection(bits, yesFlags);
|
||||
|
||||
#ifdef SPARSEMATCH_DEBUG
|
||||
if (yesMatch == bestYesMatch &&
|
||||
yesExtraneousBits == bestYesExtraneousBits)
|
||||
{
|
||||
++numDupMatches;
|
||||
dupMatchStr = it->getDescription();
|
||||
}
|
||||
#endif
|
||||
|
||||
if ((yesMatch > bestYesMatch) ||
|
||||
(yesMatch >= bestYesMatch && yesExtraneousBits < bestYesExtraneousBits))
|
||||
{
|
||||
result = &(*it);
|
||||
bestYesMatch = yesMatch;
|
||||
bestYesExtraneousBits = yesExtraneousBits;
|
||||
#ifdef SPARSEMATCH_DEBUG
|
||||
numDupMatches = 0;
|
||||
curBestMatchStr = it->getDescription();
|
||||
#endif
|
||||
}
|
||||
} // end for i
|
||||
|
||||
} // end for it
|
||||
|
||||
#ifdef SPARSEMATCH_DEBUG
|
||||
if (numDupMatches > 0)
|
||||
{
|
||||
AsciiString curConditionStr;
|
||||
bits.buildDescription(&curConditionStr);
|
||||
DEBUG_CRASH(("ambiguous model match in findBestInfoSlow \n\nbetween \n(%s)\n<and>\n(%s)\n\n(%d extra matches found)\n\ncurrent bits are (\n%s)\n",
|
||||
curBestMatchStr.str(),
|
||||
dupMatchStr.str(),
|
||||
numDupMatches,
|
||||
curConditionStr.str()));
|
||||
}
|
||||
#endif
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------------------------------------
|
||||
public:
|
||||
|
||||
//-------------------------------------------------------------------------------------------------
|
||||
void clear()
|
||||
{
|
||||
m_bestMatches.clear();
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------------------------------------
|
||||
const MATCHABLE* findBestInfo(const std::vector<MATCHABLE>& v, const BITSET& bits) const
|
||||
{
|
||||
MatchMap::const_iterator it = m_bestMatches.find(bits);
|
||||
if (it != m_bestMatches.end())
|
||||
{
|
||||
return (*it).second;
|
||||
}
|
||||
|
||||
const MATCHABLE* info = findBestInfoSlow(v, bits);
|
||||
|
||||
DEBUG_ASSERTCRASH(info != NULL, ("no suitable match for criteria was found!\n"));
|
||||
if (info != NULL)
|
||||
m_bestMatches[bits] = info;
|
||||
|
||||
return info;
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
#endif // __SparseMatchFinder_H_
|
||||
|
Reference in a new issue