int main() { int i, A, B; scanf("%s %s", S, T); for(i = 0; T[i] != '\0'; ++i) { ++Cnt[GetIdx(T[i])]; } for(A = i = 0; S[i] != '\0'; ++i) { int idx = GetIdx(S[i]); if(Cnt[idx]) { --Cnt[idx]; ++A; Visited[i] = 1; } } for(B = i = 0; S[i] != '\0'; ++i) { if(!Visited[i]) { int idx = GetIdx(S[i]); if(Cnt[idx < 26 ? idx + 26 : idx - 26]) { --Cnt[idx < 26 ? idx + 26 : idx - 26]; ++B; } } } printf("%d %d\n", A, B); return 0; }
bool CDecalsDrawerGL4::Decal::InvalidateExtents() const { Invalidate(); const int idx = GetIdx(); decalDrawer->waitingDecalsForOverlapTest.push_back(idx); decalDrawer->RemoveFromGroup(idx); return decalDrawer->FindAndAddToGroup(idx); }
/// Vermisst ein neues Weltmeer von einem Punkt aus, indem es alle mit diesem Punkt verbundenen /// Wasserpunkte mit der gleichen ID belegt und die Anzahl zurückgibt unsigned GameWorld::MeasureSea(const MapPoint pt, const unsigned short sea_id) { // Breitensuche von diesem Punkt aus durchführen std::vector<bool> visited(width_ * height_, false); std::queue< MapPoint > todo; MapPoint start(pt); todo.push(start); // Knoten zählen (Startknoten schon mit inbegriffen) unsigned count = 0; while(!todo.empty()) { MapPoint p = todo.front(); todo.pop(); if(visited[GetIdx(p)]) continue; GetNode(p).sea_id = sea_id; for(unsigned i = 0; i < 6; ++i) { MapPoint pa = GetNeighbour(p, i); // Ist das dort auch ein Meerespunkt? if(!IsSeaPoint(pa)) continue; if(!visited[GetIdx(pa)]) { todo.push(pa); } } visited[GetIdx(p)] = true; ++count; } return count; }
void CDecalsDrawerGL4::Decal::SetOwner(const void* o) { if (!IsValid()) return; owner = o; if (o == nullptr) { decalDrawer->alphaDecayingDecals.push_back(GetIdx()); } }
void ProcLinsym( void ) /****************************/ { list_of_names * symname; symbol * sym; bool is32bit; unsigned sym_len; ObjBuff++; /* skip flags */ symname = FindName( GetIdx() ); sym_len = strlen( symname->name ); sym = SymOp( ST_FIND | ST_STATIC, symname->name, sym_len ); if( sym == NULL ) sym = SymOp( ST_FIND, symname->name, sym_len ); if( sym == NULL ) { BadObject(); return; } if( !IS_SYM_COMDAT(sym) ) return; is32bit = (ObjFormat & FMT_32BIT_REC) != 0; if( sym->mod == CurrMod && !(sym->info & SYM_DEAD) ) { DBIAddLines( sym->p.seg, ObjBuff, EOObjRec - ObjBuff, is32bit ); } }
void GameWorld::Scan(glArchivItem_Map* map) { width_ = map->getHeader().getWidth(); //-V807 height_ = map->getHeader().getHeight(); lt = LandscapeType(map->getHeader().getGfxSet()); Init(); // Dummy-Hafenpos für Index 0 einfügen // ask Oliverr why! // -> I just did, the dummy is so that the harbor "0" might be used for ships with no particular destination // poc: if you ever remove this dummy go to GameWorldBase::CalcDistanceToNearestHarbor and fix the loop to include the first harbor again (think Ive seen other instances of dummyadjusted loops as well...) GameWorldBase::HarborPos dummy(MapPoint(0, 0)); harbor_pos.push_back(dummy); // Andere Sachen setzen MapPoint pt(0, 0); for(pt.y = 0; pt.y < height_; ++pt.y) { for(pt.x = 0; pt.x < width_; ++pt.x) { MapNode& node = GetNode(pt); node.roads[2] = node.roads[1] = node.roads[0] = 0; node.roads_real[2] = node.roads_real[1] = node.roads_real[0] = false; node.altitude = map->GetMapDataAt(MAP_ALTITUDE, pt.x, pt.y); // Aufpassen, dass die Terrainindizes im Rahmen liegen, ansonsten 0 nehmen, unbekanntes Terrain (Bsp. // Karte "Drachenebene") unsigned char t1 = map->GetMapDataAt(MAP_TERRAIN1, pt.x, pt.y), t2 = map->GetMapDataAt(MAP_TERRAIN2, pt.x, pt.y); // Hafenplatz? if(TerrainData::IsHarborSpot(t1)) { GameWorldBase::HarborPos p(pt); node.harbor_id = harbor_pos.size(); harbor_pos.push_back(p); } else node.harbor_id = 0; node.t1 = TerrainData::MapIdx2Terrain(t1); node.t2 = TerrainData::MapIdx2Terrain(t2); node.resources = map->GetMapDataAt(MAP_RESOURCES, pt.x, pt.y); // Wasser? if(node.resources == 0x20 || node.resources == 0x21) { // TODO: Berge hatten komische Wasserbeeinflussung // ggf 0-4 Wasser setzen if( (node.t1 == TT_DESERT || node.t2 == TT_DESERT) || TerrainData::IsWater(node.t1) || TerrainData::IsWater(node.t2) ) node.resources = 0; // Kein Wasser, in der Wüste, da isses trocken! else if( (node.t1 == TT_STEPPE || node.t2 == TT_STEPPE) ) node.resources = 0x23; // 2 Wasser else if( (node.t1 == TT_SAVANNAH || node.t2 == TT_SAVANNAH) ) node.resources = 0x25; // 4 Wasser else node.resources = 0x27; // 7 Wasser } node.reserved = false; node.owner = 0; for(unsigned i = 0; i < 4; ++i) node.boundary_stones[i] = 0; node.sea_id = 0; // FOW-Zeug initialisieren for(unsigned i = 0; i < GAMECLIENT.GetPlayerCount(); ++i) { MapNode::FoWData& fow = node.fow[i]; switch(GAMECLIENT.GetGGS().exploration) { case GlobalGameSettings::EXP_DISABLED: { fow.visibility = VIS_VISIBLE; } break; case GlobalGameSettings::EXP_CLASSIC: { fow.visibility = VIS_INVISIBLE; } break; case GlobalGameSettings::EXP_FOGOFWAR: { fow.visibility = VIS_INVISIBLE; } break; case GlobalGameSettings::EXP_FOGOFWARE_EXPLORED: { fow.visibility = VIS_FOW; } break; } fow.last_update_time = 0; fow.object = NULL; fow.roads[0] = fow.roads[1] = fow.roads[2] = 0; fow.owner = 0; for(unsigned z = 0; z < 4; ++z) fow.boundary_stones[z] = 0; } } } std::vector< MapPoint > headquarter_positions; // Objekte auslesen for(pt.y = 0; pt.y < height_; ++pt.y) { for(pt.x = 0; pt.x < width_; ++pt.x) { unsigned int pos = GetIdx(pt); unsigned char lc = map->GetMapDataAt(MAP_LANDSCAPE, pt.x, pt.y); switch(map->GetMapDataAt(MAP_TYPE, pt.x, pt.y)) { // Player Startpos (provisorisch) case 0x80: { headquarter_positions.push_back(pt); if(lc < GAMECLIENT.GetPlayerCount()) { GetPlayer(lc).hqPos = pt; nodes[pos].obj = NULL; } } break; // Baum 1-4 case 0xC4: { if(lc >= 0x30 && lc <= 0x3D) nodes[pos].obj = new noTree(pt, 0, 3); else if(lc >= 0x70 && lc <= 0x7D) nodes[pos].obj = new noTree(pt, 1, 3); else if(lc >= 0xB0 && lc <= 0xBD) nodes[pos].obj = new noTree(pt, 2, 3); else if(lc >= 0xF0 && lc <= 0xFD) nodes[pos].obj = new noTree(pt, 3, 3); else { LOG.lprintf("Unbekannter Baum1-4 auf x=%d, y=%d: id=%d (0x%0X)\n", pt.x, pt.y, lc, lc); nodes[pos].obj = NULL; } } break; // Baum 5-8 case 0xC5: { if(lc >= 0x30 && lc <= 0x3D) nodes[pos].obj = new noTree(pt, 4, 3); else if(lc >= 0x70 && lc <= 0x7D) nodes[pos].obj = new noTree(pt, 5, 3); else if(lc >= 0xB0 && lc <= 0xBD) nodes[pos].obj = new noTree(pt, 6, 3); else if(lc >= 0xF0 && lc <= 0xFD) nodes[pos].obj = new noTree(pt, 7, 3); else { LOG.lprintf("Unbekannter Baum5-8 auf x=%d, y=%d: id=%d (0x%0X)\n", pt.x, pt.y, lc, lc); nodes[pos].obj = NULL; } } break; // Baum 9 case 0xC6: { if(lc >= 0x30 && lc <= 0x3D) nodes[pos].obj = new noTree(pt, 8, 3); else { LOG.lprintf("Unbekannter Baum9 auf x=%d, y=%d: id=%d (0x%0X)\n", pt.x, pt.y, lc, lc); nodes[pos].obj = NULL; } } break; // Sonstiges Naturzeug ohne Funktion, nur zur Dekoration case 0xC8: { /// @todo mis0bobs unvollständig (dieses lagerzelt), 4 und 5 überhaupt nicht erwähnt // mis1bobs, 2 und 3 sind vollständig eingebaut // Objekte aus der map_?_z.lst if(lc <= 0x0A) nodes[pos].obj = new noEnvObject(pt, 500 + lc); // "wasserstein" aus der map_?_z.lst else if(lc == 0x0B) nodes[pos].obj = new noStaticObject(pt, 500 + lc); // Objekte aus der map_?_z.lst else if(lc >= 0x0C && lc <= 0x0F) nodes[pos].obj = new noEnvObject(pt, 500 + lc); // Objekte aus der map.lst else if(lc >= 0x10 && lc <= 0x14) nodes[pos].obj = new noEnvObject(pt, 542 + lc - 0x10); // gestrandetes Schiff (mis0bobs, unvollständig) else if(lc == 0x15) nodes[pos].obj = new noStaticObject(pt, (lc - 0x15) * 2, 0, 1); // das Tor aus der map_?_z.lst else if(lc == 0x16) nodes[pos].obj = new noStaticObject(pt, 560, 0xFFFF, 2); // das geöffnete Tor aus map_?_z.lst else if(lc == 0x17) nodes[pos].obj = new noStaticObject(pt, 561, 0xFFFF, 2); // Stalagmiten (mis1bobs) else if(lc >= 0x18 && lc <= 0x1E) nodes[pos].obj = new noStaticObject(pt, (lc - 0x18) * 2, 1); // toter Baum (mis1bobs) else if(lc >= 0x1F && lc <= 0x20) nodes[pos].obj = new noStaticObject(pt, 20 + (lc - 0x1F) * 2, 1); // Gerippe (mis1bobs) else if(lc == 0x21) nodes[pos].obj = new noEnvObject(pt, 30, 1); // Objekte aus der map.lst else if(lc >= 0x22 && lc <= 0x27) nodes[pos].obj = new noEnvObject(pt, 550 + lc - 0x22); // Objekte aus der map.lst else if(lc >= 0x28 && lc <= 0x2B) nodes[pos].obj = new noEnvObject(pt, 556 + lc - 0x28); // die "kaputten" Gebäuderuinen usw (mis2bobs) else if(lc >= 0x2C && lc <= 0x2D) nodes[pos].obj = new noStaticObject(pt, (lc - 0x2C) * 2, 2); else if(lc == 0x2E) nodes[pos].obj = new noStaticObject(pt, (lc - 0x2C) * 2, 2, 1); else if(lc == 0x2F) nodes[pos].obj = new noStaticObject(pt, (lc - 0x2C) * 2, 2, 2); else if(lc == 0x30) nodes[pos].obj = new noEnvObject(pt, (lc - 0x2C) * 2, 2); // der Wikinger (mis3bobs) else if(lc == 0x31) nodes[pos].obj = new noStaticObject(pt, 0, 2); else { LOG.lprintf("Unbekanntes Naturzeug auf x=%d, y=%d: id=%d (0x%0X)\n", pt.x, pt.y, lc, lc); nodes[pos].obj = NULL; } } break; // Granit Typ 1 case 0xCC: { if(lc >= 0x01 && lc <= 0x06) nodes[pos].obj = new noGranite(GT_1, lc - 1); else { LOG.lprintf("Unbekannter Granit1 auf x=%d, y=%d: id=%d (0x%0X)\n", pt.x, pt.y, lc, lc); nodes[pos].obj = NULL; } } break; // Granit Typ 2 case 0xCD: { if(lc >= 0x01 && lc <= 0x06) nodes[pos].obj = new noGranite(GT_2, lc - 1); else { LOG.lprintf("Unbekannter Granit2 auf x=%d, y=%d: id=%d (0x%0X)\n", pt.x, pt.y, lc, lc); nodes[pos].obj = NULL; } } break; // Nichts case 0: { nodes[pos].obj = NULL; } break; default: { /*LOG.lprintf("Unbekanntes Objekt %d (0x%0X) auf x=%d, y=%d: id=%d (0x%0X)\n", map->map_type[y*width+x], map->map_type[y*width+x], x, y, lc, lc); */ nodes[pos].obj = NULL; } break; } } } // BQ mit nichts erstmal inititalisieren (HQ-Setzen berechnet diese neu und braucht sie) for(pt.y = 0; pt.y < height_; ++pt.y) { for(pt.x = 0; pt.x < width_; ++pt.x) { SetBQ(pt, BQ_NOTHING); } } //random locations? -> randomize them :) if (GAMECLIENT.GetGGS().random_location) { ptrdiff_t (*p_myrandom)(ptrdiff_t) = myRandom; std::random_shuffle(headquarter_positions.begin(), headquarter_positions.end(), p_myrandom); for (unsigned i = 0; i < GAMECLIENT.GetPlayerCount(); ++i) { GetPlayer(i).hqPos = headquarter_positions.at(i); } } // HQ setzen for(unsigned i = 0; i < GAMECLIENT.GetPlayerCount(); ++i) { // Existiert überhaupt ein HQ? if(GetPlayer(i).hqPos.x != 0xFFFF) { if(GetPlayer(i).ps == PS_OCCUPIED || GetPlayer(i).ps == PS_KI) { nobHQ* hq = new nobHQ(GetPlayer(i).hqPos, i, GetPlayer(i).nation); SetNO(hq, GetPlayer(i).hqPos); GetPlayer(i).AddWarehouse(reinterpret_cast<nobBaseWarehouse*>(hq)); } /*else GetNode(GetPlayer(i).hqx,GetPlayer(i).hqy).obj = 0;*/ } } // Tiere auslesen for(pt.y = 0; pt.y < height_; ++pt.y) { for(pt.x = 0; pt.x < width_; ++pt.x) { unsigned pos = GetIdx(pt); // Tiere setzen Species species; switch(map->GetMapDataAt(MAP_ANIMALS, pt.x, pt.y)) { // TODO: Welche ID ist Polarbär? case 1: species = Species(SPEC_RABBITWHITE+RANDOM.Rand(__FILE__, __LINE__, 0, 2)); break; // zufällige Hasenart nehmen case 2: species = SPEC_FOX; break; case 3: species = SPEC_STAG; break; case 4: species = SPEC_DEER; break; case 5: species = SPEC_DUCK; break; case 6: species = SPEC_SHEEP; break; default: species = SPEC_NOTHING; break; } if(species != SPEC_NOTHING) { noAnimal* animal = new noAnimal(species, pt); AddFigure(animal, pt); // Loslaufen animal->StartLiving(); } /// 4 Fische setzen if(map->GetMapDataAt(MAP_RESOURCES, pos) > 0x80 && map->GetMapDataAt(MAP_RESOURCES, pos) < 0x90) GetNode(pt).resources = 0x84; } } /// Weltmeere vermessen for(pt.y = 0; pt.y < height_; ++pt.y) { for(pt.x = 0; pt.x < width_; ++pt.x) { // Noch kein Meer an diesem Punkt? if(!GetNode(pt).sea_id) { // Aber trotzdem Teil eines noch nicht vermessenen Meeres? if(IsSeaPoint(pt)) { unsigned sea_size = MeasureSea(pt, seas.size()); seas.push_back(Sea(sea_size)); } } } } /// Die Meere herausfinden, an die die Hafenpunkte grenzen for(unsigned i = 0; i < harbor_pos.size(); ++i) { for(unsigned z = 0; z < 6; ++z) harbor_pos[i].cps[z].sea_id = IsCoastalPoint(GetNeighbour(harbor_pos[i].pos, z)); } // Nachbarn der einzelnen Hafenplätze ermitteln CalcHarborPosNeighbors(); /// Schatten und BQ berechnen for(pt.y = 0; pt.y < height_; ++pt.y) { for(pt.x = 0; pt.x < width_; ++pt.x) { RecalcShadow(pt); SetBQ(pt, GAMECLIENT.GetPlayerID()); } } /// Bei FoW und aufgedeckt müssen auch die ersten FoW-Objekte erstellt werden if(GAMECLIENT.GetGGS().exploration == GlobalGameSettings::EXP_FOGOFWARE_EXPLORED) { for(pt.y = 0; pt.y < height_; ++pt.y) { for(pt.x = 0; pt.x < width_; ++pt.x) { // Alle Spieler durchgehen for(unsigned i = 0; i < GAMECLIENT.GetPlayerCount(); ++i) { // An der Stelle FOW für diesen Spieler? if(GetNode(pt).fow[i].visibility == VIS_FOW) SaveFOWNode(pt, i); } } } } }
iSharedValue* ceSharedValueManager::GetValue(const std::string &name) { return GetValue(GetIdx(name)); }
void CDecalsDrawerGL4::Decal::Invalidate() const { const int idx = GetIdx(); decalDrawer->decalsToUpdate.push_back(idx); }
void CDecalsDrawerGL4::Decal::Free() const { decalDrawer->FreeDecal(GetIdx()); }
T operator()(std::array<std::size_t, Nd> idxs) const { return mData[GetIdx(idxs)]; }
/// Wegfinden ( A* ), O(v lg v) --> Wegfindung auf allgemeinen Terrain (ohne Straßen), für Wegbau und frei herumlaufende Berufe bool GameWorldBase::FindFreePathAlternatingConditions(const MapPoint start, const MapPoint dest, const bool random_route, const unsigned max_route, std::vector<unsigned char>* route, unsigned* length, unsigned char* first_dir, FP_Node_OK_Callback IsNodeOK, FP_Node_OK_Callback IsNodeOKAlternate, FP_Node_OK_Callback IsNodeToDestOk, const void* param, const bool record) const { // increase currentVisit, so we don't have to clear the visited-states at every run currentVisit++; //currentVisitEven++; // if the counter reaches its maxium, tidy up if (currentVisit == std::numeric_limits<unsigned>::max() - 1) { for (unsigned i = 0; i < (maxMapSize * maxMapSize); ++i) { pf_nodes[i].lastVisited = 0; pf_nodes[i].lastVisitedEven = 0; } currentVisit = 1; //currentVisitEven = 1; } std::list<PathfindingPoint> todo; bool prevstepEven=true; //flips between even and odd unsigned stepsTilSwitch=1; PathfindingPoint::Init(dest, this); // Anfangsknoten einfügen unsigned start_id = MakeCoordID(start); todo.push_back(PathfindingPoint(start, start_id)); // Und mit entsprechenden Werten füllen //pf_nodes[start_id].it_p = ret.first; pf_nodes[start_id].prevEven = INVALID_PREV; pf_nodes[start_id].lastVisitedEven = currentVisit; pf_nodes[start_id].wayEven = 0; pf_nodes[start_id].dirEven = 0; //LOG.lprintf("pf: from %i, %i to %i, %i \n", x_start, y_start, x_dest, y_dest); // TODO confirm random unsigned rand = GetIdx(start) * GAMECLIENT.GetGFNumber() % 6; //RANDOM.Rand(__FILE__, __LINE__, y_start * GetWidth() + x_start, 6); while(!todo.empty()) { if(!stepsTilSwitch) //counter for next step and switch condition { prevstepEven=!prevstepEven; stepsTilSwitch=todo.size(); //prevstepEven? LOG.lprintf("pf: even, to switch %i listsize %i ", stepsTilSwitch, todo.size()) : LOG.lprintf("pf: odd, to switch %i listsize %i ", stepsTilSwitch, todo.size()); } //else //prevstepEven? LOG.lprintf("pf: even, to switch %i listsize %i ", stepsTilSwitch, todo.size()) : LOG.lprintf("pf: odd, to switch %i listsize %i ", stepsTilSwitch, todo.size()); stepsTilSwitch--; // Knoten mit den geringsten Wegkosten auswählen PathfindingPoint best = *todo.begin(); // Knoten behandelt --> raus aus der todo Liste todo.erase(todo.begin()); //printf("x: %u y: %u\n", best.x, best.y); // ID des besten Punktes ausrechnen unsigned best_id = best.id; //LOG.lprintf(" now %i, %i id: %i \n", best.x, best.y, best_id); // Dieser Knoten wurde aus dem set entfernt, daher wird der entsprechende Iterator // auf das Ende (also nicht definiert) gesetzt, quasi als "NULL"-Ersatz //pf_nodes[best_id].it_p = todo.end(); // Ziel schon erreicht? Allerdings Null-Weg, wenn Start=Ende ist, verbieten if(dest == best.pt && ((prevstepEven && pf_nodes[best_id].wayEven) || (!prevstepEven && pf_nodes[best_id].way))) { // Ziel erreicht! // Jeweils die einzelnen Angaben zurückgeben, falls gewünscht (Pointer übergeben) if(length) *length = prevstepEven ? pf_nodes[best_id].wayEven : pf_nodes[best_id].way; if(route) prevstepEven? route->resize(pf_nodes[best_id].wayEven) : route->resize(pf_nodes[best_id].way); // Route rekonstruieren und ggf. die erste Richtung speichern, falls gewünscht bool alternate=prevstepEven; for(unsigned z = prevstepEven? pf_nodes[best_id].wayEven - 1 : pf_nodes[best_id].way - 1; best_id != start_id; --z, best_id = alternate? pf_nodes[best_id].prevEven : pf_nodes[best_id].prev, alternate=!alternate) { if(route) (*route)[z] = alternate? pf_nodes[best_id].dirEven : pf_nodes[best_id].dir; if(first_dir && z == 0) *first_dir = pf_nodes[best_id].dirEven; } // Fertig, es wurde ein Pfad gefunden return true; } // Maximaler Weg schon erreicht? In dem Fall brauchen wir keine weiteren Knoten von diesem aus bilden if((prevstepEven && pf_nodes[best_id].wayEven)==max_route || (!prevstepEven && pf_nodes[best_id].way == max_route)) continue; // Bei Zufälliger Richtung anfangen (damit man nicht immer denselben Weg geht, besonders für die Soldaten wichtig) unsigned startDir = random_route ? rand : 0; //LOG.lprintf("pf get neighbor nodes %i, %i id: %i \n", best.x, best.y, best_id); // Knoten in alle 6 Richtungen bilden for(unsigned z = startDir + 3; z < startDir + 9; ++z) { unsigned i = z % 6; // Koordinaten des entsprechenden umliegenden Punktes bilden MapPoint na = GetNeighbour(best.pt, i); // ID des umliegenden Knotens bilden unsigned xaid = MakeCoordID(na); // Knoten schon auf dem Feld gebildet? if ((prevstepEven && pf_nodes[xaid].lastVisited == currentVisit) || (!prevstepEven && pf_nodes[xaid].lastVisitedEven == currentVisit)) { continue; } // Das Ziel wollen wir auf jedenfall erreichen lassen, daher nur diese zusätzlichen // Bedingungen, wenn es nicht das Ziel ist if(na != dest && ((prevstepEven && IsNodeOK) || (!prevstepEven && IsNodeOKAlternate))) { if(prevstepEven) { if(!IsNodeOK(*this, na, i, param)) continue; } else { if (!IsNodeOKAlternate(*this, na, i, param)) continue; MapPoint p = best.pt; std::vector<MapPoint>evenlocationsonroute; bool alternate=prevstepEven; unsigned back_id=best_id; for(unsigned i=pf_nodes[best_id].way-1; i>1; i--, back_id = alternate? pf_nodes[back_id].prevEven : pf_nodes[back_id].prev, alternate=!alternate) // backtrack the plannend route and check if another "even" position is too close { unsigned char pdir = alternate? pf_nodes[back_id].dirEven : pf_nodes[back_id].dir; p = GetNeighbour(p, (pdir+3)%6); if(i%2==0) //even step { evenlocationsonroute.push_back(p); } } bool tooclose=false; //LOG.lprintf("pf from %i, %i to %i, %i now %i, %i ", x_start, y_start, x_dest, y_dest, xa, ya);//\n for(std::vector<MapPoint>::const_iterator it=evenlocationsonroute.begin();it!=evenlocationsonroute.end(); ++it) { //LOG.lprintf("dist to %i, %i ", temp, *it); if(CalcDistance(na, (*it))<2) { tooclose=true; break; } } //LOG.lprintf("\n"); if(CalcDistance(na, start)<2) continue; if(CalcDistance(na, dest)<2) continue; if(tooclose) continue; } } // Zusätzliche Bedingungen, auch die das letzte Stück zum Ziel betreffen if(IsNodeToDestOk) { if(!IsNodeToDestOk(*this, na, i, param)) continue; } // Alles in Ordnung, Knoten kann gebildet werden prevstepEven? pf_nodes[xaid].lastVisited = currentVisit : pf_nodes[xaid].lastVisitedEven = currentVisit; prevstepEven? pf_nodes[xaid].way = pf_nodes[best_id].wayEven + 1: pf_nodes[xaid].wayEven = pf_nodes[best_id].way + 1; prevstepEven? pf_nodes[xaid].dir = i : pf_nodes[xaid].dirEven = i; prevstepEven? pf_nodes[xaid].prev = best_id : pf_nodes[xaid].prevEven = best_id ; todo.push_back(PathfindingPoint(na, xaid)); //pf_nodes[xaid].it_p = ret.first; } } // Liste leer und kein Ziel erreicht --> kein Weg return false; }
/// Wegfinden ( A* ), O(v lg v) --> Wegfindung auf allgemeinen Terrain (ohne Straßen), für Wegbau und frei herumlaufende Berufe bool GameWorldBase::FindFreePath(const MapPoint start, const MapPoint dest, const bool random_route, const unsigned max_route, std::vector<unsigned char>* route, unsigned* length, unsigned char* first_dir, FP_Node_OK_Callback IsNodeOK, FP_Node_OK_Callback IsNodeToDestOk, const void* param, const bool record) const { // increase currentVisit, so we don't have to clear the visited-states at every run currentVisit++; // if the counter reaches its maxium, tidy up if (currentVisit == std::numeric_limits<unsigned>::max() - 1) { for (unsigned i = 0; i < (maxMapSize * maxMapSize); ++i) { pf_nodes[i].lastVisited = 0; pf_nodes[i].lastVisitedEven = 0; } currentVisit = 1; } std::set<PathfindingPoint> todo; PathfindingPoint::Init(dest, this); // Anfangsknoten einfügen unsigned start_id = MakeCoordID(start); std::pair< std::set<PathfindingPoint>::iterator, bool > ret = todo.insert(PathfindingPoint(start, start_id)); // Und mit entsprechenden Werten füllen pf_nodes[start_id].it_p = ret.first; pf_nodes[start_id].prev = INVALID_PREV; pf_nodes[start_id].lastVisited = currentVisit; pf_nodes[start_id].way = 0; pf_nodes[start_id].dir = 0; // TODO confirm random unsigned rand = (GetIdx(start)) * GAMECLIENT.GetGFNumber() % 6; //RANDOM.Rand(__FILE__, __LINE__, y_start * GetWidth() + x_start, 6); while(!todo.empty()) { // Knoten mit den geringsten Wegkosten auswählen PathfindingPoint best = *todo.begin(); // Knoten behandelt --> raus aus der todo Liste todo.erase(todo.begin()); //printf("x: %u y: %u\n", best.x, best.y); // ID des besten Punktes ausrechnen unsigned best_id = best.id; // Dieser Knoten wurde aus dem set entfernt, daher wird der entsprechende Iterator // auf das Ende (also nicht definiert) gesetzt, quasi als "NULL"-Ersatz pf_nodes[best_id].it_p = todo.end(); // Ziel schon erreicht? Allerdings Null-Weg, wenn Start=Ende ist, verbieten if(dest == best.pt && pf_nodes[best_id].way) { // Ziel erreicht! // Jeweils die einzelnen Angaben zurückgeben, falls gewünscht (Pointer übergeben) if(length) *length = pf_nodes[best_id].way; if(route) route->resize(pf_nodes[best_id].way); // Route rekonstruieren und ggf. die erste Richtung speichern, falls gewünscht for(unsigned z = pf_nodes[best_id].way - 1; best_id != start_id; --z, best_id = pf_nodes[best_id].prev) { if(route) (*route)[z] = pf_nodes[best_id].dir; if(first_dir && z == 0) *first_dir = pf_nodes[best_id].dir; } // Fertig, es wurde ein Pfad gefunden return true; } // Maximaler Weg schon erreicht? In dem Fall brauchen wir keine weiteren Knoten von diesem aus bilden if(pf_nodes[best_id].way == max_route) continue; // Bei Zufälliger Richtung anfangen (damit man nicht immer denselben Weg geht, besonders für die Soldaten wichtig) unsigned start = random_route ? rand : 0; // Knoten in alle 6 Richtungen bilden for(unsigned z = start + 3; z < start + 9; ++z) { unsigned i = z % 6; // Koordinaten des entsprechenden umliegenden Punktes bilden MapPoint na = GetNeighbour(best.pt, i); // ID des umliegenden Knotens bilden unsigned xaid = MakeCoordID(na); // Knoten schon auf dem Feld gebildet? if (pf_nodes[xaid].lastVisited == currentVisit) { // Dann nur ggf. Weg und Vorgänger korrigieren, falls der Weg kürzer ist if(pf_nodes[xaid].it_p != todo.end() && pf_nodes[best_id].way + 1 < pf_nodes[xaid].way) { pf_nodes[xaid].way = pf_nodes[best_id].way + 1; pf_nodes[xaid].prev = best_id; todo.erase(pf_nodes[xaid].it_p); ret = todo.insert(PathfindingPoint(na, xaid)); pf_nodes[xaid].it_p = ret.first; pf_nodes[xaid].dir = i; } // Wir wollen nicht denselben Knoten noch einmal einfügen, daher Abbruch continue; } // Das Ziel wollen wir auf jedenfall erreichen lassen, daher nur diese zusätzlichen // Bedingungen, wenn es nicht das Ziel ist if(na != dest && IsNodeOK) { if(!IsNodeOK(*this, na, i, param)) continue; } // Zusätzliche Bedingungen, auch die das letzte Stück zum Ziel betreffen if(IsNodeToDestOk) { if(!IsNodeToDestOk(*this, na, i, param)) continue; } // Alles in Ordnung, Knoten kann gebildet werden pf_nodes[xaid].lastVisited = currentVisit; pf_nodes[xaid].way = pf_nodes[best_id].way + 1; pf_nodes[xaid].dir = i; pf_nodes[xaid].prev = best_id; ret = todo.insert(PathfindingPoint(na, xaid)); pf_nodes[xaid].it_p = ret.first; } } // Liste leer und kein Ziel erreicht --> kein Weg return false; }