As a French person I feel like it's my duty to explain strikes to you. - AdrienIer

Create an account  

 
Strategy Thread - for quick strategy questions and answers

(March 30th, 2014, 11:43)Catwalk Wrote: That second one looks good, but as is often the case with RefSteel's posts I have no clue what he's saying smile

Lol, me too, he's in a much higher mental plane than me.

I think for a potential tile, you take (distance to your nearest city) + 2 * (distance to your unit). You teleport to the tile with the minimum value for this. If it's a tie, take the most south tile. If that's a tie, take the most west tile. He, at least, seems to be convinced this covers everything.

What I'm unclear about is what "distance" means. There are several possibilities:
1. Pythagorean distance: sqrt(delta x squared + delta y squared) with some rounding rule.
2. absolute delta x + delta y. ("Manhattan distance").
3. Distance according to city border pops. E.g. distance 2 is the blunt fat cross of a city with a border pop. Distance 3 is the influence of a city with 2 border pops, and so on.

We may actually be talking about #3, i.e. the cultural influence of a city is also a distance metric in Civ 4. (!) I don't trust that that's actually true, it would take a lot of time in WB and / or looking at the source code to be sure.

(I'm not liable for you relying on the above for tactics and it failing hilariously. lol )
Reply

Wouldn't it be neither Pythagorean nor Manhattan, since diagonals carry the same value as horizontal and vertical distance, so it could be a version of Manhattan where it follows the shortest go-to route in unit movement?
Reply

(March 30th, 2014, 12:09)Hashoosh Wrote: Wouldn't it be neither Pythagorean nor Manhattan, since diagonals carry the same value as horizontal and vertical distance, so it could be a version of Manhattan where it follows the shortest go-to route in unit movement?

That would be a fourth possibility (max(abs(delta x), abs(delta y))) but I don't think it works like that either!
Reply

If you look in your PB11 thread post, he clearly says it's cultural distance.
Reply

Code sleuthing:

Code:
// 4 | 4 | 3 | 3 | 3 | 4 | 4
// -------------------------
// 4 | 3 | 2 | 2 | 2 | 3 | 4
// -------------------------
// 3 | 2 | 1 | 1 | 1 | 2 | 3
// -------------------------
// 3 | 2 | 1 | 0 | 1 | 2 | 3
// -------------------------
// 3 | 2 | 1 | 1 | 1 | 2 | 3
// -------------------------
// 4 | 3 | 2 | 2 | 2 | 3 | 4
// -------------------------
// 4 | 4 | 3 | 3 | 3 | 4 | 4
//
// Returns the distance between plots according to the pattern above...
inline int plotDistance(int iX1, int iY1, int iX2, int iY2)                                                    // Exposed to Python
{
    int iDX;
    int iDY;

    iDX = xDistance(iX1, iX2);
    iDY = yDistance(iY1, iY2);

    return (std::max(iDX, iDY) + (std::min(iDX, iDY) / 2));
}

// 3 | 3 | 3 | 3 | 3 | 3 | 3
// -------------------------
// 3 | 2 | 2 | 2 | 2 | 2 | 3
// -------------------------
// 3 | 2 | 1 | 1 | 1 | 2 | 3
// -------------------------
// 3 | 2 | 1 | 0 | 1 | 2 | 3
// -------------------------
// 3 | 2 | 1 | 1 | 1 | 2 | 3
// -------------------------
// 3 | 2 | 2 | 2 | 2 | 2 | 3
// -------------------------
// 3 | 3 | 3 | 3 | 3 | 3 | 3
//
// Returns the distance between plots according to the pattern above...
inline int stepDistance(int iX1, int iY1, int iX2, int iY2)                                                    // Exposed to Python
{
    return std::max(xDistance(iX1, iX2), yDistance(iY1, iY2));
}

I think we're talking about what the code calls "plotDistance", and I'm pretty sure it's what culture uses.

What really isn't obvious (to me!) is the workings of formula it's based on:

max(delta x, delta y) + min(delta x, delta y) / 2

So what makes the "blunt" part of the BFC is actually the rounding of the second division by 2! (If this is obvious to you, you are far better at mathematical intuition than I am.)

I had thought cultural borders were something like Manhattan distance, but with the point on the horizontal or vertical line taken away. But this isn't it.

I've actually wondered about this in game, too, the way the 4th ring borders include an extra corner when it's not obvious they should.

And... here's the function that I think we care about:

Code:
// false if unit is killed
bool CvUnit::jumpToNearestValidPlot()
{
    CvCity* pNearestCity;
    CvPlot* pLoopPlot;
    CvPlot* pBestPlot;
    int iValue;
    int iBestValue;
    int iI;

    FAssertMsg(!isAttacking(), "isAttacking did not return false as expected");
    FAssertMsg(!isFighting(), "isFighting did not return false as expected");

    pNearestCity = GC.getMapINLINE().findCity(getX_INLINE(), getY_INLINE(), getOwnerINLINE());

    iBestValue = MAX_INT;
    pBestPlot = NULL;

    for (iI = 0; iI < GC.getMapINLINE().numPlotsINLINE(); iI++)
    {
        pLoopPlot = GC.getMapINLINE().plotByIndexINLINE(iI);

        if (pLoopPlot->isValidDomainForLocation(*this))
        {
            if (canMoveInto(pLoopPlot))
            {
                if (canEnterArea(pLoopPlot->getTeam(), pLoopPlot->area()) && !isEnemy(pLoopPlot->getTeam(), pLoopPlot))
                {
                    FAssertMsg(!atPlot(pLoopPlot), "atPlot(pLoopPlot) did not return false as expected");

                    if ((getDomainType() != DOMAIN_AIR) || pLoopPlot->isFriendlyCity(*this, true))
                    {
                        if (pLoopPlot->isRevealed(getTeam(), false))
                        {
                            iValue = (plotDistance(getX_INLINE(), getY_INLINE(), pLoopPlot->getX_INLINE(), pLoopPlot->getY_INLINE()) * 2);

                            if (pNearestCity != NULL)
                            {
                                iValue += plotDistance(pLoopPlot->getX_INLINE(), pLoopPlot->getY_INLINE(), pNearestCity->getX_INLINE(), pNearestCity->getY_INLINE());
                            }

                            if (getDomainType() == DOMAIN_SEA && !plot()->isWater())
                            {
                                if (!pLoopPlot->isWater() || !pLoopPlot->isAdjacentToArea(area()))
                                {
                                    iValue *= 3;
                                }
                            }
                            else
                            {
                                if (pLoopPlot->area() != area())
                                {
                                    iValue *= 3;
                                }
                            }

                            if (iValue < iBestValue)
                            {
                                iBestValue = iValue;
                                pBestPlot = pLoopPlot;
                            }
                        }
                    }
                }
            }
        }
    }

    bool bValid = true;
    if (pBestPlot != NULL)
    {
        setXY(pBestPlot->getX_INLINE(), pBestPlot->getY_INLINE());
    }
    else
    {
        kill(false);
        bValid = false;
    }

    return bValid;
}

So there's the authoritative answer, and we see the "*2" that RefSteel empirically determined.

Edit: also, based on a superficial understanding, there's also a big penalty for jumping from one landmass to another. (Or maybe from one landmass to another one with a different area, lol. It depends on what the area() function does.)

Edit 2: If it's not completely obvious how the cultural distance pattern continues, showing it with a horrific JavaScript one-liner:

Code:
var bound=6; for(var y=-bound; y<=bound; y++) {var s = ""; for(var x=-bound;x<=bound; x++) { s += (Math.max(Math.abs(x), Math.abs(y)) + Math.floor(Math.min(Math.abs(x), Math.abs(y)) / 2)) + " "; } console.log(s); }
9 8 8 7 7 6 6 6 7 7 8 8 9  
8 7 7 6 6 5 5 5 6 6 7 7 8  
8 7 6 5 5 4 4 4 5 5 6 7 8  
7 6 5 4 4 3 3 3 4 4 5 6 7  
7 6 5 4 3 2 2 2 3 4 5 6 7  
6 5 4 3 2 1 1 1 2 3 4 5 6
6 5 4 3 2 1 0 1 2 3 4 5 6  
6 5 4 3 2 1 1 1 2 3 4 5 6  
7 6 5 4 3 2 2 2 3 4 5 6 7  
7 6 5 4 4 3 3 3 4 4 5 6 7  
8 7 6 5 5 4 4 4 5 5 6 7 8
8 7 7 6 6 5 5 5 6 6 7 7 8
9 8 8 7 7 6 6 6 7 7 8 8 9
Reply

Here's the intuition behind plot distance: Horizontal and vertical moves cost 1, diagonal moves cost 1.5.

To calculate a distance, go diagonally until you can finish the rest in a straight vertical or horizontal line. The length of the traversed diagonal is 1.5 * min(dx, dy). The length of the horizontal or vertical line is max(dx, dy) - min(dx, dy). The sum of the two parts is max(dx, dy) + 0.5 * min(dx, dy).
I have to run.
Reply

Is it worth it to build a city just for a gems/gold/silver resource? It provides happiness and some commerce, but costs maintenance and production.
Okay Mansa, I'll take Printing Press for Liberalism. Now where did I put my cannons?
Reply

That question is a bit too broad Sun. Do you mean the city has absolutely nothing else going for it (= ice all around) or just a bunch of grassland and plains tiles? Other than that, it depends heavily on how badly you need happiness. Which generally depends on how much you have already. Do you have an example you can show us?
Reply

A size 1 city working a non-river Silver tundra hill and nothing else gives you 3 hammers and 6 commerce from tiles plus 1, 2, 4 or more from trade routes. Should easily barely pay for itself, I should imagine you'd have currency for 2 trade routes and either foreign trade routes or some island cities to give +4 or +6 from trade routes.

Precious metal provide +1 happy, +1 more with forges which you will get soon enough. Maybe add 1-2 "things" from each city, hammers or commerce, depending a bit on how close to happy limit you are. So that can pay back the cost of the settler in 5-50 turns. A Civ where the happiness gives +2 hammers to 5 cities on normal speed pays back the settler in 10 turns.

So it will be worth it on the paper down the line, question is if you have better use for those hammers/settlers _now_, if you can secure the metal down the line in some better way - 3rd ring culture from a decent city, trade, warfare. It could beat building units for 100 hammers because extra happiness should let you whip a few more hammers worth of units down the line. If you didn't have a pressing need for them 20 turns ago.
Played: FFH PBEM XXVI (Rhoanna) FFH PBEM XXV (Shekinah) FFH PBEM XXX (Flauros) Pitboss 11 (Kublai Rome)
Playing:Pitboss 18 (Ghengis Portugal) PBEM 60 - AI start (Napoleon Inca)
Reply

(March 30th, 2014, 16:03)Molach Wrote: A size 1 city working a non-river Silver tundra hill and nothing else gives you 3 hammers and 6 commerce from tiles plus 1, 2, 4 or more from trade routes. Should easily pay for itself

This is often untrue because of all the hidden costs generated by that city. When you're on the steep part of the number-of-cities cost curve, somewhere around 8-12 existing cities, this one additional city can cost as much as 12 extra maintenance in your existing cities after inflation. There's also civic upkeep. It's very easy to think such a city is worthwhile when it's actually a net loss.
Reply



Forum Jump: