(svn r12431) [NoAI] -Add: added AIEventSubsidiaryOffer, which keeps you informed about new Subsidiaries
/* $Id$ */
/** @file ai_abstractlist.cpp Implementation of AIAbstractList */
#include <squirrel.h>
#include "ai_abstractlist.hpp"
#include "../../debug.h"
/**
* Base class for any AIAbstractList sorter.
*/
class AIAbstractListSorter {
protected:
AIAbstractList *list;
public:
/**
* Virtual dtor, needed to mute warnings.
*/
virtual ~AIAbstractListSorter() { }
/**
* Get the first item of the sorter.
*/
virtual int32 Begin() = 0;
/**
* Get the next item of the sorter.
*/
virtual int32 Next() = 0;
/**
* See if there is a next item of the sorter.
*/
virtual bool HasNext() = 0;
};
/**
* Sort by value, ascending.
*/
class AIAbstractListSorterValueAscending : public AIAbstractListSorter {
private:
AIAbstractList::AIAbstractListBucket::iterator bucket_iter;
AIAbstractList::AIItemList *bucket_list;
AIAbstractList::AIItemList::iterator bucket_list_iter;
public:
AIAbstractListSorterValueAscending(AIAbstractList *list)
{
this->list = list;
this->bucket_list = NULL;
}
int32 Begin()
{
if (this->list->buckets.empty()) return 0;
this->bucket_iter = this->list->buckets.begin();
this->bucket_list = &(*this->bucket_iter).second;
this->bucket_list_iter = this->bucket_list->begin();
return *bucket_list_iter;
}
int32 Next()
{
if (this->list->buckets.empty() || this->bucket_list == NULL) return 0;
this->bucket_list_iter++;
if (this->bucket_list_iter == this->bucket_list->end()) {
this->bucket_iter++;
if (this->bucket_iter == this->list->buckets.end()) return 0;
this->bucket_list = &(*this->bucket_iter).second;
this->bucket_list_iter = this->bucket_list->begin();
}
return *bucket_list_iter;
}
bool HasNext()
{
if (this->list->buckets.empty() || this->bucket_list == NULL) return false;
return this->bucket_iter != this->list->buckets.end() && this->bucket_list_iter != this->bucket_list->end();
}
};
/**
* Sort by value, descending.
*/
class AIAbstractListSorterValueDescending : public AIAbstractListSorter {
private:
AIAbstractList::AIAbstractListBucket::reverse_iterator bucket_iter;
AIAbstractList::AIItemList *bucket_list;
AIAbstractList::AIItemList::reverse_iterator bucket_list_iter;
public:
AIAbstractListSorterValueDescending(AIAbstractList *list)
{
this->list = list;
this->bucket_list = NULL;
}
int32 Begin()
{
if (this->list->buckets.empty()) return 0;
this->bucket_iter = this->list->buckets.rbegin();
this->bucket_list = &(*this->bucket_iter).second;
this->bucket_list_iter = this->bucket_list->rbegin();
return *bucket_list_iter;
}
int32 Next()
{
if (this->list->buckets.empty() || this->bucket_list == NULL) return 0;
this->bucket_list_iter++;
if (this->bucket_list_iter == this->bucket_list->rend()) {
this->bucket_iter++;
if (this->bucket_iter == this->list->buckets.rend()) return 0;
this->bucket_list = &(*this->bucket_iter).second;
this->bucket_list_iter = this->bucket_list->rbegin();
}
return *bucket_list_iter;
}
bool HasNext()
{
if (this->list->buckets.empty() || this->bucket_list == NULL) return false;
return this->bucket_iter != this->list->buckets.rend() && this->bucket_list_iter != this->bucket_list->rend();
}
};
/**
* Sort by item, ascending.
*/
class AIAbstractListSorterItemAscending : public AIAbstractListSorter {
private:
AIAbstractList::AIAbstractListMap::iterator item_iter;
public:
AIAbstractListSorterItemAscending(AIAbstractList *list)
{
this->list = list;
}
int32 Begin()
{
if (this->list->items.empty()) return 0;
this->item_iter = this->list->items.begin();
return (*this->item_iter).first;
}
int32 Next()
{
if (this->list->items.empty()) return 0;
this->item_iter++;
return (*this->item_iter).first;
}
bool HasNext()
{
if (this->list->items.empty()) return false;
return this->item_iter != this->list->items.end();
}
};
/**
* Sort by item, descending.
*/
class AIAbstractListSorterItemDescending : public AIAbstractListSorter {
private:
AIAbstractList::AIAbstractListMap::reverse_iterator item_iter;
public:
AIAbstractListSorterItemDescending(AIAbstractList *list)
{
this->list = list;
}
int32 Begin()
{
if (this->list->items.empty()) return 0;
this->item_iter = this->list->items.rbegin();
return (*this->item_iter).first;
}
int32 Next()
{
if (this->list->items.empty()) return 0;
this->item_iter++;
return (*this->item_iter).first;
}
bool HasNext()
{
if (this->list->items.empty()) return false;
return this->item_iter != this->list->items.rend();
}
};
AIAbstractList::AIAbstractList()
{
/* Default sorter */
this->sorter = new AIAbstractListSorterValueDescending(this);
this->sorter_type = SORT_BY_VALUE;
this->sort_ascending = false;
this->initialized = false;
}
AIAbstractList::~AIAbstractList()
{
delete this->sorter;
}
bool AIAbstractList::HasItem(int32 item)
{
return this->items.count(item) == 1;
}
void AIAbstractList::Clear()
{
this->items.clear();
this->buckets.clear();
}
void AIAbstractList::AddItem(int32 item)
{
if (this->HasItem(item)) return;
this->items[item] = 0;
this->buckets[0].insert(item);
}
void AIAbstractList::RemoveItem(int32 item)
{
if (!this->HasItem(item)) return;
this->buckets[this->GetValue(item)].erase(item);
if (this->buckets[this->GetValue(item)].empty()) this->buckets.erase(this->GetValue(item));
this->items.erase(item);
}
int32 AIAbstractList::Begin()
{
this->initialized = true;
return this->sorter->Begin();
}
int32 AIAbstractList::Next()
{
if (this->initialized == false) {
DEBUG(ai, 0, "ERROR: Next() is invalid as Begin() is never called");
return false;
}
return this->sorter->Next();
}
bool AIAbstractList::IsEmpty()
{
return this->items.empty();
}
bool AIAbstractList::HasNext()
{
if (this->initialized == false) {
DEBUG(ai, 0, "ERROR: HasNext() is invalid as Begin() is never called");
return false;
}
return this->sorter->HasNext();
}
int32 AIAbstractList::Count()
{
return this->items.size();
}
int32 AIAbstractList::GetValue(int32 item)
{
if (!this->HasItem(item)) return 0;
return this->items[item];
}
bool AIAbstractList::SetValue(int32 item, int32 value)
{
if (!this->HasItem(item)) return false;
this->buckets[this->GetValue(item)].erase(item);
if (this->buckets[this->GetValue(item)].empty()) this->buckets.erase(this->GetValue(item));
this->items[item] = value;
this->buckets[value].insert(item);
return true;
}
void AIAbstractList::Sort(SorterType sorter, bool ascending)
{
if (sorter == this->sorter_type && ascending == this->sort_ascending) return;
delete this->sorter;
switch (sorter) {
case SORT_BY_ITEM:
if (ascending) this->sorter = new AIAbstractListSorterItemAscending(this);
else this->sorter = new AIAbstractListSorterItemDescending(this);
break;
case SORT_BY_VALUE:
if (ascending) this->sorter = new AIAbstractListSorterValueAscending(this);
else this->sorter = new AIAbstractListSorterValueDescending(this);
break;
default:
this->Sort(SORT_BY_ITEM, false);
return;
}
this->sorter_type = sorter;
this->sort_ascending = ascending;
}
void AIAbstractList::AddList(AIAbstractList *list)
{
AIAbstractListMap *list_items = &list->items;
for (AIAbstractListMap::iterator iter = list_items->begin(); iter != list_items->end(); iter++) {
this->AddItem((*iter).first);
this->SetValue((*iter).first, (*iter).second);
}
}
void AIAbstractList::RemoveAboveValue(int32 value)
{
for (AIAbstractListMap::iterator next_iter, iter = this->items.begin(); iter != this->items.end(); iter = next_iter) {
next_iter = iter; next_iter++;
if ((*iter).second > value) this->items.erase(iter);
}
for (AIAbstractListBucket::iterator next_iter, iter = this->buckets.begin(); iter != this->buckets.end(); iter = next_iter) {
next_iter = iter; next_iter++;
if ((*iter).first > value) this->buckets.erase(iter);
}
}
void AIAbstractList::RemoveBelowValue(int32 value)
{
for (AIAbstractListMap::iterator next_iter, iter = this->items.begin(); iter != this->items.end(); iter = next_iter) {
next_iter = iter; next_iter++;
if ((*iter).second < value) this->items.erase(iter);
}
for (AIAbstractListBucket::iterator next_iter, iter = this->buckets.begin(); iter != this->buckets.end(); iter = next_iter) {
next_iter = iter; next_iter++;
if ((*iter).first < value) this->buckets.erase(iter);
}
}
void AIAbstractList::RemoveBetweenValue(int32 start, int32 end)
{
for (AIAbstractListMap::iterator next_iter, iter = this->items.begin(); iter != this->items.end(); iter = next_iter) {
next_iter = iter; next_iter++;
if ((*iter).second > start && (*iter).second < end) this->items.erase(iter);
}
for (AIAbstractListBucket::iterator next_iter, iter = this->buckets.begin(); iter != this->buckets.end(); iter = next_iter) {
next_iter = iter; next_iter++;
if ((*iter).first > start && (*iter).first < end) this->buckets.erase(iter);
}
}
void AIAbstractList::RemoveValue(int32 value)
{
for (AIAbstractListMap::iterator next_iter, iter = this->items.begin(); iter != this->items.end(); iter = next_iter) {
next_iter = iter; next_iter++;
if ((*iter).second == value) this->items.erase(iter);
}
for (AIAbstractListBucket::iterator next_iter, iter = this->buckets.begin(); iter != this->buckets.end(); iter = next_iter) {
next_iter = iter; next_iter++;
if ((*iter).first == value) this->buckets.erase(iter);
}
}
void AIAbstractList::RemoveTop(int32 count)
{
if (!this->sort_ascending) {
this->Sort(this->sorter_type, !this->sort_ascending);
this->RemoveBottom(count);
this->Sort(this->sorter_type, !this->sort_ascending);
return;
}
switch (this->sorter_type) {
default: NOT_REACHED();
case SORT_BY_VALUE:
for (AIAbstractListBucket::iterator iter = this->buckets.begin(); iter != this->buckets.end(); iter = this->buckets.begin()) {
AIItemList *items = &(*iter).second;
size_t size = items->size();
for (AIItemList::iterator iter = items->begin(); iter != items->end(); iter = items->begin()) {
if (--count < 0) return;
this->RemoveItem(*iter);
/* When the last item is removed from the bucket, the bucket itself is removed.
* This means that the iterators can be invalid after a call to RemoveItem.
*/
if (--size == 0) break;
}
}
break;
case SORT_BY_ITEM:
for (AIAbstractListMap::iterator iter = this->items.begin(); iter != this->items.end(); iter = this->items.begin()) {
if (--count < 0) return;
this->RemoveItem((*iter).first);
}
break;
}
}
void AIAbstractList::RemoveBottom(int32 count)
{
if (!this->sort_ascending) {
this->Sort(this->sorter_type, !this->sort_ascending);
this->RemoveTop(count);
this->Sort(this->sorter_type, !this->sort_ascending);
return;
}
switch (this->sorter_type) {
default: NOT_REACHED();
case SORT_BY_VALUE:
for (AIAbstractListBucket::reverse_iterator iter = this->buckets.rbegin(); iter != this->buckets.rend(); iter = this->buckets.rbegin()) {
AIItemList *items = &(*iter).second;
size_t size = items->size();
for (AIItemList::reverse_iterator iter = items->rbegin(); iter != items->rend(); iter = items->rbegin()) {
if (--count < 0) return;
this->RemoveItem(*iter);
/* When the last item is removed from the bucket, the bucket itself is removed.
* This means that the iterators can be invalid after a call to RemoveItem.
*/
if (--size == 0) break;
}
}
case SORT_BY_ITEM:
for (AIAbstractListMap::reverse_iterator iter = this->items.rbegin(); iter != this->items.rend(); iter = this->items.rbegin()) {
if (--count < 0) return;
this->RemoveItem((*iter).first);
}
break;
}
}
void AIAbstractList::RemoveList(AIAbstractList *list)
{
AIAbstractListMap *list_items = &list->items;
for (AIAbstractListMap::iterator iter = list_items->begin(); iter != list_items->end(); iter++) {
this->RemoveItem((*iter).first);
}
}
void AIAbstractList::KeepAboveValue(int32 value)
{
for (AIAbstractListMap::iterator next_iter, iter = this->items.begin(); iter != this->items.end(); iter = next_iter) {
next_iter = iter; next_iter++;
if ((*iter).second <= value) this->items.erase(iter);
}
for (AIAbstractListBucket::iterator next_iter, iter = this->buckets.begin(); iter != this->buckets.end(); iter = next_iter) {
next_iter = iter; next_iter++;
if ((*iter).first <= value) this->buckets.erase(iter);
}
}
void AIAbstractList::KeepBelowValue(int32 value)
{
for (AIAbstractListMap::iterator next_iter, iter = this->items.begin(); iter != this->items.end(); iter = next_iter) {
next_iter = iter; next_iter++;
if ((*iter).second >= value) this->items.erase(iter);
}
for (AIAbstractListBucket::iterator next_iter, iter = this->buckets.begin(); iter != this->buckets.end(); iter = next_iter) {
next_iter = iter; next_iter++;
if ((*iter).first >= value) this->buckets.erase(iter);
}
}
void AIAbstractList::KeepBetweenValue(int32 start, int32 end)
{
for (AIAbstractListMap::iterator next_iter, iter = this->items.begin(); iter != this->items.end(); iter = next_iter) {
next_iter = iter; next_iter++;
if ((*iter).second <= start || (*iter).second >= end) this->items.erase(iter);
}
for (AIAbstractListBucket::iterator next_iter, iter = this->buckets.begin(); iter != this->buckets.end(); iter = next_iter) {
next_iter = iter; next_iter++;
if ((*iter).first <= start || (*iter).first >= end) this->buckets.erase(iter);
}
}
void AIAbstractList::KeepValue(int32 value)
{
for (AIAbstractListMap::iterator next_iter, iter = this->items.begin(); iter != this->items.end(); iter = next_iter) {
next_iter = iter; next_iter++;
if ((*iter).second != value) this->items.erase(iter);
}
for (AIAbstractListBucket::iterator next_iter, iter = this->buckets.begin(); iter != this->buckets.end(); iter = next_iter) {
next_iter = iter; next_iter++;
if ((*iter).first != value) this->buckets.erase(iter);
}
}
void AIAbstractList::KeepTop(int32 count)
{
this->RemoveBottom(this->Count() - count);
}
void AIAbstractList::KeepBottom(int32 count)
{
this->RemoveTop(this->Count() - count);
}
void AIAbstractList::KeepList(AIAbstractList *list)
{
AIAbstractList tmp;
for (AIAbstractListMap::iterator iter = this->items.begin(); iter != this->items.end(); iter++) {
tmp.AddItem((*iter).first);
tmp.SetValue((*iter).first, (*iter).second);
}
tmp.RemoveList(list);
this->RemoveList(&tmp);
}
SQInteger AIAbstractList::Valuate(HSQUIRRELVM vm) {
int nparam = sq_gettop(vm) - 2;
/* Get the list instance and the function to call */
HSQOBJECT obj_list, obj_func;
sq_getstackobj(vm, 1, &obj_list);
sq_getstackobj(vm, 2, &obj_func);
/* Read the params */
HSQOBJECT obj_params[10];
assert(nparam < 10);
for (int i = 0; i < nparam; i++) {
sq_getstackobj(vm, i + 3, &obj_params[i]);
}
/* Remove all unneeded stuff */
sq_pop(vm, nparam + 1);
/* Walk all items, and query the result */
this->buckets.clear();
for (AIAbstractListMap::iterator iter = this->items.begin(); iter != this->items.end(); iter++) {
/* The function to call */
sq_pushobject(vm, obj_func);
/* The 'list' instance; this is most likely wrong, but we need to send something ;) */
sq_pushobject(vm, obj_list);
/* Now send the params */
sq_pushinteger(vm, (*iter).first);
for (int i = 0; i < nparam; i++) {
sq_pushobject(vm, obj_params[i]);
}
/* Call the function */
if (SQ_FAILED(sq_call(vm, nparam + 2, SQTrue, SQTrue))) return -1;
/* Retreive the return value */
SQInteger value;
switch (sq_gettype(vm, -1)) {
case OT_INTEGER: {
sq_getinteger(vm, -1, &value);
} break;
case OT_BOOL: {
SQBool v;
sq_getbool(vm, -1, &v);
value = v ? 1 : 0;
} break;
default: {
sq_throwerror(vm, _SC("return value of valuator is not valid (not integer/bool)"));
return -1;
}
}
/* Remove junk */
sq_pop(vm, 2);
(*iter).second = value;
this->buckets[value].insert((*iter).first);
}
return 0;
}