コード例 #1
0
ファイル: 518B.c プロジェクト: NoSoul/CodeForces
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;
}
コード例 #2
0
bool CDecalsDrawerGL4::Decal::InvalidateExtents() const
{
	Invalidate();
	const int idx = GetIdx();
	decalDrawer->waitingDecalsForOverlapTest.push_back(idx);
	decalDrawer->RemoveFromGroup(idx);
	return decalDrawer->FindAndAddToGroup(idx);
}
コード例 #3
0
ファイル: GameWorld.cpp プロジェクト: Ribosom/s25client
/// 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;

}
コード例 #4
0
void CDecalsDrawerGL4::Decal::SetOwner(const void* o)
{
	if (!IsValid())
		return;

	owner = o;
	if (o == nullptr) {
		decalDrawer->alphaDecayingDecals.push_back(GetIdx());
	}
}
コード例 #5
0
ファイル: wcomdef.c プロジェクト: ABratovic/open-watcom-v2
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 );
    }
}
コード例 #6
0
ファイル: GameWorld.cpp プロジェクト: Ribosom/s25client
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);
                }
            }
        }
    }

}
コード例 #7
0
iSharedValue* ceSharedValueManager::GetValue(const std::string &name)
{
	return GetValue(GetIdx(name));
}
コード例 #8
0
void CDecalsDrawerGL4::Decal::Invalidate() const
{
	const int idx = GetIdx();
	decalDrawer->decalsToUpdate.push_back(idx);

}
コード例 #9
0
void CDecalsDrawerGL4::Decal::Free() const
{
	decalDrawer->FreeDecal(GetIdx());
}
コード例 #10
0
 T operator()(std::array<std::size_t, Nd> idxs) const { 
   return mData[GetIdx(idxs)];
 } 
コード例 #11
0
ファイル: Pathfinding.cpp プロジェクト: Ribosom/s25client
/// 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;
}
コード例 #12
0
ファイル: Pathfinding.cpp プロジェクト: Ribosom/s25client
/// 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;
}