# AI Development Discussion and Feedback

• @zlefin If you are seeing errors in the latest pre-release then please let me know as we try to keep it stable. I'd rather try to fix any errors you see then revert. But there hasn't been very many AI changes recently so the regular stable should be fine (7621) if you want to test things out.

Yeah, the canHold is used to indicate whether the AI thinks it can hold or would be worth holding a territory it can attack. It uses this to determine whether to move minimal troops and prefer using air if canHold=false and move max attackers in to maximize its TUV trade if canHold=true.

• @redrum
was responded to before I finished edit(s), so discussion chain gets confused; just skip past this.
edit - rewriting for clarity, one moment;

• @zlefin Ok, I'll take a look. In that case, please try this pre-release as I don't see any NPE when starting BW2 BoP: 1.9.0.0.9687

• I'm still gettin ga null pointer exception when starting that map with russia set to hard ai in version .9687; maybe the map xmls got corrupted or something; I forget what the issue was that affected the 270bc maps; but something similar here might've caused a problem.

I tried using triplea's remove map to remove Big world 2 then reinstall it; still gettin the nullpointerexception; where should I post the error log from the console? it looks really long; like it's stuck in a loop; I wonder why it's affecting my installation but not yours. bleh.

did a little more checking - i'm gettin the same error (or at least same name for the error) on a lot of different maps; and in both the .9687 and the .9713; I think something musta gotten screwed up with my overall triplea installations.

• @zlefin I'd recommend clearing your map directory and redownload maps. You can just post the error here for now.

• @zlefin hey! Cool! I suggested literally years ago that when the AI is officially done that maybe we can make a thread for an "AI tweak challenge" where someone tweaks the AI and challenges us to beat the AI twice (once as Axis and once as Allies etc.) and then we can see who submits the hardest most unbeatable AI!

Ya, I was testing the current AI as it went from easy to currently very tough but the AI has now been at its current state for literally 2 years now so I haven't hadto test it and I have been waiting for "tactical AI" updates until then but I think I'm basically waiting for the official final release to test.

Great posts though and I hope you submit tweaked AI's (I only play the WWII Classic map though) to battle and test to see if they are actually better than the current AI ... just an interesting idea and could lead to years and years of tough, challenging battles to post about in some thread eventually!

• @redrum
ok; I dug a little more: i'm still getting the error when I use the .9687 installation I have in a separate folder. If I use 7621, the most recent stable, I don't get the error.

her'es the error (very long indeed):

TripleA engine version 1.9.0.0.9687
Warning: serialization de-serialization error, m_name in DefaultNamed.java is null.
Warning: serialization de-serialization error, m_name in DefaultNamed.java is null.
Warning: serialization de-serialization error, m_name in DefaultNamed.java is null.
Warning: serialization de-serialization error, m_name in DefaultNamed.java is null.
Warning: serialization de-serialization error, m_name in DefaultNamed.java is null.
Warning: serialization de-serialization error, m_name in DefaultNamed.java is null.
Warning: serialization de-serialization error, m_name in DefaultNamed.java is null.
Warning: serialization de-serialization error, m_name in DefaultNamed.java is null.
Warning: serialization de-serialization error, m_name in DefaultNamed.java is null.
Warning: serialization de-serialization error, m_name in DefaultNamed.java is null.
Warning: serialization de-serialization error, m_name in DefaultNamed.java is null.
Warning: serialization de-serialization error, m_name in DefaultNamed.java is null.
Warning: serialization de-serialization error, m_name in DefaultNamed.java is null.
Warning: serialization de-serialization error, m_name in DefaultNamed.java is null.
Warning: serialization de-serialization error, m_name in DefaultNamed.java is null.
Warning: serialization de-serialization error, m_name in DefaultNamed.java is null.
Warning: serialization de-serialization error, m_name in DefaultNamed.java is null.
Warning: serialization de-serialization error, m_name in DefaultNamed.java is null.
Warning: serialization de-serialization error, m_name in DefaultNamed.java is null.
Warning: serialization de-serialization error, m_name in DefaultNamed.java is null.
Error: java.lang.NullPointerException
java.lang.NullPointerException
at games.strategy.engine.data.DefaultNamed.equals(DefaultNamed.java:33)
at java.base/java.util.HashMap.putVal(Unknown Source)
at java.base/jdk.internal.reflect.GeneratedMethodAccessor21.invoke(Unknown Source)
at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
at java.base/java.lang.reflect.Method.invoke(Unknown Source)
at java.base/jdk.internal.reflect.GeneratedMethodAccessor20.invoke(Unknown Source)
at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
at java.base/java.lang.reflect.Method.invoke(Unknown Source)
at java.base/jdk.internal.reflect.GeneratedMethodAccessor21.invoke(Unknown Source)
at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
at java.base/java.lang.reflect.Method.invoke(Unknown Source)
at java.base/jdk.internal.reflect.GeneratedMethodAccessor20.invoke(Unknown Source)
at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
at java.base/java.lang.reflect.Method.invoke(Unknown Source)
at java.base/jdk.internal.reflect.GeneratedMethodAccessor21.invoke(Unknown Source)
at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
at java.base/java.lang.reflect.Method.invoke(Unknown Source)
at java.base/jdk.internal.reflect.GeneratedMethodAccessor20.invoke(Unknown Source)
at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
at java.base/java.lang.reflect.Method.invoke(Unknown Source)
at java.base/jdk.internal.reflect.GeneratedMethodAccessor21.invoke(Unknown Source)
at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
at java.base/java.lang.reflect.Method.invoke(Unknown Source)
at java.base/jdk.internal.reflect.GeneratedMethodAccessor20.invoke(Unknown Source)
at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
at java.base/java.lang.reflect.Method.invoke(Unknown Source)
at java.base/jdk.internal.reflect.GeneratedMethodAccessor21.invoke(Unknown Source)
at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
at java.base/java.lang.reflect.Method.invoke(Unknown Source)
at java.base/jdk.internal.reflect.GeneratedMethodAccessor20.invoke(Unknown Source)
at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
at java.base/java.lang.reflect.Method.invoke(Unknown Source)
at java.base/jdk.internal.reflect.GeneratedMethodAccessor21.invoke(Unknown Source)
at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
at java.base/java.lang.reflect.Method.invoke(Unknown Source)
at java.base/jdk.internal.reflect.GeneratedMethodAccessor21.invoke(Unknown Source)
at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
at java.base/java.lang.reflect.Method.invoke(Unknown Source)
at java.base/jdk.internal.reflect.GeneratedMethodAccessor20.invoke(Unknown Source)
at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
at java.base/java.lang.reflect.Method.invoke(Unknown Source)
at java.base/jdk.internal.reflect.GeneratedMethodAccessor21.invoke(Unknown Source)
at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
at java.base/java.lang.reflect.Method.invoke(Unknown Source)
at java.base/jdk.internal.reflect.GeneratedMethodAccessor20.invoke(Unknown Source)
at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
at java.base/java.lang.reflect.Method.invoke(Unknown Source)
at java.base/jdk.internal.reflect.GeneratedMethodAccessor21.invoke(Unknown Source)
at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
at java.base/java.lang.reflect.Method.invoke(Unknown Source)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(Unknown Source)
at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
at java.base/java.lang.reflect.Method.invoke(Unknown Source)
at java.base/jdk.internal.reflect.GeneratedMethodAccessor20.invoke(Unknown Source)
at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
at java.base/java.lang.reflect.Method.invoke(Unknown Source)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(Unknown Source)
at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
at java.base/java.lang.reflect.Method.invoke(Unknown Source)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(Unknown Source)
at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
at java.base/java.lang.reflect.Method.invoke(Unknown Source)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(Unknown Source)
at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
at java.base/java.lang.reflect.Method.invoke(Unknown Source)
at games.strategy.engine.framework.GameDataUtils.cloneGameData(GameDataUtils.java:29)
at games.strategy.engine.framework.GameDataUtils.cloneGameData(GameDataUtils.java:19)
at games.strategy.triplea.ui.TripleAFrame.showHistory(TripleAFrame.java:1657)
at games.strategy.ui.SwingAction.lambda$invokeAndWait$0(SwingAction.java:86)
at games.strategy.ui.SwingAction.lambda$invokeAndWaitResult$1(SwingAction.java:114)
at java.desktop/java.awt.event.InvocationEvent.dispatch(Unknown Source)
at java.desktop/java.awt.EventQueue.dispatchEventImpl(Unknown Source)
at java.desktop/java.awt.EventQueue.access$500(Unknown Source) at java.desktop/java.awt.EventQueue$3.run(Unknown Source)
at java.desktop/java.awt.EventQueue$3.run(Unknown Source) at java.base/java.security.AccessController.doPrivileged(Native Method) at java.base/java.security.ProtectionDomain$JavaSecurityAccessImpl.doIntersectionPrivilege(Unknown Source)
at java.desktop/java.awt.EventQueue.dispatchEvent(Unknown Source)

• I'm gonna just test with 7621 for awhile; and see how the ai plays here. I think the .8304 (or whatever it was I previously had had) version had some weird bugs in it anyways; in particular in it I think the enemytuvswing for the check the enemy counterattack to see if it can hold captured territories was generating some very erroneous values (like 2E9; which is obviously absurd), which caused the ai to do some dumb things. but that doesn't seem to be occurring in 7621, and it was consistently doing so in that other version for some of the opening moves. right now I don' tfeel like trying to dig it out again and see if the behavior consistently recurs in that version; especially sinc eit may well relate to since-fixed bugs, and i've had too much drama today.

• @zlefin That's fine. Looks like the error occurs when you are trying to load a save game. Do you know what version you created that save game with and can you upload the save game here so I can try to reproduce it?

It appears either the save game data is messed up or something has changed in the engine causing it to not be able to load the old save game.

• @captain-crunch Yah, if an AI thing for tuning the algorithm values per game (not per map) would be eventually made, I think there should be a way to determine what gets accepted, in case anybody wants to submit one for any not actively owned maps (of course, maps with an active owner, the owner decides).
Maybe running AI vs AI somewhat officially monitored battles, in case, like, several people offer an AI configuration for WW2 Classic or whatever (you also have to consider that proposals might be worse than default, so some reasonably quick way to test would be in order, unless restricting the feature to actively owned maps only).

• @redrum
but that error didn' toccur when I was trying to load a save game; it was starting a new game.
I opened that copy of triplea (which is on a separate installation as to not interfere), did select map for another map to make sure it clears it. did select map again to select bigworld2 BOP, set Russia to Hard AI; and click play to start the game. then it generates that error within a second or so. and it still consistently does that if I repeat the process using the 9687 installation.

maybe it's a side effect of it being a different installation?

• were there any known bugs in the ai's calculations in 7621?

• @zlefin Not that I can think of. If there were any they were very minor.

I'm guessing your error on the pre-release has nothing to do with the AI though. You can probably start the game up with all human and see the same error.

• @redrum
if I start with all human I don' tget any errors; and can go through russia's first turn without any issues. so whatever it is, it's affected by me setting russia to ai.

• @zlefin Try doing "Show History". I think that is what is triggering the error.

• @redrum
yep; that did it. doing show history even in an all human game caused the nullpointerexception.

back to dealing with the ai stuff! so when it's at: "Check if we should try to hold attack territories"
where does it derive the "enemyattackers" value from? what assumptions does it make when it does that derivation?
oh and I note there's two different times it does that check; one early on, and one somewhat later on with what looks like a smaller list of targets, which looks like a list culled down to the best targets.

• @zlefin Weird. I think you have some kind of messed up install. I'd recommend wiping all your TripleA installs and map directories then reinstalling at some point.

For enemyAttackers, it tries to calculate how many units each of its enemies could potentially attack the given territory with and then selects the group of enemy units that it believes has the most "power" which it then considers the the max enemy attackers that it could face in a counter attack. It tends to be extra conservative around this if there are potential can openers.

• @redrum
some of the numbers i've seen for the enemyattackers value look like it's underestimating the size of the counterattack. in particular it looks like it's not counting counterattackers who would come from another territory it's considering attacking.
I've a save I could put up to better show the point; or I could just copy part of the logs and explain the situation, whihc would be best?

• @zlefin Correct, it tries to ignore enemy counter attackers from territories that it is planning to attack since it assumes those units will die. My guess is there are some cases that it must decide not to attack one of those territories and isn't taking the additional enemy counterattack units into account. Save games are definitely better especially right before it makes the moves and if it makes those moves almost everytime.

• @zlefin Nice to see another contributor.... thanks for jumping in @zlefin.

37571
1788
2105
Who's Online
Visitors Today