Forest of Assassins - Battle of Rung Sat - 9/21/55 - AAR (AI vs. AI)

Please post your after action reports on your battles and campaigns here.

Moderator: Campaign Series Matrix Edition Development Group

User avatar
berto
Posts: 21461
Joined: Wed Mar 13, 2002 1:15 am
Location: metro Chicago, Illinois, USA
Contact:

Re: Forest of Assassins - Battle of Rung Sat - 9/21/55 - AAR (AI vs. AI)

Post by berto »

By luck of the move (EAI pathfinding), all of the _11TH_NAVAL_ASSAULT_GROUP_390 transports avoid the mines (magenta circle) at the river bend:

CSVN_AAR_AI_AI_RungSat122.jpg
CSVN_AAR_AI_AI_RungSat122.jpg (875.48 KiB) Viewed 1077 times

The Marines disembark, advance near the shore, then enemy opfire!

CSVN_AAR_AI_AI_RungSat123.jpg
CSVN_AAR_AI_AI_RungSat123.jpg (844.04 KiB) Viewed 1077 times

Note that in the earlier auto-test, with the Side B BX Army units all halt()'ed or hold()'ed, there was no enemy opfire.

Not stopping to return the fire, the VNA Marines continue their advance along the swamp's edge, and:

CSVN_AAR_AI_AI_RungSat124.jpg
CSVN_AAR_AI_AI_RungSat124.jpg (873.31 KiB) Viewed 1077 times

More blood spilt.

It gets worse. Enemy mortars target the transports.

CSVN_AAR_AI_AI_RungSat126.jpg
CSVN_AAR_AI_AI_RungSat126.jpg (856.54 KiB) Viewed 1077 times

Before, with the Side B forces inactive, operations were easy, a walk in the park (swamp). Now, with the BX Army fully active, more like a walk through the valley of the shadow of death.

On Turn 12, an especially bad sequence (with Damage Results bottom to top):

CSVN_AAR_AI_AI_RungSat127.jpg
CSVN_AAR_AI_AI_RungSat127.jpg (838.91 KiB) Viewed 1077 times

Can it get any worse? Yes it can! :(

CSVN_AAR_AI_AI_RungSat128.jpg
CSVN_AAR_AI_AI_RungSat128.jpg (893.94 KiB) Viewed 1077 times

From bad to worse to worst.

CSVN_AAR_AI_AI_RungSat129.jpg
CSVN_AAR_AI_AI_RungSat129.jpg (900.01 KiB) Viewed 1077 times

At the start of Turn 15, looking at the Strength Dialog, we can now see how desperate the _11TH_NAVAL_ASSAULT_GROUP_390 situation is:

CSVN_AAR_AI_AI_RungSat130.jpg
CSVN_AAR_AI_AI_RungSat130.jpg (715.99 KiB) Viewed 1077 times

Is there a remedy for this? Yes, an easy fix is to have the attack_way_point() not skirt the swamp's edge but rather plod through the swamp further inland (green arrows), away from the open field of fire across the wet paddies and out of enemy LOS. The Marines are sure to suffer when crossing the ford (FD), but at least they should avoid taking casualties before that.

Our aces in the hole: We haven't plotted any VNA airstrikes yet. We are saving them for scripting last, because we don't yet know where around the map and how much and when they will be most needed.

At this juncture, with VNA Marine casualties so high and without any hope of their meaningfully attacking the Military Post, there is no further purpose in continuing this auto-test. Here, in this locale, this time around, the VNA are plainly beaten.

Better luck -- and scripted orders -- next time!
Campaign Series Legion https://cslegion.com/
Campaign Series Lead Coder https://www.matrixgames.com/forums/view ... hp?f=10167
Panzer Campaigns, Panzer Battles Lead Coder https://wargameds.com
User avatar
berto
Posts: 21461
Joined: Wed Mar 13, 2002 1:15 am
Location: metro Chicago, Illinois, USA
Contact:

Re: Forest of Assassins - Battle of Rung Sat - 9/21/55 - AAR (AI vs. AI)

Post by berto »

Right. Here is the modified attack_way_point() command:


Code: Select all

            attack_way_point(units, {"66,34", "68,35", "68,37", OBJECTIVES[14]}, DOWNRIGHTDIR, 0, 100, ATTACK_STRONG)

CSVN_AAR_AI_AI_RungSat134.jpg
CSVN_AAR_AI_AI_RungSat134.jpg (583.26 KiB) Viewed 1047 times

Where the _11TH_NAVAL_ASSAULT_GROUP_390 will avoid exposing itself to flanking fire by traversing the magenta circled hexes. It will go round about more widely instead.
Campaign Series Legion https://cslegion.com/
Campaign Series Lead Coder https://www.matrixgames.com/forums/view ... hp?f=10167
Panzer Campaigns, Panzer Battles Lead Coder https://wargameds.com
User avatar
berto
Posts: 21461
Joined: Wed Mar 13, 2002 1:15 am
Location: metro Chicago, Illinois, USA
Contact:

Re: Forest of Assassins - Battle of Rung Sat - 9/21/55 - AAR (AI vs. AI)

Post by berto »

Setting aside the _11TH_NAVAL_ASSAULT_GROUP_390, we consider now the _10TH_NAVAL_ASSAULT_GROUP_379 mission, and orders.

In the following screenshot

CSVN_AAR_AI_AI_RungSat131.jpg
CSVN_AAR_AI_AI_RungSat131.jpg (3.15 MiB) Viewed 1045 times

in the Find Organization Dialog, we have selected, thereby highlighted on the game map, the 10th Naval Assault Group. Their mission is to sail down the Song Long Tau, take a sharp right turn down the Nga Ba Dong Tranh, steer left at the Rach Tac Roi, a short while later sail right down an inland waterway, finally disembarking (at the green circles) just northwest of Xom An Thit (Quang Xuyen), and the District Office at that place. From there, the _10TH_NAVAL_ASSAULT_GROUP_379 is to attack and hopefully capture OBJECTIVES[18] and OBJECTIVES[21].

For the 10th NAG Marines, their orders code is similar to the 11th's (see earlier posts):


Code: Select all

    -- _10TH_NAVAL_ASSAULT_GROUP_379 -- 10th Naval Assault Group
    -- _1ST_PLT_380, _2ND_PLT_381, _3RD_PLT_382
    do local units = counters_active(join({_1ST_PLT_380, _2ND_PLT_381, _3RD_PLT_382}))
       local transports = counters_active(join({_LCVP_385, _LCVP_386, _LCVP_387}))
       local flotilla = join({units, transports})
       _10TH_NAVAL_ASSAULT_GROUP_379_MARINES_DISEMBARKED = _10TH_NAVAL_ASSAULT_GROUP_379_MARINES_DISEMBARKED or are_ground(units)
       if not _10TH_NAVAL_ASSAULT_GROUP_379_MARINES_DISEMBARKED then -- water transport to landing point
            if not at(units, "72,55") then
                if chance(50) then
                    move_way_point(flotilla, {"42,23", "49,35", "58,37", "63,37", "68,45", "67,49", "72,55"}, NODIR, 0, 100)
                else
                    move_fire_way_point(flotilla, {"42,23", "49,35", "58,37", "63,37", "68,45", "67,49", "72,55"}, NODIR, 2, 100)
                end
            else
                disembark(flotilla, "72,55", UPRIGHTDIR, 100)
            end
        else -- only if disembarked, on land
            if _10TH_NAVAL_ASSAULT_GROUP_379_SUPPORT_DISEMBARKED then -- wait for support
                if objective_owner(OBJECTIVES[18]) == BX_SIDE then
                    attack_strong(units, OBJECTIVES[18], UPDIR, 1, 100)
                elseif objective_owner(OBJECTIVES[21]) == BX_SIDE then
                    attack_strong(units, OBJECTIVES[21], UPDIR, 1, 100)
                end
                if not at(transports, "73,56") then
                    move_norush(transports, "73,56")
                else
                    fire_direct_nearest_to_hex (transports, OBJECTIVES[18])
                end
            end
        end
    end


After unloading the Marines, their transports are to move closer and join in the attack, firing direct at any enemy nearest to OBJECTIVES[18].

The support units' orders:


Code: Select all

    -- _MMG_48_383
    -- _81MM_MORTARS_384 -- Marine M1 81mm Mortars
    do local units = counters_active(join({_MMG_48_383, _81MM_MORTARS_384}))
       local transports = counters_active(join({_LCA_388, _LCA_389}))
       local flotilla = join({units, transports})
       _10TH_NAVAL_ASSAULT_GROUP_379_SUPPORT_DISEMBARKED = _10TH_NAVAL_ASSAULT_GROUP_379_SUPPORT_DISEMBARKED or are_ground(units)
       if not _10TH_NAVAL_ASSAULT_GROUP_379_SUPPORT_DISEMBARKED then
            -- water transport to landing point
            if not at(units, "72,54") then
                if chance(100) then
                    move_way_point(flotilla, {"42,23", "49,35", "58,37", "63,37", "68,45", "67,49", "72,54"}, NODIR, 0, 100)
                else
                    move_fire_way_point(flotilla, {"42,23", "49,35", "58,37", "63,37", "68,45", "67,49", "72,54"}, NODIR, 2, 100)
                end
            else
                disembark(flotilla, "72,54", UPRIGHTDIR, 100)
            end
        else -- only if disembarked, on land
            if _10TH_NAVAL_ASSAULT_GROUP_379_MARINES_DISEMBARKED then -- wait for marines
                if not at(_MMG_48_383, "74,55") then
                    move_rush(_MMG_48_383, "74,55") -- move to entrenched village
                else
                    fire_direct_nearest(_MMG_48_383, 100)
                end
                fire_indirect_nearest(_81MM_MORTARS_384, 100)
                if not at(transports, "73,56") then
                    move_norush(transports, "73,56")
                else
                    fire_direct_nearest_to_hex (transports, OBJECTIVES[18])
                end
            end
        end
    end


Similarly, after unloading, the support troops' transports are to join in the attack on OBJECTIVES[18].

Note the

Code: Select all

            if _10TH_NAVAL_ASSAULT_GROUP_379_SUPPORT_DISEMBARKED then -- wait for support
                [Marines orders]
            end

            ...

            if _10TH_NAVAL_ASSAULT_GROUP_379_MARINES_DISEMBARKED then -- wait for marines
                [support unit orders]
            end


The Marines don't launch the attack unless and until the support units are disembarked; and the support troops (the MGs and mortars) don't press the attack unless/until the Marines are disembarked and ready. We don't want the attack to be piecemeal. This will be especially important for reasons soon to be explained.
Campaign Series Legion https://cslegion.com/
Campaign Series Lead Coder https://www.matrixgames.com/forums/view ... hp?f=10167
Panzer Campaigns, Panzer Battles Lead Coder https://wargameds.com
User avatar
berto
Posts: 21461
Joined: Wed Mar 13, 2002 1:15 am
Location: metro Chicago, Illinois, USA
Contact:

Re: Forest of Assassins - Battle of Rung Sat - 9/21/55 - AAR (AI vs. AI)

Post by berto »

We set the auto-test to pause at the start of Turn 15 by means of



rober@Rob10rto /cygdrive/c/Games/Matrix Games/Vietnam/vietnam
$ echo "15a" > pass



And launch the auto-test with the command



rober@Rob10rto /cygdrive/c/Games/Matrix Games/Vietnam/vietnam
$ ./vnengine.exe -W -5 -T VN_550921_Rung_Sat.scn



At the beginning of Turn 15, Side A Phase, we see

CSVN_AAR_AI_AI_RungSat132.jpg
CSVN_AAR_AI_AI_RungSat132.jpg (865.75 KiB) Viewed 1044 times

Most of the _10TH_NAVAL_ASSAULT_GROUP_379 has assembled, but not disembarked yet. Note the laggard LC to the northwest (green circle). Why are they delayed? It is because in an earlier encounter with naval mines, the transports and/or their passengers were Disrupted. While Disrupted, they were prevented from moving forward closer to the enemy. Not soon, but in a future game release, I will change the "no moving closer to enemy if disrupted" rule to not apply to carried passengers, only to their transports. In other words

  • disrupted transport (passenger status irrelevant), no can move closer to enemy
  • undisrupted transport (passenger status irrelevant), can proceed with movement

The likelihood of delays: This is why I am scripting movement/attack delays, such as


Code: Select all

            if _10TH_NAVAL_ASSAULT_GROUP_379_SUPPORT_DISEMBARKED then -- wait for support
                [Marines orders]
            end


(See previous post.)

Four turns later, at the start of Turn 19, we see

CSVN_AAR_AI_AI_RungSat133.jpg
CSVN_AAR_AI_AI_RungSat133.jpg (863.33 KiB) Viewed 1044 times

The pieces are all in place. The 10th NAG has launched its attacks around Xom An Thit.

I won't let this auto-test continue, because ... you can probably guess the reason. The BX Army was put on hold. I will unleash them in the next auto-test.
Campaign Series Legion https://cslegion.com/
Campaign Series Lead Coder https://www.matrixgames.com/forums/view ... hp?f=10167
Panzer Campaigns, Panzer Battles Lead Coder https://wargameds.com
User avatar
berto
Posts: 21461
Joined: Wed Mar 13, 2002 1:15 am
Location: metro Chicago, Illinois, USA
Contact:

Re: Forest of Assassins - Battle of Rung Sat - 9/21/55 - AAR (AI vs. AI)

Post by berto »

In the next auto-test, now with the Side B BX Army SAI activated, the situation at the start of Turn 6:

CSVN_AAR_AI_AI_RungSat135.jpg
CSVN_AAR_AI_AI_RungSat135.jpg (1.17 MiB) Viewed 1008 times

The 11th NAG has suffered casualties, from mines and/or enemy fire while passing the Military Post (the west one to the left). Those SP losses are par for the course thus far.

After the 10th NAG (turquoise highlighted) runs the gauntlet, the start of Turn 9 shows:

CSVN_AAR_AI_AI_RungSat136.jpg
CSVN_AAR_AI_AI_RungSat136.jpg (1.14 MiB) Viewed 1008 times

The 10th NAG too has its share of casualties.

Two turns later:

CSVN_AAR_AI_AI_RungSat137.jpg
CSVN_AAR_AI_AI_RungSat137.jpg (1.16 MiB) Viewed 1008 times

Oddly enough, no opfire from the eastern Military Post (at Ap Do Hop), the 10th NAG passes by scot-free. Are the enemy distracted by the Marines threat to the north?

Further down, as they pass, lead elements of the 10th NAG draw opfire from the bunker at hex 69,48 (yellow circle), but without effect, no SP loss.

CSVN_AAR_AI_AI_RungSat138.jpg
CSVN_AAR_AI_AI_RungSat138.jpg (1.16 MiB) Viewed 1008 times

The rest of the 10th NAG also passes by without any disruption delay or loss.
Campaign Series Legion https://cslegion.com/
Campaign Series Lead Coder https://www.matrixgames.com/forums/view ... hp?f=10167
Panzer Campaigns, Panzer Battles Lead Coder https://wargameds.com
User avatar
berto
Posts: 21461
Joined: Wed Mar 13, 2002 1:15 am
Location: metro Chicago, Illinois, USA
Contact:

Re: Forest of Assassins - Battle of Rung Sat - 9/21/55 - AAR (AI vs. AI)

Post by berto »

At Turn 15, the _10TH_NAVAL_ASSAULT_GROUP_379 is poised to attack:

CSVN_AAR_AI_AI_RungSat139.jpg
CSVN_AAR_AI_AI_RungSat139.jpg (1.09 MiB) Viewed 1001 times

Note the BX Army junk unit (yellow circle) blocking the way forward.

At Turn 19, the 10th NAG capture the Village hex at 74,55:

CSVN_AAR_AI_AI_RungSat140.jpg
CSVN_AAR_AI_AI_RungSat140.jpg (1.35 MiB) Viewed 1001 times

Where did the enemy junks go?

Just one turn later, the 10th NAG Marines assault and take OBJECTIVES[21] also:

CSVN_AAR_AI_AI_RungSat141.jpg
CSVN_AAR_AI_AI_RungSat141.jpg (1.35 MiB) Viewed 1001 times

It is interesting to note that despite the SAI directive to prioritize OBJECTIVES[18] over OBJECTIVES[21]


Code: Select all

                if objective_owner(OBJECTIVES[18]) == BX_SIDE then
                    attack_strong(units, OBJECTIVES[18], UPDIR, 1, 100)
                elseif objective_owner(OBJECTIVES[21]) == BX_SIDE then
                    attack_strong(units, OBJECTIVES[21], UPDIR, 1, 100)
                end

the EAI (Engine AI) has opted to attack OBJECTIVES[21] first.

It is important to remember (quoting from https://www.matrixgames.com/forums/view ... 0&t=383969):


People somehow have the notion that the SAI dictates everything. No. As we explain and discuss and tweak the Rung Sat (and other) Lua file(s), it will become clearer over time that the game's SAI is only half of the AI story, not even that; the other half is the EAI, assisted by the AAI (Adaptive AI).

The SAI paints in broad strokes with a wide brush, works best at company level and higher. The EAI paints the finer details, works best at directing the individual platoons. The AAI adds a touch of color.

When scripting the AI, don't think of micromanaging each and every counter's movement and action hex by hex. It doesn't work that way.

There are so many factors involved, the algorithms are so complex, so much randomness is built into the system, you can never precisely direct or anticipate what the SAI/EAI/AAI will do in combination.

...

Kind of like how quantum mechanics' uncertainty principle describes the physical world, with the game's AI, you never quite know what it will do, it will be full of surprises. Think of the replayability!


Rather than go straight for OBJECTIVES[18], the EAI in its superior wisdom (superior to the SAI) decides to have 10th NAG assault the AA unit in the bunker hex to the south:

CSVN_AAR_AI_AI_RungSat142.jpg
CSVN_AAR_AI_AI_RungSat142.jpg (1.36 MiB) Viewed 1001 times

"Think of the replayability!" The next time around, in combination, and with different internal die rolls, the AI gods (SAI, EAI, AAI) might resolve the orders differently. You never know.

After a hard and lengthy fight, the 10th NAG Marines assault and overrun the enemy AA guns:

CSVN_AAR_AI_AI_RungSat143.jpg
CSVN_AAR_AI_AI_RungSat143.jpg (1.36 MiB) Viewed 1001 times

On Turn 29, OBJECTIVES[18] falls also:

CSVN_AAR_AI_AI_RungSat144.jpg
CSVN_AAR_AI_AI_RungSat144.jpg (1.09 MiB) Viewed 1001 times

Side A VNA losses are dreadful. So too the Side B BX Army. (The double '??' indicates SP losses 10+. One '?' indicates single digit SP losses.) But note: these figures include 11th NAG casualties in their fight (off screen) to the north.

This outcome was unexpected. TBH, I expected the 10th NAG to fail its mission to take both OBJECTIVES[18] & OBJECTIVES[21] (turquoise circles). (As of Turn 29, to the north, 11th NAG struggles to take the Military Post.)

With a quarter of the scenario duration remaining, what next? Go for OBJECTIVES[20] (yellow circle) a couple of klicks to the north maybe? Or?

Attached to this post is



VN_550921_Rung_Sat.zip
(18.21 KiB) Downloaded 13 times

$ unzip -l VN_550921_Rung_Sat.zip
Archive: VN_550921_Rung_Sat.zip
Length Date Time Name
--------- ---------- ----- ----
111974 10-14-2022 16:34 VN_550921_Rung_Sat.lua
--------- -------
111974 1 file



with the latest Lua code, and with all SAI activated. This is more or less the same version included in the imminent CSVN UPDATE 1.23, planned for release sometime next week hopefully.
Campaign Series Legion https://cslegion.com/
Campaign Series Lead Coder https://www.matrixgames.com/forums/view ... hp?f=10167
Panzer Campaigns, Panzer Battles Lead Coder https://wargameds.com
User avatar
berto
Posts: 21461
Joined: Wed Mar 13, 2002 1:15 am
Location: metro Chicago, Illinois, USA
Contact:

Re: Forest of Assassins - Battle of Rung Sat - 9/21/55 - AAR (AI vs. AI)

Post by berto »

berto wrote: Sat Oct 15, 2022 10:48 am
Where did the enemy junks go?

A 3D screenshot shows:

CSVN_AAR_AI_AI_RungSat145.jpg
CSVN_AAR_AI_AI_RungSat145.jpg (1.77 MiB) Viewed 997 times

In the highlighted hex (73,56), see the wreckage (fire and smoke) graphic? Evidently the enemy junks were fired on and destroyed. Indeed, see the last screenshot in the previous post. In Strength Dialog, Side B SP Losses, it says: "6 [?VP] Watercraft unit". But of course they (all six of them) were destroyed!

(Why does it show '6', not '?', like for the other Side B enemy units? It's because as larger watercraft (or vehicular) in the water, out in the open, you can't miss them, you can't fail to see their destruction. So you see that even with (Enhanced) Fog of War, you will still have glimpses of hard facts. In the game's FOW, not absolutely everything will be obscured. It all depends.)
Campaign Series Legion https://cslegion.com/
Campaign Series Lead Coder https://www.matrixgames.com/forums/view ... hp?f=10167
Panzer Campaigns, Panzer Battles Lead Coder https://wargameds.com
User avatar
berto
Posts: 21461
Joined: Wed Mar 13, 2002 1:15 am
Location: metro Chicago, Illinois, USA
Contact:

Re: Forest of Assassins - Battle of Rung Sat - 9/21/55 - AAR (AI vs. AI)

Post by berto »

For reasons that will soon become apparent, here too we will set aside the _10TH_NAVAL_ASSAULT_GROUP_379 battle plan orders, possibly returning to them later. Moving on ...

Next up is the 58th Infantry Battalion, 154th Infantry Regiment, highlighted in the screenshot following, and with its assigned Objectives circled in green:

CSVN_AAR_AI_AI_RungSat146.jpg
CSVN_AAR_AI_AI_RungSat146.jpg (3.57 MiB) Viewed 947 times

Initially, we will focus on the 1st/58th Infantry Company, ordered to take OBJECTIVES[4] then OBJECTIVES[12], winding its way through the jungle and swampy terrain as shown:

CSVN_AAR_AI_AI_RungSat147.jpg
CSVN_AAR_AI_AI_RungSat147.jpg (1.69 MiB) Viewed 947 times

The orders code is pretty straightforward:


Code: Select all

    -- _1ST_58TH_INF_COY_55_B_303 -- 1st/58th Infantry Company 55 - B
    do local units = _1ST_58TH_INF_COY_55_B_303
        if objective_owner(OBJECTIVES[4]) == BX_SIDE then
            attack_way_point(units, {"39,37", OBJECTIVES[4]}, NODIR, 0, 100, ATTACK_STRONG)
        elseif objective_owner(OBJECTIVES[12]) == BX_SIDE then
            attack_way_point(units, {"45,36", "47,36", "49,39", "51,40", OBJECTIVES[12]}, NODIR, 0, 100, ATTACK_STRONG)
        end
        if objective_owner(OBJECTIVES[4]) == VNA_SIDE then
            -- have the weakest unit among the 1st/58th garrison and defend OBJECTIVES[4]
            _VNA_OBJECTIVES4_GARRISON = _VNA_OBJECTIVES4_GARRISON or random_pick(counters_weakest(units))
            defend_normal(_VNA_OBJECTIVES4_GARRISON, OBJECTIVES[4], NODIR, 0, 100)
        end
    end


Simple, concise. But can we make it better? Yes we can!

That second if-then code block, to have the weakest unit of the 1st/58th garrison OBJECTIVES[4] -- that is something you will want to do in many attack sequences. After taking an objective, you don't want to abandon the place, leaving it entirely open to enemy reoccupcation. You will want to leave behind a defending garrison to thwart that.

A new uber function, in user.lua:


Code: Select all

-- garrison() -- among the given trackids, have the weakest unit garrison the indicated hc

function garrison (trackids, hc)

    if not trackids then return false end
    local tl
    if type(trackids) == "table" then
        if #trackids == 0 then return false end
        tl = trackids
    elseif type(trackids) == "number" then
        tl = {trackids}
    else
        return false
    end
    if not hc then return false end
    if (hc ~= HEXUNKNOWN) and not on_map(hc) then
        log(APPLOG, LOG_WARNING, "in " .. "garrison()" .. ", mistaken (off-map or nonsensical) hc " .. hc .. ", order not given")
        return false
    end

    local side = counter_side(tl[1])
    local garrison = nil

    if ((objective_owner(hc) == side) or occupied(hc, side)) then
        garrison = random_pick(counters_weakest(trackids))
        defend_normal(garrison, hc, NODIR, 0, 100)
    end

    return garrison

end


Like any of the other uber functions, you don't need to understand how they work. Just make use of them! In this circumstance, we use garrison() thusly:


Code: Select all

    -- _1ST_58TH_INF_COY_55_B_303 -- 1st/58th Infantry Company 55 - B
    do local units = difference(_1ST_58TH_INF_COY_55_B_303, _VNA_OBJECTIVES4_GARRISON)
        if objective_owner(OBJECTIVES[4]) == BX_SIDE then
            attack_way_point(units, {"39,37", OBJECTIVES[4]}, NODIR, 0, 100, ATTACK_STRONG)
        elseif objective_owner(OBJECTIVES[12]) == BX_SIDE then
            attack_way_point(units, {"45,36", "47,36", "49,39", "51,40", OBJECTIVES[12]}, NODIR, 0, 100, ATTACK_STRONG)
        end
        _VNA_OBJECTIVES4_GARRISON = _VNA_OBJECTIVES4_GARRISON or garrison(units, OBJECTIVES[4])
    end


The first time around, and for every turn OBJECTIVES[4] remains in enemy hands

  • The local variable units is set to the difference between the full _1ST_58TH_INF_COY_55_B_303 and _VNA_OBJECTIVES4_GARRISON, which before the capture is nil. In effect, units is set to the full _1ST_58TH_INF_COY_55_B_303.
  • All units are early on ordered to way point attack OBJECTIVES[4].
  • _VNA_OBJECTIVES4_GARRISON is set equal to _VNA_OBJECTIVES4_GARRISON, which is nil, so the right side of the 'or' is evaluated.
  • 'garrison(units, OBJECTIVES[4])' evaluates to nil, the return value of the garrison() function call.
  • 'nil or nil' evaluates to nil, thus early on _VNA_OBJECTIVES4_GARRISON retains its nil value.

On the turn immediately after OBJECTIVES[4]'s capture

  • The units local variable is again set to the difference between the full _1ST_58TH_INF_COY_55_B_303 and _VNA_OBJECTIVES4_GARRISON, which is still nil. In effect, units is set to the full _1ST_58TH_INF_COY_55_B_303.
  • OBJECTIVES[4] having been captured, all units are newly ordered to way point attack OBJECTIVES[12].
  • _VNA_OBJECTIVES4_GARRISON is set equal to _VNA_OBJECTIVES4_GARRISON, which is nil, so the right side of the 'or' is evaluated.
  • 'garrison(units, OBJECTIVES[4])' now evaluates to 307, the trackid of the company's weakest unit (_MMG_48_307), the return value of the garrison() function call. In the function call, _MMG_48_307 has been ordered to normal defend OBJECTIVES[4], which overrides its just issued attack_way_point() order.
  • 'nil or 307' evaluates to 307, so now _VNA_OBJECTIVES4_GARRISON finally has a non nil value, 307.

On the following turn, and every turn thereafter

  • The local variable units is set to the difference between the full _1ST_58TH_INF_COY_55_B_303 and _VNA_OBJECTIVES4_GARRISON. In effect, units is set to the a subset of _1ST_58TH_INF_COY_55_B_303 excluding trackid 307.
  • OBJECTIVES[4] having been captured, _1ST_58TH_INF_COY_55_B_303 minus _MMG_48_307 continue to way point attack OBJECTIVES[12]. _MMG_48_307 keeps its earlier normal defend OBJECTIVES[4] order, as set in the preceding garrison() call.
  • _VNA_OBJECTIVES4_GARRISON is set equal to _VNA_OBJECTIVES4_GARRISON, 307, which is non nil. This time (and subsequently), the right side of the 'or' is not evaluated, hence garrison() is no longer called for _1ST_58TH_INF_COY_55_B_303.

It is important that you get the gist of how this all works. You do not need to unpack the garrison() function definition.

But here's the thing. Instead of this


Code: Select all

    do local units = _1ST_58TH_INF_COY_55_B_303
        ...
        if objective_owner(OBJECTIVES[4]) == VNA_SIDE then
            -- have the weakest unit among the 1st/58th garrison and defend OBJECTIVES[4]
            _VNA_OBJECTIVES4_GARRISON = _VNA_OBJECTIVES4_GARRISON or random_pick(counters_weakest(units))
            defend_normal(_VNA_OBJECTIVES4_GARRISON, OBJECTIVES[4], NODIR, 0, 100)
        end
    end


we can now substitute the more concise


Code: Select all

    do local units = difference(_1ST_58TH_INF_COY_55_B_303, _VNA_OBJECTIVES4_GARRISON)
        ...
        _VNA_OBJECTIVES4_GARRISON = _VNA_OBJECTIVES4_GARRISON or garrison(units, OBJECTIVES[4]
    end


A one (or two) liner replaces a four- or five-line if-end code block. Compared to more verbose code, briefer code is easier to read, and maintain and keep bug free (because fewer fiddly details). Win!
Campaign Series Legion https://cslegion.com/
Campaign Series Lead Coder https://www.matrixgames.com/forums/view ... hp?f=10167
Panzer Campaigns, Panzer Battles Lead Coder https://wargameds.com
User avatar
berto
Posts: 21461
Joined: Wed Mar 13, 2002 1:15 am
Location: metro Chicago, Illinois, USA
Contact:

Re: Forest of Assassins - Battle of Rung Sat - 9/21/55 - AAR (AI vs. AI)

Post by berto »

On Turn 4 of the auto-test, we see:

CSVN_AAR_AI_AI_RungSat148.jpg
CSVN_AAR_AI_AI_RungSat148.jpg (1.09 MiB) Viewed 931 times

The lead platoon of the _1ST_58TH_INF_COY_55_B_303 has reached the first way point. The other platoons trail behind.

On Turn 6, a surprise:

CSVN_AAR_AI_AI_RungSat149.jpg
CSVN_AAR_AI_AI_RungSat149.jpg (1.09 MiB) Viewed 931 times

OBJECTIVES[4] is captured! So easily. Apparently there were no BX Army defenders to contest the capture.

_1ST_58TH_INF_COY_55_B_303 proceeds to way point move on to the next objective. At Turn 8:

CSVN_AAR_AI_AI_RungSat150.jpg
CSVN_AAR_AI_AI_RungSat150.jpg (1.09 MiB) Viewed 931 times

At Turn 10:

CSVN_AAR_AI_AI_RungSat151.jpg
CSVN_AAR_AI_AI_RungSat151.jpg (1.16 MiB) Viewed 931 times

_MMG_48_307, the company's weakest unit, is indeed left behind to garrison (defend normal) OBJECTIVES[4]. The garrison() uber function etc. are all WAD!

The lead platoon has reached the way point hex 49,39. The _1ST_58TH_INF_COY_55_B_303 infantry have two paths (green arrows) leading to OBJECTIVES[12]. Which one to take?

We revise the code:


Code: Select all

            attack_way_point(units, {"45,36", "47,36", "49,39", random_pick({"51,40", "51,40", "51,37"}), OBJECTIVES[12]}, NODIR, 0, 100, ATTACK_STRONG)


Um, what is that random_pick() function call doing in the list of attack_way_point() inputs (parameters)? That's odd!

But perfectly acceptable. 'random_pick({"51,40", "51,40", "51,37"})' evaluates to "51,40" or "51,37", depending (on the die roll). Whether the fourth hex in the list of way points is a hard-coded "51,40" or 'random_pick({"51,40", ...})' effectively makes no difference. You can nest function calls in your function input lists.

With that code change, we retry the auto-test, and ... the joke's on me. That random_pick() call embedded in the attack_way_point(). It refreshes each turn, there is a new random pick each go around, so the way point move goes one way, then backtracks and goes the other way, etc., etc. Oops!

Back to the drawing board:


Code: Select all

            _1ST_58TH_INF_COY_55_B_303_WAYPOINT4 = _1ST_58TH_INF_COY_55_B_303_WAYPOINT4 or random_pick({"51,40", "51,40", "51,37"})
            attack_way_point(units, {"45,36", "47,36", "49,39", _1ST_58TH_INF_COY_55_B_303_WAYPOINT4, OBJECTIVES[12]}, NODIR, 0, 100, ATTACK_STRONG)


We set a new global variable _1ST_58TH_INF_COY_55_B_303_WAYPOINT4 once and only once to the random_pick() result. With every attack_way_point() call, the fourth way point never varies. Problem solved!

Note: The issue was not embedding functions calls in function parameter lists. It is okay to do that. The issue here was that this one particular embedded function call, random_pick(), is repeatedly called turn after turn, and with each new turn, potentially gives a different result, making the way point list variable from turn to turn leading to chaotic, random movement.

Note that in the 'random_pick({"51,40", "51,40", "51,37"})' we have "51,40" twice and "51,37". This implies a 2 out of 3 chance that "51,40" will be randomly picked, "51,37" only a 1 out of 3 chance. It is more likely the 1st/58th infantry will continue taking the right fork Path (PT) to OBJECTIVES[12]. But we allow for the possibility it will go off Path and take the left fork (left green arrow in the preceding screenshot).

We could have done this:


Code: Select all

            if chance(66) then
                attack_way_point(units, {"45,36", "47,36", "49,39", "51,40", OBJECTIVES[12]}, NODIR, 0, 100, ATTACK_STRONG)
            else
                attack_way_point(units, {"45,36", "47,36", "49,39", "51,37", OBJECTIVES[12]}, NODIR, 0, 100, ATTACK_STRONG)
            end


Is one way or the other briefer, more concise? Arguable. Take your pick.

We let the auto-test run another turn, then:

CSVN_AAR_AI_AI_RungSat152.jpg
CSVN_AAR_AI_AI_RungSat152.jpg (1.16 MiB) Viewed 931 times

Okay, the 1st/58th infantry are taking the right fork, on-path route to OBJECTIVES[12].

Two turns later:

CSVN_AAR_AI_AI_RungSat153.jpg
CSVN_AAR_AI_AI_RungSat153.jpg (1.1 MiB) Viewed 931 times

Side B BX Army defenders opfire at the approaching VNA infantry, but undeterred, the _2ND_PLT_305 immediately assaults OBJECTIVES[12] and captures it. That too was easy!

We are only 13 turns into the scenario and by now _1ST_58TH_INF_COY_55_B_303 has succeeded in its two assigned missions. What to do next? After garrisoning OBJECTIVES[12], the other two platoons could wander about generally southward looking for trouble, looking for BX Army supply dumps and jungle factories to destroy. Or we could let them rest on their laurels, no more orders.

Before going in, how would the VNA know that OBJECTIVES[4] and OBJECTIVES[12] were so lightly defended? Consider the other fights around the map coded and described in earlier posts. Most of them were challenges, some of them very tough fights. Like the other cases, in this case, we might suppose that _1ST_58TH_INF_COY_55_B_303 would also face some tough, drawn out fights, requiring most of the scenario to (a) do the way point moves (what if intercepted along the way by enemy units?) and (b) assault and capture the two Objectives (what if they were stoutly defended?).

No, it is reasonable that we code the _1ST_58TH_INF_COY_55_B_303 battle plan orders no further. Why write speculative code based on unlikely situations? For the 1st/58th, we will let the matter rest.

Hmm. Since we know there is a possibility that the OBJECTIVES[12] Military Post will fall as early as Turn 13, should we consider delaying the _NAVAL_ASSAULT_GROUPS_377 in their movement down the Song Long Tau to the Nga Ba Dong Tranh and beyond? Where in passing by the (OBJECTIVES[12]) Military Post they are opfired at and, as we have seen, suffering SP loss in the passage? Should we code _NAVAL_ASSAULT_GROUPS_377 maybe to delay, awaiting the _1ST_58TH_INF_COY_55_B_303 first taking out the Military Post defenders? Something to think about.
Campaign Series Legion https://cslegion.com/
Campaign Series Lead Coder https://www.matrixgames.com/forums/view ... hp?f=10167
Panzer Campaigns, Panzer Battles Lead Coder https://wargameds.com
User avatar
berto
Posts: 21461
Joined: Wed Mar 13, 2002 1:15 am
Location: metro Chicago, Illinois, USA
Contact:

Re: Forest of Assassins - Battle of Rung Sat - 9/21/55 - AAR (AI vs. AI)

Post by berto »

Considering now also the rest of the 58th/154th Infantry Battalion:

CSVN_AAR_AI_AI_RungSat154.jpg
CSVN_AAR_AI_AI_RungSat154.jpg (3.47 MiB) Viewed 889 times

The 2nd/58th and the Weapons Coy (turquoise highlights) are to head southeastward, attack first OBJECTIVES[6], then OBJECTIVES[7] (green arrows).

The 3rd/58th (magenta highlights) is to stay behind, help to defend the two VNA Military Posts in the rear. How can we be sure there are not enemy forces lurking about? Probably not, but can we be sure? Better not to take chances. (And as we shall soon see, the 3rd/58th does not really need to advance anyway.)

(There is no 4th/58th in this scenario.)

Here is the orders code for the entire battalion:


Code: Select all

    --------------------------------------------------------------------------
    -- _58TH_154TH_INF_BTN_55_B_301 -- 58th/154th Infantry Battalion 55 - B --
    --------------------------------------------------------------------------

    -- _HQ_302 -- ARVN Battalion HQ (foot)
    -- _58TH_154TH_465 -- ARVN Commander 1
    do local units = join({_HQ_302, _58TH_154TH_465})
        defend_normal(units, OBJECTIVES[2], NODIR, 0, 100)
    end

    -- _1ST_58TH_INF_COY_55_B_303 -- 1st/58th Infantry Company 55 - B
    do local units = difference(_1ST_58TH_INF_COY_55_B_303, _VNA_OBJECTIVES4_GARRISON)
        if objective_owner(OBJECTIVES[4]) == BX_SIDE then
            attack_way_point(units, {"39,37", OBJECTIVES[4]}, NODIR, 0, 100, ATTACK_STRONG)
        elseif objective_owner(OBJECTIVES[12]) == BX_SIDE then
            _1ST_58TH_INF_COY_55_B_303_WAYPOINT4 = _1ST_58TH_INF_COY_55_B_303_WAYPOINT4 or random_pick({"51,40", "51,40", "51,37"})
            attack_way_point(units, {"45,36", "47,36", "49,39", _1ST_58TH_INF_COY_55_B_303_WAYPOINT4, OBJECTIVES[12]}, NODIR, 0, 100, ATTACK_STRONG)
        end
        _VNA_OBJECTIVES4_GARRISON = _VNA_OBJECTIVES4_GARRISON or garrison(units, OBJECTIVES[4])
    end

    -- _2ND_58TH_INF_COY_55_B_309 -- 2nd/58th Infantry Company 55 - B
    -- _58TH_WEAPONS_COY_55_327 -- 58th Weapons Company 55
    do local units = difference(join({_2ND_58TH_INF_COY_55_B_309, _58TH_WEAPONS_COY_55_327}), join({{_VNA_OBJECTIVES6_GARRISON}, {_VNA_OBJECTIVES7_GARRISON}}))
        if objective_owner(OBJECTIVES[6]) == BX_SIDE then
            attack_way_point(units, {"40,39", "43,40", OBJECTIVES[6]}, NODIR, 0, 100, ATTACK_STRONG)
        elseif objective_owner(OBJECTIVES[7]) == BX_SIDE then
            attack_strong(units, OBJECTIVES[7])
        else
            -- assist in attack on OBJECTIVES[12]?  or, what else?
        end
        _VNA_OBJECTIVES6_GARRISON = _VNA_OBJECTIVES6_GARRISON or garrison(units, OBJECTIVES[6])
        _VNA_OBJECTIVES7_GARRISON = _VNA_OBJECTIVES7_GARRISON or garrison(difference(units, _VNA_OBJECTIVES6_GARRISON), OBJECTIVES[7])
    end
    -- _81MM_MORTAR_331 -- M1 81mm Mortars
    if objective_owner(OBJECTIVES[6]) == VNA_SIDE then
        if not at(_81MM_MORTAR_331, OBJECTIVES[6]) then
            move_norush(_81MM_MORTAR_331, OBJECTIVES[6])
        else
            fire_indirect_nearest(_81MM_MORTAR_331, 100)
        end
    end

    -- _3RD_58TH_INF_COY_55_B_315 -- 3rd/58th Infantry Company 55 - B
    do local units = _3RD_58TH_INF_COY_55_B_315
        defend_way_point(join({_3RD_PLT_318, _MMG_48_319}), {"31,37", OBJECTIVES[2]})
    end


The battalion leadership, _HQ_302 (the Battalion HQ) & _58TH_154TH_465 (the Commander), we have them defend in place.

For the _1ST_58TH_INF_COY_55_B_303, the orders code is unchanged from before.

We join the _2ND_58TH_INF_COY_55_B_309 & _58TH_WEAPONS_COY_55_327 into a single units package, and have them way point attack OBJECTIVES[6], then directly attack OBJECTIVES[7]. After that, what next?

In the second of the two garrison determinations


Code: Select all

        _VNA_OBJECTIVES6_GARRISON = _VNA_OBJECTIVES6_GARRISON or garrison(units, OBJECTIVES[6])
        _VNA_OBJECTIVES7_GARRISON = _VNA_OBJECTIVES7_GARRISON or garrison(difference(units, _VNA_OBJECTIVES6_GARRISON), OBJECTIVES[7])


note where we need to exclude _VNA_OBJECTIVES6_GARRISON when determining _VNA_OBJECTIVES7_GARRISON. We do that by means of the 'difference(units, _VNA_OBJECTIVES6_GARRISON)'.

On first auto-test, this error:



2022-10-29 10:57:16 vnengine.exe: [ERROR ID 3004] (appl.cpp, line 4822, ApplWindow::LOnNextPhase()) in ApplWindow::LOnNextPhase(), error running function 'on_next_phase': init.lua:603: bad argument #1 to 'for iterator' (table expected, got number)



init.lua:603 is this line:

CSVN_AAR_AI_AI_RungSat165.jpg
CSVN_AAR_AI_AI_RungSat165.jpg (76.5 KiB) Viewed 889 times

Evidently, the Lua interpreter finds fault with the lists input. Looking at the orders code, in this line, originally written as


Code: Select all

    do local units = difference(join({_2ND_58TH_INF_COY_55_B_309, _58TH_WEAPONS_COY_55_327}), join({_VNA_OBJECTIVES6_GARRISON, _VNA_OBJECTIVES7_GARRISON}))


we need to put { and } around the *GARRISON, as in (look closely!)


Code: Select all

    do local units = difference(join({_2ND_58TH_INF_COY_55_B_309, _58TH_WEAPONS_COY_55_327}), join({{_VNA_OBJECTIVES6_GARRISON}, {_VNA_OBJECTIVES7_GARRISON}}))


Why? It is because the join() function expects to have a list of lists as its first input. _VNA_OBJECTIVES6_GARRISON and _VNA_OBJECTIVES7_GARRISON are not lists, aka Lua "tables"; they are in fact trackids (integers). We need to enclose _VNA_OBJECTIVES6_GARRISON etc. with { and } in order to make them the required lists. The Lua CSEE is usually forgiving about this sort of thing, usually auto-corrects if you don't manage your { and } and so on properly. But this is not one of those cases. Beware!
Campaign Series Legion https://cslegion.com/
Campaign Series Lead Coder https://www.matrixgames.com/forums/view ... hp?f=10167
Panzer Campaigns, Panzer Battles Lead Coder https://wargameds.com
User avatar
berto
Posts: 21461
Joined: Wed Mar 13, 2002 1:15 am
Location: metro Chicago, Illinois, USA
Contact:

Re: Forest of Assassins - Battle of Rung Sat - 9/21/55 - AAR (AI vs. AI)

Post by berto »

On Turn 4 of the subsequent auto-test, we see:

CSVN_AAR_AI_AI_RungSat155.jpg
CSVN_AAR_AI_AI_RungSat155.jpg (1.12 MiB) Viewed 887 times

Three turns later:

CSVN_AAR_AI_AI_RungSat156.jpg
CSVN_AAR_AI_AI_RungSat156.jpg (1.13 MiB) Viewed 887 times

And three more turns after that, at Turn10:

CSVN_AAR_AI_AI_RungSat157.jpg
CSVN_AAR_AI_AI_RungSat157.jpg (1.12 MiB) Viewed 887 times

Uneventful thus far. But not for long.

On Turn, _2ND_58TH_INF_COY_55_B_309 assaults OBJECTIVES[6]. The defenders are pushovers:

CSVN_AAR_AI_AI_RungSat158.jpg
CSVN_AAR_AI_AI_RungSat158.jpg (336.88 KiB) Viewed 887 times

At Turn10, Side B phase, a BX Army sniper fires back:

CSVN_AAR_AI_AI_RungSat159.jpg
CSVN_AAR_AI_AI_RungSat159.jpg (342.36 KiB) Viewed 887 times

Ignoring the sniper, the _2ND_58TH_INF_COY_55_B_309 presses forward. On Turn 12, OBJECTIVES[7] falls without apparent opposition:

CSVN_AAR_AI_AI_RungSat160.jpg
CSVN_AAR_AI_AI_RungSat160.jpg (1.12 MiB) Viewed 887 times

VNA artillery fire at the sniper from off-screen to the southwest:

CSVN_AAR_AI_AI_RungSat161.jpg
CSVN_AAR_AI_AI_RungSat161.jpg (1.11 MiB) Viewed 887 times

Even though we haven't yet written orders code for those artillery, they still fire, because their standing order at this point is halt(). A Halt order doesn't preclude opportunity firing. Note: It is the EAI, not the SAI, that is taking this initiative.

At Turn 13, the enemy sniper is eliminated (magenta circle):

CSVN_AAR_AI_AI_RungSat162.jpg
CSVN_AAR_AI_AI_RungSat162.jpg (381.33 KiB) Viewed 887 times

Were the VNA explicitly SAI ordered to fire on that enemy sniper? No. Another example the game engine EAI taking the initiative.

Also on Turn 13, to the northeast, the OBJECTIVES[12] Military Post is assaulted and taken:

CSVN_AAR_AI_AI_RungSat163.jpg
CSVN_AAR_AI_AI_RungSat163.jpg (238.36 KiB) Viewed 887 times
Campaign Series Legion https://cslegion.com/
Campaign Series Lead Coder https://www.matrixgames.com/forums/view ... hp?f=10167
Panzer Campaigns, Panzer Battles Lead Coder https://wargameds.com
User avatar
berto
Posts: 21461
Joined: Wed Mar 13, 2002 1:15 am
Location: metro Chicago, Illinois, USA
Contact:

Re: Forest of Assassins - Battle of Rung Sat - 9/21/55 - AAR (AI vs. AI)

Post by berto »

At Turn 15, we have this:

CSVN_AAR_AI_AI_RungSat164.jpg
CSVN_AAR_AI_AI_RungSat164.jpg (2.12 MiB) Viewed 872 times

All Objectives in the 58th/154th Infantry Battalion's AO are captured. What else is there to do?

In the Scenario Briefing, let us not forget this:



"Your Primary Mission is to clear the entire area of operations, defeating any Binh Xuen forces that are found.

"Your Secondary Mission is to destroy any headquarters and supplies found."



The Primary Mission goes without saying, but the Secondary bears emphasizing.

So what else could the 58th/154th do? Go swamp rat hunting!

The _58TH_154TH_INF_BTN_55_B_301 could retrace its steps. Beyond defending the rear areas, the _3RD_58TH_INF_COY_55_B_315 could head up the peninsula to the northwest. But you should know: The Rung Sat Swamp is southeast of Saigon. After the earlier Battle of Saigon (see the VN_550429_Saigon scenario), the VNA are pushing the BX Army away, generally to the southeast. Northwest of this scenario's (VN_550921_Rung_Sat) VNA "front line", we might expect that rearward area already to be cleared. So retracing and searching to the rear is not likely to be fruitful.

But if the 58th/154th is to press forward, where can in the swampy morass can it reasonably go? In the above screenshot, the green arrows show some possible pathways.

Or, scripting this might be pointless. As before, how would the VNA high command expect the 58th/154th's missions to be cakewalks? Who would have thought these nearby Objectives would be so lightly defended? Recall the tough fights in the 1st Parachute Battalion's AO to the north. Why would the VNA high command expect the 58th/154th Infantry Battalion's experience to be any different?

If this Side A VNA Army were being human played, the human player might now sail some spare riverine units, if any, up those inland waterways to provide ferry crossing points. It is something we might return to later, but good luck scripting that.

With over half the scenario remaining, we might even send a flotilla of riverines to transport the 58th/154th Infantry hither and yon. But they are Infantry, not Marines. Moreover, sending the 58th/154th off on some entirely different, improvised mission would demand a situational awareness, superior communications, and overall command flexibility unlikely in Real Life, especially so for the fledgling Vietnamese National Army (just after conclusion of the French Indochina War).

When SAI'ing, we must resist the temptation to script forces in all-knowing fashion, with hindsight gained (a) from designing the scenario, and knowing where all of the forces are (no FOW), and (b) after repeated auto-tests. When SAI'ing forces, we should put ourselves in the shoes of the high commands with the knowledge and capabilities they had at the time. Again, the aim here is plausibility, not crafting an AI approaching supercomputer levels of competence (if that were even possible).

Another consideration: There are only so many hours in the day, days in the week, etc. Do we have time to SAI a scenario endlessly in a quixotic quest to achieve the "perfect" AI? The question answers itself.

Before we move on, I have revised the Lua script, substituting this


Code: Select all

    -- _81MM_MORTAR_331 -- M1 81mm Mortars
    fire_indirect_nearest_from(_81MM_MORTAR_331, OBJECTIVES[6])


for this


Code: Select all

    -- _81MM_MORTAR_331 -- M1 81mm Mortars
    if objective_owner(OBJECTIVES[6]) == VNA_SIDE then
        if not at(_81MM_MORTAR_331, OBJECTIVES[6]) then
            move_norush(_81MM_MORTAR_331, OBJECTIVES[6])
        else
            fire_indirect_nearest(_81MM_MORTAR_331, 100)
        end
    end


See the difference? The first example uses the new uber function fire_indirect_nearest_from(), which moves the artillery piece to the firebase first (if safe to do so), from there firing at the nearest enemy. Something you will see over and over again, this special handling of company artillery (overriding the earlier units-wide orders). A one-liner (ignoring the -- comment) vs. six lines of script code. More concise, earlier to read, easier to maintain. Win, win, win!

In another auto-test, I confirmed that the above code -- the first of the two examples, the one using the new fire_indirect_nearest_from() uber function -- has positioned _81MM_MORTAR_331 at OBJECTIVES[6], there ready to indirect fire at the nearest enemy. (Note where _MMG_329, the weakest unit in the joined _2ND_58TH_INF_COY_55_B_309 & _58TH_WEAPONS_COY_55_327, is stationed there also.)

Attached are the latest versions of the pertinent files, including the new fire_indirect_nearest_from() function, and other improvements:

$ unzip -l VN_550921_Rung_Sat_20221029.zip
Archive: VN_550921_Rung_Sat_20221029.zip
Length Date Time Name
--------- ---------- ----- ----
113822 10-29-2022 14:06 VN_550921_Rung_Sat.lua
459150 10-29-2022 10:02 init.lua
113107 10-29-2022 14:04 user.lua
--------- -------
686079 3 files

VN_550921_Rung_Sat_20221029.zip
(72.14 KiB) Downloaded 16 times

For you to have a look-see, and perhaps to run your own auto-tests with (good luck).
Campaign Series Legion https://cslegion.com/
Campaign Series Lead Coder https://www.matrixgames.com/forums/view ... hp?f=10167
Panzer Campaigns, Panzer Battles Lead Coder https://wargameds.com
User avatar
berto
Posts: 21461
Joined: Wed Mar 13, 2002 1:15 am
Location: metro Chicago, Illinois, USA
Contact:

Re: Forest of Assassins - Battle of Rung Sat - 9/21/55 - AAR (AI vs. AI)

Post by berto »

Saving for last the toughest assignments, the 22nd/154th Infantry Battalion AO:

CSVN_AAR_AI_AI_RungSat166.jpg
CSVN_AAR_AI_AI_RungSat166.jpg (3.57 MiB) Viewed 758 times

The 22nd/154th has three Objectives to capture: OBJECTIVES[3], the Military Post to the left (west); OBJECTIVES[5], Xom Rach Bac Kieng; and OBJECTIVES[11], the Military Post to the right (east).

There is one, and only one, River (W) and Minor River (MR) crossing point, the shallow spot at hex 41,56 (green circle). It is key to the whole operation. How to get there (and beyond)? By some twisty turny paths (see the green arrows to the left). There are effectively no other ways.

Since there is only one hexside for the 22nd/154th to assault the first Objective, OBJECTIVES[3], if that Objective is heavily defended, we might anticipate a long, bloody fight for that Military Post. A good place to target some airstrikes?

Beyond that, more torturous pathways to the other two Objectives (see the green arrows to the right).

As with the 58th/154th (see preceding posts), we should consider nabbing some spare riverine transports, if any, to sail up some of these inland waterways to provide some ferry crossing points, thereby opening up some alternate pathways. We might even order the Marines to take OBJECTIVES[11], the Military Post to the east.

But for now, we will just script the 22nd/154th orders as best we can.
Campaign Series Legion https://cslegion.com/
Campaign Series Lead Coder https://www.matrixgames.com/forums/view ... hp?f=10167
Panzer Campaigns, Panzer Battles Lead Coder https://wargameds.com
User avatar
berto
Posts: 21461
Joined: Wed Mar 13, 2002 1:15 am
Location: metro Chicago, Illinois, USA
Contact:

Re: Forest of Assassins - Battle of Rung Sat - 9/21/55 - AAR (AI vs. AI)

Post by berto »

At first, we script _2ND_22ND_INF_COY_55_B_278 and _22NDWEAPONS_COY_55_296 to way point attack OBJECTIVES[3], taking the initially due east route:


Code: Select all

    -- _2ND_22ND_INF_COY_55_B_278 -- 2nd/22nd Infantry Company 55 - B
    -- _22NDWEAPONS_COY_55_296 -- 22ndWeapons Company 55
    do local units = difference(join({_2ND_22ND_INF_COY_55_B_278, _22NDWEAPONS_COY_55_296}), _2ND_22ND_467)
        attack_way_point(units, {"35,50", "39,56", OBJECTIVES[3]}, NODIR, 0, 100, ATTACK_STRONG)
    end
    -- _81MM_MORTAR_300 -- M1 81mm Mortars
    fire_indirect_nearest_from(_81MM_MORTAR_300, "37,53")


In the auto-test, at Turn 5, we see this:

CSVN_AAR_AI_AI_RungSat167.jpg
CSVN_AAR_AI_AI_RungSat167.jpg (572.85 KiB) Viewed 805 times

Not good. A lone commander should not be out in front like that.

Looking at the org lists, we see:


Code: Select all

    _2ND_22ND_INF_COY_55_B_278 = {467,279,280,281,282} -- [C] [1102239] 2nd/22nd Infantry Company 55 - B
    _2ND_22ND_467 = {467} -- [P] [32,48] [114001] ARVN Commander 1
    _1ST_PLT_279 = {279} -- [P] [32,48] [112007] ARVN Infantry Platoon 55 B
    _2ND_PLT_280 = {280} -- [P] [32,48] [112007] ARVN Infantry Platoon 55 B
    _3RD_PLT_281 = {281} -- [P] [32,49] [112007] ARVN Infantry Platoon 55 B
    _MMG_48_282 = {282} -- [P] [32,49] [112071] M1919A4 Machine Gun


A special company commander (second item in that list) is leading the 2nd/22nd. We need for him to stick with his units.

I create a new uber function (in user.lua), accompany():


Code: Select all

-- accompany() -- move the follower units along with, accompanying the leads

function accompany (followers, leaders)

    if not followers then return false end
    local fl
    if type(followers) == "table" then
        if #followers == 0 then return false end
        fl = followers
    elseif type(followers) == "number" then
        fl = {followers}
    else
        return false
    end
    if not leaders then return false end
    local ll
    if type(leaders) == "table" then
        if #leaders == 0 then return false end
        ll = leaders
    elseif type(leaders) == "number" then
        ll = {leaders}
    else
        return false
    end

    local hc = random_pick(counter_hexes(difference(ll, fl)))
    move_norush(fl, hc)

    return hc ~= HEXUNKNOWN

end


I revise the orders code:


Code: Select all

    -- _2ND_22ND_INF_COY_55_B_278 -- 2nd/22nd Infantry Company 55 - B
    -- _22NDWEAPONS_COY_55_296 -- 22ndWeapons Company 55
    do local units = join({_2ND_22ND_INF_COY_55_B_278, _22NDWEAPONS_COY_55_296})
        attack_way_point(units, {"35,50", "39,56", OBJECTIVES[3]}, NODIR, 0, 100, ATTACK_STRONG)
    end
    -- _2ND_22ND_467
    accompany(_2ND_22ND_467, _2ND_22ND_INF_COY_55_B_278)
    -- _81MM_MORTAR_300 -- M1 81mm Mortars
    fire_indirect_nearest_from(_81MM_MORTAR_300, "37,53")


Initially, in the units definition


Code: Select all

    do local units = difference(join({_2ND_22ND_INF_COY_55_B_278, _22NDWEAPONS_COY_55_296}), _2ND_22ND_467)


But because the accompany() call assigns an overriding move_norush() order to _2ND_22ND_467, there is no need to exclude _2ND_22ND_467 from the units list.

At turn 4 of a restarted auto-test, this:

CSVN_AAR_AI_AI_RungSat168.jpg
CSVN_AAR_AI_AI_RungSat168.jpg (1.26 MiB) Viewed 805 times

So far, so good. The Commander is sticking with his units.

Three turns later, at Turn 7, again the Commander is sticking with this units:

CSVN_AAR_AI_AI_RungSat169.jpg
CSVN_AAR_AI_AI_RungSat169.jpg (1.24 MiB) Viewed 805 times

Three turns after that, at Turn 10, I see a problem:

CSVN_AAR_AI_AI_RungSat170.jpg
CSVN_AAR_AI_AI_RungSat170.jpg (1.21 MiB) Viewed 805 times

Can you spot it?

...

It is this. _81MM_MORTAR_300 is supposed to remain behind, indirect firing from hex "37,53" (yellow circle).

In user.lua, I correct the fire_indirect_nearest_from() function definition:


Code: Select all

    if not occupied(hc, other_side) then
--    if (objective_owner(hc) == side) or occupied(hc, side) then
        if not at(tl, hc) then
            move_norush(tl, hc)
        else
            return fire_indirect_nearest(tl, 100)
        end
    end


In the earlier definition, we check whether the hc is own-side owned, if an Objective, or own-side occupied. But what if the hex is not occupied? Evidently, hex "37,53" may or may not be owned (because not an Objective) or own-side occupied, so the mortars movement to that hex never happens. The fix is to check whether the hex is not other side occupied (hence is safe to move there).

With fire_indirect_nearest_from() fixed, at Turn 10 of a retried auto-test, it shows:

CSVN_AAR_AI_AI_RungSat171.jpg
CSVN_AAR_AI_AI_RungSat171.jpg (1.24 MiB) Viewed 805 times

_81MM_MORTAR_300 is indeed sited at hex "37,53" (and subsequently indirect fires from that place). That's better!
Campaign Series Legion https://cslegion.com/
Campaign Series Lead Coder https://www.matrixgames.com/forums/view ... hp?f=10167
Panzer Campaigns, Panzer Battles Lead Coder https://wargameds.com
User avatar
berto
Posts: 21461
Joined: Wed Mar 13, 2002 1:15 am
Location: metro Chicago, Illinois, USA
Contact:

Re: Forest of Assassins - Battle of Rung Sat - 9/21/55 - AAR (AI vs. AI)

Post by berto »

In the attack approach to on OBJECTIVES[3], this:

CSVN_AAR_AI_AI_RungSat172.jpg
CSVN_AAR_AI_AI_RungSat172.jpg (343.99 KiB) Viewed 799 times

Ouch! The attack hasn't started, and already an entire VNA platoon is eliminated.

A while later, more bad news:

CSVN_AAR_AI_AI_RungSat173.jpg
CSVN_AAR_AI_AI_RungSat173.jpg (273.62 KiB) Viewed 799 times

Some good news. The VNA have stumbled on a BX Army supply cache:

CSVN_AAR_AI_AI_RungSat174.jpg
CSVN_AAR_AI_AI_RungSat174.jpg (250.85 KiB) Viewed 799 times

The first VNA assault:

CSVN_AAR_AI_AI_RungSat175.jpg
CSVN_AAR_AI_AI_RungSat175.jpg (410.29 KiB) Viewed 799 times

A tough fight indeed.

The Military Post is a Building hex, with substantial defensive benefits (low TEM, 0.60). In fire after fire, one arty strike to the next, I see lots of "No Effect" and "Unknown Effects".

CSVN_AAR_AI_AI_RungSat176.jpg
CSVN_AAR_AI_AI_RungSat176.jpg (17 KiB) Viewed 799 times

Meanwhile, the VNA are out in the open (in the swamp) getting clobbered.

At Turn 19, unexpectedly:

CSVN_AAR_AI_AI_RungSat177.jpg
CSVN_AAR_AI_AI_RungSat177.jpg (570.32 KiB) Viewed 799 times

OBJECTIVES[3] falls! Just as good, the enemy Supply Depot at that place is destroyed. We infer this, because supply depots are immobile, and there is no unit accompanying the retreated engineer unit.

The situation at Turn 20, the scenario's half-way point:

CSVN_AAR_AI_AI_RungSat178.jpg
CSVN_AAR_AI_AI_RungSat178.jpg (1.41 MiB) Viewed 776 times

Look at those Side A SP Losses. Awful! But an important Military Post is taken, and an enemy Supply Depot is destroyed. All in all, the sacrifice is worth it.

Do the 2nd/22nd Infantry Company and 22nd Weapons Company have enough strength to continue the fight? They still have two full-strength platoons remaining (see the insert), but the remainder of the force is depleted, next to useless. Without RR & MG support, it is difficult to foresee them taking OBJECTIVES[5], if strongly defended. Not to mention they still have that nearby enemy engineer platoon to contend with. Scout around for enemy easy-pickings Supply Depots and Jungle Factories, maybe?
Campaign Series Legion https://cslegion.com/
Campaign Series Lead Coder https://www.matrixgames.com/forums/view ... hp?f=10167
Panzer Campaigns, Panzer Battles Lead Coder https://wargameds.com
User avatar
berto
Posts: 21461
Joined: Wed Mar 13, 2002 1:15 am
Location: metro Chicago, Illinois, USA
Contact:

Re: Forest of Assassins - Battle of Rung Sat - 9/21/55 - AAR (AI vs. AI)

Post by berto »

I script the rest of the 22nd/154th Infantry Battalion:


Code: Select all

    --------------------------------------------------------------------------
    -- _22ND_154TH_INF_BTN_55_B_270 -- 22nd/154th Infantry Battalion 55 - B --
    --------------------------------------------------------------------------

    -- _HQ_271 -- ARVN Battalion HQ (foot)
    do local units = _HQ_271
        defend_normal(units) -- defend in place
    end

    -- _22ND_154TH_464 -- ARVN Commander 1
    do local units = _22ND_154TH_464
        -- lead attack on OBJECTIVES[11] or OBJECTIVES[5]; see below
    end

    -- _1ST_22ND_INF_COY_55_B_272 -- 1st/22nd Infantry Company 55 - B
    -- _3RD_22ND_INF_COY_55_B_284 -- 3rd/22nd Infantry Company 55 - B
    do local units = join({_1ST_22ND_INF_COY_55_B_272, _3RD_22ND_INF_COY_55_B_284})
        _1ST_22ND_3RD_22ND_OBJECTIVE = _1ST_22ND_3RD_22ND_OBJECTIVE or random_pick({OBJECTIVES[11], OBJECTIVES[11], OBJECTIVES[5]})
        if objective_owner(OBJECTIVES[3]) == BX_SIDE then
            move_way_point(units, {"32,53", "36,54", "39,57"})
        else
            if _1ST_22ND_3RD_22ND_OBJECTIVE == OBJECTIVES[11] then
                attack_way_point(units, {OBJECTIVES[3], "45,51", "48,53", "51,54", OBJECTIVES[11]}, NODIR, 0, 100, ATTACK_STRONG)
            elseif _1ST_22ND_3RD_22ND_OBJECTIVE == OBJECTIVES[5] then
                attack_way_point(units, {OBJECTIVES[3], "43,49", OBJECTIVES[5]}, NODIR, 0, 100, ATTACK_STRONG)
            end
        end
        accompany(_22ND_154TH_464, units)
        garrison(_MMG_48_288, "32,49") -- keep behind _3RD_22ND_INF_COY_55_B_284 _MMG_48_288 to garrison MP at hex 32,49
    end

    -- _2ND_22ND_INF_COY_55_B_278 -- 2nd/22nd Infantry Company 55 - B
    -- _22NDWEAPONS_COY_55_296 -- 22ndWeapons Company 55
    do local units = difference(join({_2ND_22ND_INF_COY_55_B_278, _22NDWEAPONS_COY_55_296}), _2ND_22ND_467)
        if objective_owner(OBJECTIVES[3]) == BX_SIDE then
            attack_way_point(units, {"35,50", "39,56", OBJECTIVES[3]}, NODIR, 0, 100, ATTACK_STRONG)
        elseif objective_owner(OBJECTIVES[5]) == BX_SIDE then
            attack_way_point(units, {OBJECTIVES[3], "43,49", OBJECTIVES[5]}, NODIR, 0, 100, ATTACK_STRONG)
        end
        garrison(units, OBJECTIVES[3])
    end
    -- _2ND_22ND_467
    accompany(_2ND_22ND_467, _2ND_22ND_INF_COY_55_B_278)
    -- _81MM_MORTAR_300 -- M1 81mm Mortars
    fire_indirect_nearest_from(_81MM_MORTAR_300, "37,53")


Focus on the top two thirds of that. The bottom one third we had scripted earlier.

As mentioned earlier, there is one and only way forward, the shallow river hex 41,56. And that is the only hex from which to assault OBJECTIVES[3]. _2ND_22ND_INF_COY_55_B_278 and _22NDWEAPONS_COY_55_296 were earlier assigned to attack and capture that place. The other two companies, _1ST_22ND_INF_COY_55_B_272 and _3RD_22ND_INF_COY_55_B_284, we have them way point move to nearby hex 39,57, then stick around off to the side awaiting capture of OBJECTIVES[3]:


Code: Select all

        if objective_owner(OBJECTIVES[3]) == BX_SIDE then
            move_way_point(units, {"32,53", "36,54", "39,57"})


Else OBJECTIVES[3] has been captured, so the 1st/22nd and 3rd/22nd move to way point attack either OBJECTIVES[11] (2/3 chance) or OBJECTIVES[5] (1/3 chance).


Code: Select all

        _1ST_22ND_3RD_22ND_OBJECTIVE = _1ST_22ND_3RD_22ND_OBJECTIVE or random_pick({OBJECTIVES[11], OBJECTIVES[11], OBJECTIVES[5]})
        ...
        else
            if _1ST_22ND_3RD_22ND_OBJECTIVE == OBJECTIVES[11] then
                attack_way_point(units, {OBJECTIVES[3], "45,51", "48,53", "51,54", OBJECTIVES[11]}, NODIR, 0, 100, ATTACK_STRONG)
            elseif _1ST_22ND_3RD_22ND_OBJECTIVE == OBJECTIVES[5] then
                attack_way_point(units, {OBJECTIVES[3], "43,49", OBJECTIVES[5]}, NODIR, 0, 100, ATTACK_STRONG)
            end
        end


If the latter, they join the 2nd/22nd and the Weapons Company in attacking OBJECTIVES[5]:


Code: Select all

        elseif objective_owner(OBJECTIVES[5]) == BX_SIDE then
            attack_way_point(units, {OBJECTIVES[3], "43,49", OBJECTIVES[5]}, NODIR, 0, 100, ATTACK_STRONG)
        end


The battalion commander is assigned to accompany the 1st/22nd & 3rd/22nd as they advance and attack:


Code: Select all

       accompany(_22ND_154TH_464, units)


The Battalion HQ remains behind at its orginal location


Code: Select all

    -- _HQ_271 -- ARVN Battalion HQ (foot)
    do local units = _HQ_271
        defend_normal(units) -- defend in place
    end


as does the 3rd/22nd's machine gunners


Code: Select all

        garrison(_MMG_48_288, "32,49") -- keep behind _3RD_22ND_INF_COY_55_B_284 _MMG_48_288 to garrison MP at hex 32,49


Let's see how this latest orders code plays out ...
Campaign Series Legion https://cslegion.com/
Campaign Series Lead Coder https://www.matrixgames.com/forums/view ... hp?f=10167
Panzer Campaigns, Panzer Battles Lead Coder https://wargameds.com
User avatar
berto
Posts: 21461
Joined: Wed Mar 13, 2002 1:15 am
Location: metro Chicago, Illinois, USA
Contact:

Re: Forest of Assassins - Battle of Rung Sat - 9/21/55 - AAR (AI vs. AI)

Post by berto »

In the auto-test, OBJECTIVES[3] (yellow circle) falls by Turn 13:

CSVN_AAR_AI_AI_RungSat179.jpg
CSVN_AAR_AI_AI_RungSat179.jpg (1.72 MiB) Viewed 751 times

Note where the 1st/22nd & 3rd/22nd are off to the side, at hexes 38,57 & 39,57.

With OBJECTIVES[13] taken, all four companies (and commanders) move forward.

OBJECTIVES[5] (yellow circle) falls on Turn 19 without a fight. Note where an enemy sniper unit is harrassing the VNA along the way.

CSVN_AAR_AI_AI_RungSat180.jpg
CSVN_AAR_AI_AI_RungSat180.jpg (1.59 MiB) Viewed 751 times

Note also: There is no SAI code instructing the VNA to fire at the sniper(s). Credit the EAI for doing that.

At Turn 21, the VNA cries "enough!", assault the sniper(s), and capture him (them):

CSVN_AAR_AI_AI_RungSat181.jpg
CSVN_AAR_AI_AI_RungSat181.jpg (1.6 MiB) Viewed 751 times

Again, credit the EAI for taking that initiative.

Five turns later, at Turn 26, we have:

CSVN_AAR_AI_AI_RungSat182.jpg
CSVN_AAR_AI_AI_RungSat182.jpg (1.59 MiB) Viewed 751 times

Two platoons of the 1st/22nd are blocked by a BX Army platoon en route to OBJECTIVES[11].

The remainder of the 1st/22nd together with the 3rd/22nd? They appear to be stuck, not crossing the ford over to hex 45,51.

A look at the engine.log shows:



2022-11-13 12:22:39 vnengine.exe: [DEBUG ID 4000] (control.cpp, line 1644, Control::MakeGoal()) in Control::MakeGoal(), setting goal, assigning order, turn 26, side 0, unit ARVN Infantry Platoon 55 B, hex 45,52, trackid 286, strackid 284, xai 48, yai 53, hexai 48,53, aidir -1, airadius 0, aiactprob 100, aiorder 9



For _2ND_PLT_286, one of the units in that stack, its latest aiorder is 9 (see here: https://www.matrixgames.com/forums/view ... 3#p5014433), and its current hexai is 48,53 -- that is, move_norush() to hex 48,53. Evidently this way point attack order is not working as expected:


Code: Select all

                attack_way_point(units, {OBJECTIVES[3], "45,51", "48,53", "51,54", OBJECTIVES[11]}, NODIR, 0, 100, ATTACK_STRONG)


I suspect the fix for this is to add an additional way point, "46,51", in the middle of that way point sequence:


Code: Select all

               attack_way_point(units, {OBJECTIVES[3], "45,51", "46,51", "48,53", "51,54", OBJECTIVES[11]}, NODIR, 0, 100, ATTACK_STRONG)


Or some other remedy might be required. We shall see in a future auto-test. Darned if it ain't hard, scripting way point movements through the swamps!

Meanwhile, at OBJECTIVES[5], see where the 2nd/22nd and Weapons Coy are chilling at that place. Because after taking OBJECTIVES[5], they are not assigned to do anything else. Get your butts in gear, guys! Another thing to remedy.
Campaign Series Legion https://cslegion.com/
Campaign Series Lead Coder https://www.matrixgames.com/forums/view ... hp?f=10167
Panzer Campaigns, Panzer Battles Lead Coder https://wargameds.com
User avatar
berto
Posts: 21461
Joined: Wed Mar 13, 2002 1:15 am
Location: metro Chicago, Illinois, USA
Contact:

Re: Forest of Assassins - Battle of Rung Sat - 9/21/55 - AAR (AI vs. AI)

Post by berto »

Subsequent auto-testing showed that two additional way points were needed:


Code: Select all

                attack_way_point(units, {OBJECTIVES[3], "45,51", "46,51", "46,52", "48,53", "51,54", OBJECTIVES[11]}, NODIR, 0, 100, ATTACK_STRONG)


CSVN_AAR_AI_AI_RungSat183.jpg
CSVN_AAR_AI_AI_RungSat183.jpg (605.3 KiB) Viewed 703 times


For otherwise, the units remained stuck at or around hex 46,51. Why? <shrug> There is no understanding pathfinding failures sometimes. Sometimes, the only thing you can do is to add more way points, or reconfigure your way points. Admittedly, the game's pathfinding is imperfect. No sense fretting about it. It is what it is. At least you have ample CSEE tools (functions etc.) to fix almost any situation.

Here is the latest orders code for the 22nd/154th Infantry Battalion:


Code: Select all

    --------------------------------------------------------------------------
    -- _22ND_154TH_INF_BTN_55_B_270 -- 22nd/154th Infantry Battalion 55 - B --
    --------------------------------------------------------------------------

    -- _HQ_271 -- ARVN Battalion HQ (foot)
    do local units = _HQ_271
        defend_normal(units) -- defend in place
    end

    -- _22ND_154TH_464 -- ARVN Commander 1
    do local units = _22ND_154TH_464
        -- lead attack on OBJECTIVES[11] or OBJECTIVES[5]; see below
    end

    -- _1ST_22ND_INF_COY_55_B_272 -- 1st/22nd Infantry Company 55 - B
    -- _3RD_22ND_INF_COY_55_B_284 -- 3rd/22nd Infantry Company 55 - B
    do local units = join({_1ST_22ND_INF_COY_55_B_272, _3RD_22ND_INF_COY_55_B_284})
        _1ST_22ND_3RD_22ND_OBJECTIVE = OBJECTIVES[11]  -- _1ST_22ND_3RD_22ND_OBJECTIVE or random_pick({OBJECTIVES[11], OBJECTIVES[11], OBJECTIVES[5]})
        if objective_owner(OBJECTIVES[3]) == BX_SIDE then
            move_way_point(units, {"32,53", "36,54", "39,57"})
        else
            if _1ST_22ND_3RD_22ND_OBJECTIVE == OBJECTIVES[11] then
                attack_way_point(units, {OBJECTIVES[3], "45,51", "46,51", "46,52", "48,53", "51,54", OBJECTIVES[11]}, NODIR, 0, 100, ATTACK_STRONG)
            elseif _1ST_22ND_3RD_22ND_OBJECTIVE == OBJECTIVES[5] then
                attack_way_point(units, {OBJECTIVES[3], "43,49", OBJECTIVES[5]}, NODIR, 0, 100, ATTACK_STRONG)
            end
        end
        accompany(_22ND_154TH_464, units)
        garrison(_MMG_48_288, "32,49") -- keep behind _3RD_22ND_INF_COY_55_B_284 _MMG_48_288 to garrison MP at hex 32,49
    end

    -- _2ND_22ND_INF_COY_55_B_278 -- 2nd/22nd Infantry Company 55 - B
    -- _22NDWEAPONS_COY_55_296 -- 22ndWeapons Company 55
    do local units = difference(join({_2ND_22ND_INF_COY_55_B_278, _22NDWEAPONS_COY_55_296}), _2ND_22ND_467)
        _VNA_OBJECTIVES3_GARRISON = _VNA_OBJECTIVES3_GARRISON or garrison(units, OBJECTIVES[3])
        _VNA_OBJECTIVES5_GARRISON = _VNA_OBJECTIVES5_GARRISON or garrison(difference(units, _VNA_OBJECTIVES3_GARRISON), OBJECTIVES[5])
        units = difference(units, _GARRISONS)
        if objective_owner(OBJECTIVES[3]) == BX_SIDE then
            attack_way_point(units, {"35,50", "39,56", OBJECTIVES[3]}, NODIR, 0, 100, ATTACK_STRONG)
        elseif objective_owner(OBJECTIVES[5]) == BX_SIDE then
            attack_way_point(units, {OBJECTIVES[3], "43,49", OBJECTIVES[5]}, NODIR, 0, 100, ATTACK_STRONG)
        else
            attack_scatter(units, OBJECTIVES[5], NODIR, 4, 100, true)
        end
    end
    -- _2ND_22ND_467
    accompany(_2ND_22ND_467, counters_active(difference(_2ND_22ND_INF_COY_55_B_278, _GARRISONS)))
    garrison(_2ND_22ND_467, OBJECTIVES[5])
    -- _81MM_MORTAR_300 -- M1 81mm Mortars
    fire_indirect_nearest_from(_81MM_MORTAR_300, "37,53")


Several special things to note...

In user.lua, I have modified the garrison() function as follows:


Code: Select all

function garrison (trackids, hc)

    ...

    _GARRISONS = _GARRISONS or {}
    if garrison then
        _GARRISONS = join({_GARRISONS, garrison}, true)
    end

    ...

end


Every time a unit is successfully assigned garrison duty, its trackid is added to the (global) _GARRISONS list.

We can do this


Code: Select all

    -- _2ND_22ND_INF_COY_55_B_278 -- 2nd/22nd Infantry Company 55 - B
    -- _22NDWEAPONS_COY_55_296 -- 22ndWeapons Company 55
    do local units = difference(join({_2ND_22ND_INF_COY_55_B_278, _22NDWEAPONS_COY_55_296}), _2ND_22ND_467)
        _VNA_OBJECTIVES3_GARRISON = _VNA_OBJECTIVES3_GARRISON or garrison(units, OBJECTIVES[3])
        _VNA_OBJECTIVES5_GARRISON = _VNA_OBJECTIVES5_GARRISON or garrison(difference(units, _VNA_OBJECTIVES3_GARRISON), OBJECTIVES[5])
        units = difference(units, _GARRISONS)
        if objective_owner(OBJECTIVES[3]) == BX_SIDE then
            attack_way_point(units, {"35,50", "39,56", OBJECTIVES[3]}, NODIR, 0, 100, ATTACK_STRONG)
        elseif objective_owner(OBJECTIVES[5]) == BX_SIDE then
            attack_way_point(units, {OBJECTIVES[3], "43,49", OBJECTIVES[5]}, NODIR, 0, 100, ATTACK_STRONG)
        else
            attack_scatter(units, OBJECTIVES[5], NODIR, 4, 100, true)
        end
    end
    -- _2ND_22ND_467
    accompany(_2ND_22ND_467, counters_active(difference(_2ND_22ND_INF_COY_55_B_278, _GARRISONS)))


where we remove any garrisons from units (redefine the units value) via


Code: Select all

        units = difference(units, _GARRISONS)


thereby ensuring that any subsequent orders code does not apply to those garrisons. (Once garrisoned, we don't want a unit going off to attack etc.)

Note that in


Code: Select all

    -- _2ND_22ND_467
    accompany(_2ND_22ND_467, counters_active(difference(_2ND_22ND_INF_COY_55_B_278, _GARRISONS)))


we exclude any garrison units from the list of units that the _2ND_22ND_467 commander is to accompany.

What about the 2nd/22nd and Weapons Coy sitting idle after taking OBJECTIVES[5]? After taking that Objective, we have


Code: Select all

        else
            attack_scatter(units, OBJECTIVES[5], NODIR, 4, 100, true)


In user.lua:


Code: Select all

-- attack_scatter() -- scatter the given units, having them attack the nearest enemy, if any, at their new locations

function attack_scatter (trackids, hc, dir, extent, actprob, off_center, attype)

    [see user.lua for details

end


With such torturous waterway barriers, don't expect those units to scatter or venture off very far. But it's better than having them idling, better than having them doing nothing.
Campaign Series Legion https://cslegion.com/
Campaign Series Lead Coder https://www.matrixgames.com/forums/view ... hp?f=10167
Panzer Campaigns, Panzer Battles Lead Coder https://wargameds.com
User avatar
berto
Posts: 21461
Joined: Wed Mar 13, 2002 1:15 am
Location: metro Chicago, Illinois, USA
Contact:

Re: Forest of Assassins - Battle of Rung Sat - 9/21/55 - AAR (AI vs. AI)

Post by berto »

In the subsequent auto-test, OBJECTIVES[3] again falls by Turn 13:

CSVN_AAR_AI_AI_RungSat184.jpg
CSVN_AAR_AI_AI_RungSat184.jpg (1.21 MiB) Viewed 702 times

OBJECTIVES[5] is captured on Turn 19, again no contest:

CSVN_AAR_AI_AI_RungSat185.jpg
CSVN_AAR_AI_AI_RungSat185.jpg (1.09 MiB) Viewed 702 times

On the following turn, the EAI initiates an assault at hex 44,51. Scratch one enemy sniper!

CSVN_AAR_AI_AI_RungSat186.jpg
CSVN_AAR_AI_AI_RungSat186.jpg (429.9 KiB) Viewed 702 times
Campaign Series Legion https://cslegion.com/
Campaign Series Lead Coder https://www.matrixgames.com/forums/view ... hp?f=10167
Panzer Campaigns, Panzer Battles Lead Coder https://wargameds.com
User avatar
berto
Posts: 21461
Joined: Wed Mar 13, 2002 1:15 am
Location: metro Chicago, Illinois, USA
Contact:

Re: Forest of Assassins - Battle of Rung Sat - 9/21/55 - AAR (AI vs. AI)

Post by berto »

The 1st/22nd & 3rd/22nd companies successfully way point move towards OBJECTIVES[11], when at Turn 24 enemy resistance is encountered:

CSVN_AAR_AI_AI_RungSat187.jpg
CSVN_AAR_AI_AI_RungSat187.jpg (451.01 KiB) Viewed 788 times

Many turns, many assaults follow, all to little apparent effect:

CSVN_AAR_AI_AI_RungSat188.jpg
CSVN_AAR_AI_AI_RungSat188.jpg (455.87 KiB) Viewed 788 times

Then on Turn 28, somewhat of a surprise:

CSVN_AAR_AI_AI_RungSat189.jpg
CSVN_AAR_AI_AI_RungSat189.jpg (469.09 KiB) Viewed 788 times

The 1st/22nd & 3rd/22nd advance. More enemy sighted! This is getting to be serious.

CSVN_AAR_AI_AI_RungSat190.jpg
CSVN_AAR_AI_AI_RungSat190.jpg (450.73 KiB) Viewed 788 times

The defending enemy infantry are no match for our massed forces:

CSVN_AAR_AI_AI_RungSat191.jpg
CSVN_AAR_AI_AI_RungSat191.jpg (543.77 KiB) Viewed 788 times

The enemy mortars are captured too!

CSVN_AAR_AI_AI_RungSat192.jpg
CSVN_AAR_AI_AI_RungSat192.jpg (581.96 KiB) Viewed 788 times
Campaign Series Legion https://cslegion.com/
Campaign Series Lead Coder https://www.matrixgames.com/forums/view ... hp?f=10167
Panzer Campaigns, Panzer Battles Lead Coder https://wargameds.com
Post Reply

Return to “After Action Report”