Merge lp:~widelands-dev/widelands/ai-post-b19-2 into lp:widelands

Proposed by GunChleoc
Status: Merged
Merged at revision: 8397
Proposed branch: lp:~widelands-dev/widelands/ai-post-b19-2
Merge into: lp:widelands
Prerequisite: lp:~widelands-dev/widelands/ai_trainingsites_proportion
Diff against target: 9667 lines (+5075/-1677)
65 files modified
data/tribes/atlanteans.lua (+5/-0)
data/tribes/barbarians.lua (+5/-0)
data/tribes/buildings/productionsites/atlanteans/bakery/init.lua (+1/-1)
data/tribes/buildings/productionsites/atlanteans/barracks/init.lua (+0/-1)
data/tribes/buildings/productionsites/atlanteans/blackroot_farm/init.lua (+0/-1)
data/tribes/buildings/productionsites/atlanteans/crystalmine/init.lua (+1/-0)
data/tribes/buildings/productionsites/atlanteans/farm/init.lua (+1/-1)
data/tribes/buildings/productionsites/atlanteans/fishers_house/init.lua (+1/-0)
data/tribes/buildings/productionsites/atlanteans/mill/init.lua (+1/-0)
data/tribes/buildings/productionsites/atlanteans/sawmill/init.lua (+1/-1)
data/tribes/buildings/productionsites/atlanteans/smokery/init.lua (+1/-1)
data/tribes/buildings/productionsites/atlanteans/spiderfarm/init.lua (+1/-1)
data/tribes/buildings/productionsites/atlanteans/toolsmithy/init.lua (+0/-1)
data/tribes/buildings/productionsites/atlanteans/weaving_mill/init.lua (+2/-2)
data/tribes/buildings/productionsites/barbarians/barracks/init.lua (+1/-1)
data/tribes/buildings/productionsites/barbarians/farm/init.lua (+1/-2)
data/tribes/buildings/productionsites/barbarians/gamekeepers_hut/init.lua (+2/-1)
data/tribes/buildings/productionsites/barbarians/hunters_hut/init.lua (+2/-1)
data/tribes/buildings/productionsites/barbarians/lime_kiln/init.lua (+2/-2)
data/tribes/buildings/productionsites/barbarians/lumberjacks_hut/init.lua (+1/-2)
data/tribes/buildings/productionsites/barbarians/metal_workshop/init.lua (+1/-1)
data/tribes/buildings/productionsites/barbarians/micro_brewery/init.lua (+0/-1)
data/tribes/buildings/productionsites/barbarians/rangers_hut/init.lua (+1/-1)
data/tribes/buildings/productionsites/barbarians/reed_yard/init.lua (+1/-1)
data/tribes/buildings/productionsites/barbarians/smelting_works/init.lua (+1/-0)
data/tribes/buildings/productionsites/barbarians/tavern/init.lua (+1/-1)
data/tribes/buildings/productionsites/barbarians/well/init.lua (+1/-2)
data/tribes/buildings/productionsites/barbarians/wood_hardener/init.lua (+1/-1)
data/tribes/buildings/productionsites/empire/armorsmithy/init.lua (+0/-1)
data/tribes/buildings/productionsites/empire/bakery/init.lua (+1/-1)
data/tribes/buildings/productionsites/empire/barracks/init.lua (+0/-1)
data/tribes/buildings/productionsites/empire/brewery/init.lua (+0/-1)
data/tribes/buildings/productionsites/empire/farm/init.lua (+2/-2)
data/tribes/buildings/productionsites/empire/inn/init.lua (+0/-1)
data/tribes/buildings/productionsites/empire/marblemine/init.lua (+2/-1)
data/tribes/buildings/productionsites/empire/piggery/init.lua (+0/-1)
data/tribes/buildings/productionsites/empire/sawmill/init.lua (+1/-1)
data/tribes/buildings/productionsites/empire/sheepfarm/init.lua (+1/-1)
data/tribes/buildings/productionsites/empire/stonemasons_house/init.lua (+1/-1)
data/tribes/buildings/productionsites/empire/tavern/init.lua (+1/-1)
data/tribes/buildings/productionsites/empire/toolsmithy/init.lua (+0/-1)
data/tribes/buildings/productionsites/empire/vineyard/init.lua (+1/-1)
data/tribes/buildings/productionsites/empire/weaponsmithy/init.lua (+2/-1)
data/tribes/buildings/productionsites/empire/winery/init.lua (+2/-2)
data/tribes/buildings/trainingsites/atlanteans/dungeon/init.lua (+0/-1)
data/tribes/buildings/trainingsites/atlanteans/labyrinth/init.lua (+0/-1)
data/tribes/buildings/trainingsites/barbarians/battlearena/init.lua (+0/-1)
data/tribes/buildings/trainingsites/barbarians/trainingcamp/init.lua (+0/-1)
data/tribes/buildings/trainingsites/empire/arena/init.lua (+0/-1)
data/tribes/buildings/trainingsites/empire/colosseum/init.lua (+0/-1)
data/tribes/buildings/trainingsites/empire/trainingcamp/init.lua (+0/-1)
data/tribes/empire.lua (+5/-0)
src/ai/ai_help_structs.cc (+1107/-42)
src/ai/ai_help_structs.h (+291/-48)
src/ai/ai_hints.cc (+2/-10)
src/ai/ai_hints.h (+6/-8)
src/ai/defaultai.cc (+2515/-1067)
src/ai/defaultai.h (+75/-39)
src/ai/defaultai_seafaring.cc (+6/-6)
src/ai/defaultai_warfare.cc (+821/-366)
src/game_io/game_player_ai_persistent_packet.cc (+102/-23)
src/logic/map_objects/tribes/tribe_descr.cc (+38/-0)
src/logic/map_objects/tribes/tribe_descr.h (+13/-1)
src/logic/player.h (+16/-15)
src/wui/interactive_base.cc (+28/-0)
To merge this branch: bzr merge lp:~widelands-dev/widelands/ai-post-b19-2
Reviewer Review Type Date Requested Status
GunChleoc Approve
Review via email: mp+325796@code.launchpad.net

Description of the change

Same proposal as Tibor made, but with prerequisite branch set. Thanks to Launchpad for not letting me add it/hiding the option in the UI.

I would like to propose this branch for merge. The changes are really big, the genetic algorithm itself and many other changes that was done along the way.
The problem is that this is kind of one-way road. Once the genetic algorithm will be in trunk, it will be difficult to come back. Or rather it will be possible but a lot of logic will need to be re-created/tested manually.

Follow up action will be to prepare saving and loading AI data to and from separate text/lua file, so that training AI will not require changes in ai_help_structs.cc and recompilation.

We can do review/code fix in multiple steps...

To post a comment you must log in.
Revision history for this message
GunChleoc (gunchleoc) wrote :

@Tibor I recreated this to have a smaller diff - the trainingsites proportions branch needs to go in first.

https://code.launchpad.net/~widelands-dev/widelands/ai_trainingsites_proportion/+merge/324607

Revision history for this message
bunnybot (widelandsofficial) wrote :

Continuous integration builds have changed state:

Travis build 2308. State: errored. Details: https://travis-ci.org/widelands/widelands/builds/243585362.
Appveyor build 2142. State: failed. Details: https://ci.appveyor.com/project/widelands-dev/widelands/build/_widelands_dev_widelands_ai_post_b19_2-2142.

Revision history for this message
bunnybot (widelandsofficial) wrote :

Continuous integration builds have changed state:

Travis build 2330. State: failed. Details: https://travis-ci.org/widelands/widelands/builds/244936136.
Appveyor build 2158. State: failed. Details: https://ci.appveyor.com/project/widelands-dev/widelands/build/_widelands_dev_widelands_ai_post_b19_2-2158.

Revision history for this message
bunnybot (widelandsofficial) wrote :

Continuous integration builds have changed state:

Travis build 2332. State: errored. Details: https://travis-ci.org/widelands/widelands/builds/245083207.
Appveyor build 2160. State: failed. Details: https://ci.appveyor.com/project/widelands-dev/widelands/build/_widelands_dev_widelands_ai_post_b19_2-2160.

Revision history for this message
bunnybot (widelandsofficial) wrote :

Continuous integration builds have changed state:

Travis build 2335. State: errored. Details: https://travis-ci.org/widelands/widelands/builds/245269883.
Appveyor build 2163. State: success. Details: https://ci.appveyor.com/project/widelands-dev/widelands/build/_widelands_dev_widelands_ai_post_b19_2-2163.

Revision history for this message
GunChleoc (gunchleoc) wrote :

Code review done.

1. Please go over my changes with a fine-tooth comb to make sure that I haven't accidentally introduced any logic changes.

2. Was the test suite already broken, or did I break it with my changes?

3. We need to keep savegame compatibility until after Bzuild 20, so savegames will remain viable for bug fixing. I have added some code so that old savegames will load, but the games will segfault, because something still needs initializing. Since you know the code better than I, can you have a look?

4. We have a bunch of hard coded ware and building names that I'd like to get rid of. Turn anything that's too complicated to solve right now into a TODO comment, so that we can fix it in a follow-up branch.

5. I found a bunch of commented out code lines, I left them in with a NOCOM comment so that you can decide if you still want them someplace.

6. I think we should have a command line switch for the training mode, so we won't have to recompile to switch modes. Let me know if you want me to take care of it.

Note that I will be unable to contribute code for a few weeks starting from Thursday next week, so if you want me to do any more coding in this branch, please let me know ASAP.

Revision history for this message
TiborB (tiborb95) wrote :

Gun,

thanks for review!

Savegame compatibility is quite tricky. I will look at this but I believe that proper strategy is just to ignore previous AI data (from older packet) and initialize AI data from scratch.

I also dont like addressing buildings by name, and when we discuss AI changes on forum, most players gives advices specific for buildings&tribes. I am trying to avoid this as much as possible.

I can introduce bunch of new ai_hints like "is_bakery", though opposite would be better (per each tribe):
bakery:"barbarian_bakery"
woodcutter:"barbarian_lumberjack"

For now AI expects on some spaces in code that there is exactly one building of the type. But entries in "ai_hints" are OK, and AI will make sure the building is identified, and just one.

I will start with save/load stuff....

Revision history for this message
GunChleoc (gunchleoc) wrote :

> Savegame compatibility is quite tricky. I will look at this but I believe that proper strategy is just to ignore previous AI data (from older packet) and initialize AI data from scratch.

I agree - we have to run the loading to eat uo the packets, but
initializing the AI data from scratch will be the way to go.

> I also dont like addressing buildings by name, and when we discuss AI changes on forum, most players gives advices specific for buildings&tribes. I am trying to avoid this as much as possible.
>
> I can introduce bunch of new ai_hints like "is_bakery", though opposite would be better (per each tribe):
> bakery:"barbarian_bakery"
> woodcutter:"barbarian_lumberjack"

You mean like we have for the port & barracks? I could implement that
pretty easily.

Revision history for this message
TiborB (tiborb95) wrote :

>> I can introduce bunch of new ai_hints like "is_bakery", though opposite would be better (per each tribe):
>> bakery:"barbarian_bakery"
>> woodcutter:"barbarian_lumberjack"

?You mean like we have for the port & barracks? I could implement that

Do you mean through "ai_hints"? I have to fix also "is_basic" - as you suggested, so I can to it at once. I want to be sure it is properly "plugged" to default_ai.cc

Revision history for this message
GunChleoc (gunchleoc) wrote :

>>> I can introduce bunch of new ai_hints like "is_bakery", though opposite would be better (per each tribe):
>>> bakery:"barbarian_bakery"
>>> woodcutter:"barbarian_lumberjack"
>
> ?You mean like we have for the port & barracks? I could implement that
>
> Do you mean through "ai_hints"? I have to fix also "is_basic" - as you suggested, so I can to it at once. I want to be sure it is properly "plugged" to default_ai.cc

No, I thought that you meant this:

https://bazaar.launchpad.net/~widelands-dev/widelands/trunk/view/head:/data/tribes/atlanteans.lua#L353

and this:

https://bazaar.launchpad.net/~widelands-dev/widelands/trunk/view/head:/src/logic/map_objects/tribes/tribe_descr.h#L106

AI hints will certainly work though.

Revision history for this message
TiborB (tiborb95) wrote :

I did not know about this code, it seems to be exactly what is needed. I will use this. I will implement it myself, I want to make myself familiar with this stuff.

Revision history for this message
GunChleoc (gunchleoc) wrote :

Sounds good to me. Holler if you need help.

Revision history for this message
bunnybot (widelandsofficial) wrote :

Continuous integration builds have changed state:

Travis build 2339. State: failed. Details: https://travis-ci.org/widelands/widelands/builds/245680347.
Appveyor build 2167. State: success. Details: https://ci.appveyor.com/project/widelands-dev/widelands/build/_widelands_dev_widelands_ai_post_b19_2-2167.

Revision history for this message
GunChleoc (gunchleoc) wrote :

I ran the test suite on r8148 (the last revision before I started changing stuff) and it went though for the release build, but had 3 failures on the debug build.

Revision history for this message
TiborB (tiborb95) wrote :

@Gun,
I found that the game crashes on line:

if (field.coords.field->get_immovable()->descr().type() == Widelands::MapObjectType::MILITARYSITE) {

(gdb) bt
#0 0x0000000000ce6f5a in Widelands::MapObject::descr (this=0x0)
    at /var/widelands2/BZR/ai-post-b19-2/src/logic/map_objects/map_object.h:229
#1 0x000000000111c015 in DefaultAI::update_buildable_field (this=0x9d9cc60, field=...)
    at /var/widelands2/BZR/ai-post-b19-2/src/ai/defaultai.cc:1243
#2 0x000000000111bc9e in DefaultAI::update_all_not_buildable_fields (this=0x9d9cc60)
    at /var/widelands2/BZR/ai-post-b19-2/src/ai/defaultai.cc:1204

Do you know what had you changed? It worked for sure before...

Revision history for this message
TiborB (tiborb95) wrote :

> I ran the test suite on r8148 (the last revision before I started changing stuff) and it went though for the release build, but had 3 failures on the debug build.

The log says it is failed assert in AI code, there is player statistics (land, enemy size) missing - I can work this around easily, so do not bother yourself about it..

Revision history for this message
TiborB (tiborb95) wrote :

re:
if (field.coords.field->get_immovable()->descr().type() == Widelands::MapObjectType::MILITARYSITE) {
crash

it crashes also with brand new game, so it is not related to save/load

Revision history for this message
GunChleoc (gunchleoc) wrote :

That's a change I made because it's more efficient than an upcast (I recenty learned that dynamic_cast is expensive). This of course assumes that there is an immovable on the field.

So, either test if the immovable is nullptr first, or change back to upcast.

Revision history for this message
TiborB (tiborb95) wrote :

OK, makes sense. I did not know you had changed that line. I will add a test there if there is a building there.

Revision history for this message
SirVer (sirver) wrote :

drive by: I like this stack overflow for information about dynamic_cast<> cost: https://stackoverflow.com/questions/4050901/performance-of-dynamic-cast

tl;dr: dynamic_cast<> is not crazy expensive, but if you can do without, great. It also is usually bad design if you require dynamic_cast<> - but unfortunately, we have plenty of bad design in Widelands, so you have to use it sometimes, since you cannot design around our errors of the past.

Revision history for this message
GunChleoc (gunchleoc) wrote :

BTW comments like

  //Should happen only rarely so we print a warning here

will break codecheck, always use a blank space:

  // Should happen only rarely so we print a warning here

Regarding your question in the code, size_t is an unsigned type http://www.cplusplus.com/reference/cstddef/size_t/?kw=size_t

Revision history for this message
TiborB (tiborb95) wrote :

I presume that clang-format will take care of that, will not? Once all changes are done I will run clang-format and retest and let you know.

in 8163 I introduced new special wares, investigate diff for this revision if you are interested. I did not introduce the helper function, I think we can manage without it, especially now, when I shortened the code. But if you insist I can.

Revision history for this message
TiborB (tiborb95) wrote :

Gun,
I did some changes to critical materials stuff, I made some mistakes in 8163 it seems.

Also there are some notes for you, look for "@Gun" in the diff

The biggest issue that remains is that command line switch, I have to investigate this a bit

Revision history for this message
GunChleoc (gunchleoc) wrote :

I have answered the notes. I have also renamed "stones" to "granite". This was a leftover from my terminology cleanup for Build19 that was never implemented in the AI variables and functions - "stones" it the mountain map resource, "granite" is the ware now. The immovables littered around the map are "rocks".

I think you can get rid of one of the new definitions. If a building has refinedlog() listed in its outputs, it is automatically a logrefiner().

Also, why do we need this assertion?

    assert(count_buildings_with_attribute(BuildingAttribute::kIronMine) <= 3);

If somebody mods a tribe with even more mine upgrades, or many different types of iron ore producers, the assertion won't hold.

Revision history for this message
TiborB (tiborb95) wrote :

As for mines<=3 question, you are right, if somebody creates tribe with more mines he will have to modify the assertion - should not be a big deal, I even inserted a comment there. But for now I want to be 100% sure that it does what it is supposed to do..

Revision history for this message
GunChleoc (gunchleoc) wrote :

Sounds good to me.

Revision history for this message
GunChleoc (gunchleoc) wrote :

I ave been thinking about the command line parameter, we should do that in a follow-up branch and just set kAITrainingMode to false for now. This will make it easier to review.

You can also use kAITrainingMode in the interactive base for switching the game speed code on and off, this way that code can stay in and be always valid.

Revision history for this message
TiborB (tiborb95) wrote :

OK, we will leave the command line switch for the next time. I will go over the code again and let you know when it will be ready....

Revision history for this message
TiborB (tiborb95) wrote :

OK, next try please

Just 2 points
- diff here on web page is truncated
- there is still one NOCOM and response to Gun in that cut off part of the diff...

Revision history for this message
GunChleoc (gunchleoc) wrote :

I did a few small cleanups, this is ready to go now. Thanks for taking on this huge job!

@bunnybot merge

review: Approve
Revision history for this message
TiborB (tiborb95) wrote :

I am bit afraid of reaction of players, the change of behavior is really significant

Revision history for this message
GunChleoc (gunchleoc) wrote :

The forum people are generally very friendly and supportive, so try not to worry about it too much. The new AI seems to perform better than the old one already. Of course, there will be bugs or things not working as expected, but that's just how big changes work in software development. Well just have to fix them then as they come up.

I expect that this will produce a lot less new bugs and crashes than I myself have caused since Build 19, and I'm glad that somebody is doing AI stuff, because I don't know the first thing about AI development ;)

Revision history for this message
GunChleoc (gunchleoc) wrote :

We still have codecheck warnings. Travis is having problems today, so best wait until tomorrow and fix them then.

Revision history for this message
bunnybot (widelandsofficial) wrote :

Continuous integration builds have changed state:

Travis build 2392. State: errored. Details: https://travis-ci.org/widelands/widelands/builds/247861477.
Appveyor build 2220. State: success. Details: https://ci.appveyor.com/project/widelands-dev/widelands/build/_widelands_dev_widelands_ai_post_b19_2-2220.

Revision history for this message
bunnybot (widelandsofficial) wrote :

Refusing to merge, since Travis is not green. Use @bunnybot merge force for merging anyways.

Travis build 2392. State: errored. Details: https://travis-ci.org/widelands/widelands/builds/247861477.

Revision history for this message
bunnybot (widelandsofficial) wrote :

Continuous integration builds have changed state:

Travis build 2403. State: failed. Details: https://travis-ci.org/widelands/widelands/builds/248478925.
Appveyor build 2231. State: success. Details: https://ci.appveyor.com/project/widelands-dev/widelands/build/_widelands_dev_widelands_ai_post_b19_2-2231.

Revision history for this message
bunnybot (widelandsofficial) wrote :

Continuous integration builds have changed state:

Travis build 2406. State: passed. Details: https://travis-ci.org/widelands/widelands/builds/248928377.
Appveyor build 2234. State: success. Details: https://ci.appveyor.com/project/widelands-dev/widelands/build/_widelands_dev_widelands_ai_post_b19_2-2234.

Revision history for this message
TiborB (tiborb95) wrote :

CI seems to be OK now. Can it be merged?

Revision history for this message
GunChleoc (gunchleoc) wrote :

Yes, let's merge this :)

@bunnybot merge

BTW: I have all my editors set to automatically kill trailing whitespaces. This helps keeping the diffs small and avoids that particular codecheck fail.

Revision history for this message
TiborB (tiborb95) wrote :

Oh, I did not know such feature exists. My editor (geany) has it so I will enable it...

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
=== modified file 'data/tribes/atlanteans.lua'
--- data/tribes/atlanteans.lua 2017-04-30 10:30:02 +0000
+++ data/tribes/atlanteans.lua 2017-07-03 17:39:38 +0000
@@ -352,4 +352,9 @@
352 headquarters = "atlanteans_headquarters",352 headquarters = "atlanteans_headquarters",
353 port = "atlanteans_port",353 port = "atlanteans_port",
354 barracks = "atlanteans_barracks",354 barracks = "atlanteans_barracks",
355 bakery = "atlanteans_bakery",
356 ironore = "iron_ore",
357 rawlog = "log",
358 refinedlog = "planks",
359 granite = "granite",
355}360}
356361
=== modified file 'data/tribes/barbarians.lua'
--- data/tribes/barbarians.lua 2017-04-30 10:30:02 +0000
+++ data/tribes/barbarians.lua 2017-07-03 17:39:38 +0000
@@ -285,4 +285,9 @@
285 headquarters = "barbarians_headquarters",285 headquarters = "barbarians_headquarters",
286 port = "barbarians_port",286 port = "barbarians_port",
287 barracks = "barbarians_barracks",287 barracks = "barbarians_barracks",
288 bakery = "barbarians_bakery",
289 ironore = "iron_ore",
290 rawlog = "log",
291 refinedlog = "blackwood",
292 granite = "granite",
288}293}
289294
=== modified file 'data/tribes/buildings/productionsites/atlanteans/bakery/init.lua'
--- data/tribes/buildings/productionsites/atlanteans/bakery/init.lua 2017-02-10 09:40:17 +0000
+++ data/tribes/buildings/productionsites/atlanteans/bakery/init.lua 2017-07-03 17:39:38 +0000
@@ -32,7 +32,7 @@
32 },32 },
3333
34 aihints = {34 aihints = {
35 forced_after = 1200,35 basic_amount = 1,
36 prohibited_till = 90036 prohibited_till = 900
37 },37 },
3838
3939
=== modified file 'data/tribes/buildings/productionsites/atlanteans/barracks/init.lua'
--- data/tribes/buildings/productionsites/atlanteans/barracks/init.lua 2017-02-10 09:40:17 +0000
+++ data/tribes/buildings/productionsites/atlanteans/barracks/init.lua 2017-07-03 17:39:38 +0000
@@ -34,7 +34,6 @@
34 },34 },
3535
36 aihints = {36 aihints = {
37 forced_after = 1000,
38 very_weak_ai_limit = 1,37 very_weak_ai_limit = 1,
39 weak_ai_limit = 338 weak_ai_limit = 3
40 },39 },
4140
=== modified file 'data/tribes/buildings/productionsites/atlanteans/blackroot_farm/init.lua'
--- data/tribes/buildings/productionsites/atlanteans/blackroot_farm/init.lua 2015-12-11 16:54:00 +0000
+++ data/tribes/buildings/productionsites/atlanteans/blackroot_farm/init.lua 2017-07-03 17:39:38 +0000
@@ -29,7 +29,6 @@
2929
30 aihints = {30 aihints = {
31 prohibited_till = 600,31 prohibited_till = 600,
32 forced_after = 800,
33 space_consumer = true32 space_consumer = true
34 },33 },
3534
3635
=== modified file 'data/tribes/buildings/productionsites/atlanteans/crystalmine/init.lua'
--- data/tribes/buildings/productionsites/atlanteans/crystalmine/init.lua 2017-02-18 23:07:56 +0000
+++ data/tribes/buildings/productionsites/atlanteans/crystalmine/init.lua 2017-07-03 17:39:38 +0000
@@ -36,6 +36,7 @@
3636
37 aihints = {37 aihints = {
38 mines = "stones",38 mines = "stones",
39 basic_amount = 1,
39 prohibited_till = 60040 prohibited_till = 600
40 },41 },
4142
4243
=== modified file 'data/tribes/buildings/productionsites/atlanteans/farm/init.lua'
--- data/tribes/buildings/productionsites/atlanteans/farm/init.lua 2016-01-28 05:24:34 +0000
+++ data/tribes/buildings/productionsites/atlanteans/farm/init.lua 2017-07-03 17:39:38 +0000
@@ -30,9 +30,9 @@
3030
31 aihints = {31 aihints = {
32 space_consumer = true,32 space_consumer = true,
33 basic_amount = 1,
33 -- Farm needs spidercloth to be built and spidercloth needs corn for production34 -- Farm needs spidercloth to be built and spidercloth needs corn for production
34 -- -> farm should be built ASAP!35 -- -> farm should be built ASAP!
35 forced_after = 400,
36 prohibited_till = 20036 prohibited_till = 200
37 },37 },
3838
3939
=== modified file 'data/tribes/buildings/productionsites/atlanteans/fishers_house/init.lua'
--- data/tribes/buildings/productionsites/atlanteans/fishers_house/init.lua 2015-12-11 16:54:00 +0000
+++ data/tribes/buildings/productionsites/atlanteans/fishers_house/init.lua 2017-07-03 17:39:38 +0000
@@ -26,6 +26,7 @@
2626
27 aihints = {27 aihints = {
28 needs_water = true,28 needs_water = true,
29 basic_amount = 1,
29 prohibited_till = 60030 prohibited_till = 600
30 },31 },
3132
3233
=== modified file 'data/tribes/buildings/productionsites/atlanteans/mill/init.lua'
--- data/tribes/buildings/productionsites/atlanteans/mill/init.lua 2016-10-30 19:15:45 +0000
+++ data/tribes/buildings/productionsites/atlanteans/mill/init.lua 2017-07-03 17:39:38 +0000
@@ -33,6 +33,7 @@
33 },33 },
3434
35 aihints = {35 aihints = {
36 basic_amount = 1,
36 prohibited_till = 60037 prohibited_till = 600
37 },38 },
3839
3940
=== modified file 'data/tribes/buildings/productionsites/atlanteans/sawmill/init.lua'
--- data/tribes/buildings/productionsites/atlanteans/sawmill/init.lua 2016-12-11 09:29:28 +0000
+++ data/tribes/buildings/productionsites/atlanteans/sawmill/init.lua 2017-07-03 17:39:38 +0000
@@ -31,7 +31,7 @@
31 },31 },
3232
33 aihints = {33 aihints = {
34 forced_after = 250,34 basic_amount = 2,
35 prohibited_till = 250,35 prohibited_till = 250,
36 very_weak_ai_limit = 1,36 very_weak_ai_limit = 1,
37 weak_ai_limit = 237 weak_ai_limit = 2
3838
=== modified file 'data/tribes/buildings/productionsites/atlanteans/smokery/init.lua'
--- data/tribes/buildings/productionsites/atlanteans/smokery/init.lua 2016-10-26 19:21:32 +0000
+++ data/tribes/buildings/productionsites/atlanteans/smokery/init.lua 2017-07-03 17:39:38 +0000
@@ -32,7 +32,7 @@
32 },32 },
3333
34 aihints = {34 aihints = {
35 forced_after = 800,35 basic_amount = 1,
36 prohibited_till = 180,36 prohibited_till = 180,
37 very_weak_ai_limit = 1,37 very_weak_ai_limit = 1,
38 weak_ai_limit = 238 weak_ai_limit = 2
3939
=== modified file 'data/tribes/buildings/productionsites/atlanteans/spiderfarm/init.lua'
--- data/tribes/buildings/productionsites/atlanteans/spiderfarm/init.lua 2016-09-03 14:59:10 +0000
+++ data/tribes/buildings/productionsites/atlanteans/spiderfarm/init.lua 2017-07-03 17:39:38 +0000
@@ -31,7 +31,7 @@
31 },31 },
3232
33 aihints = {33 aihints = {
34 forced_after = 450,34 basic_amount = 1,
35 prohibited_till = 35035 prohibited_till = 350
36 },36 },
3737
3838
=== modified file 'data/tribes/buildings/productionsites/atlanteans/toolsmithy/init.lua'
--- data/tribes/buildings/productionsites/atlanteans/toolsmithy/init.lua 2016-10-30 19:15:45 +0000
+++ data/tribes/buildings/productionsites/atlanteans/toolsmithy/init.lua 2017-07-03 17:39:38 +0000
@@ -32,7 +32,6 @@
32 },32 },
3333
34 aihints = {34 aihints = {
35 forced_after = 500,
36 prohibited_till = 45035 prohibited_till = 450
37 },36 },
3837
3938
=== modified file 'data/tribes/buildings/productionsites/atlanteans/weaving_mill/init.lua'
--- data/tribes/buildings/productionsites/atlanteans/weaving_mill/init.lua 2016-12-14 09:09:34 +0000
+++ data/tribes/buildings/productionsites/atlanteans/weaving_mill/init.lua 2017-07-03 17:39:38 +0000
@@ -32,8 +32,8 @@
32 },32 },
3333
34 aihints = {34 aihints = {
35 forced_after = 600,35 prohibited_till = 400,
36 prohibited_till = 450,36 basic_amount = 1,
37 very_weak_ai_limit = 1,37 very_weak_ai_limit = 1,
38 weak_ai_limit = 238 weak_ai_limit = 2
39 },39 },
4040
=== modified file 'data/tribes/buildings/productionsites/barbarians/barracks/init.lua'
--- data/tribes/buildings/productionsites/barbarians/barracks/init.lua 2017-02-10 09:40:17 +0000
+++ data/tribes/buildings/productionsites/barbarians/barracks/init.lua 2017-07-03 17:39:38 +0000
@@ -33,7 +33,7 @@
33 },33 },
3434
35 aihints = {35 aihints = {
36 forced_after = 1000,36 basic_amount = 1,
37 very_weak_ai_limit = 1,37 very_weak_ai_limit = 1,
38 weak_ai_limit = 338 weak_ai_limit = 3
39 },39 },
4040
=== modified file 'data/tribes/buildings/productionsites/barbarians/farm/init.lua'
--- data/tribes/buildings/productionsites/barbarians/farm/init.lua 2016-01-28 05:24:34 +0000
+++ data/tribes/buildings/productionsites/barbarians/farm/init.lua 2017-07-03 17:39:38 +0000
@@ -40,8 +40,7 @@
40 },40 },
4141
42 aihints = {42 aihints = {
43 space_consumer = true,43 space_consumer = true
44 forced_after = 600
45 },44 },
4645
47 working_positions = {46 working_positions = {
4847
=== modified file 'data/tribes/buildings/productionsites/barbarians/gamekeepers_hut/init.lua'
--- data/tribes/buildings/productionsites/barbarians/gamekeepers_hut/init.lua 2015-12-11 16:54:00 +0000
+++ data/tribes/buildings/productionsites/barbarians/gamekeepers_hut/init.lua 2017-07-03 17:39:38 +0000
@@ -35,7 +35,8 @@
3535
36 aihints = {36 aihints = {
37 renews_map_resource = "meat",37 renews_map_resource = "meat",
38 prohibited_till = 90038 prohibited_till = 900,
39 basic_amount = 1
39 },40 },
4041
41 working_positions = {42 working_positions = {
4243
=== modified file 'data/tribes/buildings/productionsites/barbarians/hunters_hut/init.lua'
--- data/tribes/buildings/productionsites/barbarians/hunters_hut/init.lua 2015-12-11 16:54:00 +0000
+++ data/tribes/buildings/productionsites/barbarians/hunters_hut/init.lua 2017-07-03 17:39:38 +0000
@@ -34,7 +34,8 @@
34 },34 },
3535
36 aihints = {36 aihints = {
37 prohibited_till = 50037 prohibited_till = 500,
38 basic_amount = 1
38 },39 },
3940
40 working_positions = {41 working_positions = {
4142
=== modified file 'data/tribes/buildings/productionsites/barbarians/lime_kiln/init.lua'
--- data/tribes/buildings/productionsites/barbarians/lime_kiln/init.lua 2016-09-03 14:59:10 +0000
+++ data/tribes/buildings/productionsites/barbarians/lime_kiln/init.lua 2017-07-03 17:39:38 +0000
@@ -31,9 +31,9 @@
31 },31 },
3232
33 aihints = {33 aihints = {
34 forced_after = 600,
35 very_weak_ai_limit = 1,34 very_weak_ai_limit = 1,
36 weak_ai_limit = 235 weak_ai_limit = 2,
36 basic_amount = 1
37 },37 },
3838
39 working_positions = {39 working_positions = {
4040
=== modified file 'data/tribes/buildings/productionsites/barbarians/lumberjacks_hut/init.lua'
--- data/tribes/buildings/productionsites/barbarians/lumberjacks_hut/init.lua 2015-12-11 16:54:00 +0000
+++ data/tribes/buildings/productionsites/barbarians/lumberjacks_hut/init.lua 2017-07-03 17:39:38 +0000
@@ -32,8 +32,7 @@
32 },32 },
3333
34 aihints = {34 aihints = {
35 forced_after = 180,35 basic_amount = 1,
36 prohibited_till = 180,
37 logproducer = true36 logproducer = true
38 },37 },
3938
4039
=== modified file 'data/tribes/buildings/productionsites/barbarians/metal_workshop/init.lua'
--- data/tribes/buildings/productionsites/barbarians/metal_workshop/init.lua 2016-09-03 14:59:10 +0000
+++ data/tribes/buildings/productionsites/barbarians/metal_workshop/init.lua 2017-07-03 17:39:38 +0000
@@ -44,7 +44,7 @@
44 },44 },
4545
46 aihints = {46 aihints = {
47 forced_after = 400,47 basic_amount = 2,
48 prohibited_till = 40048 prohibited_till = 400
49 },49 },
5050
5151
=== modified file 'data/tribes/buildings/productionsites/barbarians/micro_brewery/init.lua'
--- data/tribes/buildings/productionsites/barbarians/micro_brewery/init.lua 2016-09-03 14:59:10 +0000
+++ data/tribes/buildings/productionsites/barbarians/micro_brewery/init.lua 2017-07-03 17:39:38 +0000
@@ -34,7 +34,6 @@
34 },34 },
3535
36 aihints = {36 aihints = {
37 forced_after = 500
38 },37 },
3938
40 working_positions = {39 working_positions = {
4140
=== modified file 'data/tribes/buildings/productionsites/barbarians/rangers_hut/init.lua'
--- data/tribes/buildings/productionsites/barbarians/rangers_hut/init.lua 2015-12-11 16:54:00 +0000
+++ data/tribes/buildings/productionsites/barbarians/rangers_hut/init.lua 2017-07-03 17:39:38 +0000
@@ -34,7 +34,7 @@
34 aihints = {34 aihints = {
35 renews_map_resource = "log",35 renews_map_resource = "log",
36 space_consumer = true,36 space_consumer = true,
37 prohibited_till = 20037 basic_amount = 1
38 },38 },
3939
40 working_positions = {40 working_positions = {
4141
=== modified file 'data/tribes/buildings/productionsites/barbarians/reed_yard/init.lua'
--- data/tribes/buildings/productionsites/barbarians/reed_yard/init.lua 2015-12-11 16:54:00 +0000
+++ data/tribes/buildings/productionsites/barbarians/reed_yard/init.lua 2017-07-03 17:39:38 +0000
@@ -27,7 +27,7 @@
2727
28 aihints = {28 aihints = {
29 space_consumer = true,29 space_consumer = true,
30 forced_after = 250,30 basic_amount = 1,
31 prohibited_till = 25031 prohibited_till = 250
32 },32 },
3333
3434
=== modified file 'data/tribes/buildings/productionsites/barbarians/smelting_works/init.lua'
--- data/tribes/buildings/productionsites/barbarians/smelting_works/init.lua 2016-10-24 10:07:57 +0000
+++ data/tribes/buildings/productionsites/barbarians/smelting_works/init.lua 2017-07-03 17:39:38 +0000
@@ -35,6 +35,7 @@
3535
36 aihints = {36 aihints = {
37 prohibited_till = 400,37 prohibited_till = 400,
38 basic_amount = 1,
38 very_weak_ai_limit = 1,39 very_weak_ai_limit = 1,
39 weak_ai_limit = 240 weak_ai_limit = 2
40 },41 },
4142
=== modified file 'data/tribes/buildings/productionsites/barbarians/tavern/init.lua'
--- data/tribes/buildings/productionsites/barbarians/tavern/init.lua 2016-10-24 10:10:06 +0000
+++ data/tribes/buildings/productionsites/barbarians/tavern/init.lua 2017-07-03 17:39:38 +0000
@@ -38,7 +38,7 @@
38 },38 },
3939
40 aihints = {40 aihints = {
41 forced_after = 90041 basic_amount = 1
42 },42 },
4343
44 working_positions = {44 working_positions = {
4545
=== modified file 'data/tribes/buildings/productionsites/barbarians/well/init.lua'
--- data/tribes/buildings/productionsites/barbarians/well/init.lua 2016-10-05 05:29:11 +0000
+++ data/tribes/buildings/productionsites/barbarians/well/init.lua 2017-07-03 17:39:38 +0000
@@ -33,8 +33,7 @@
3333
34 aihints = {34 aihints = {
35 mines_water = true,35 mines_water = true,
36 prohibited_till = 800,36 basic_amount = 1
37 forced_after = 800
38 },37 },
3938
40 working_positions = {39 working_positions = {
4140
=== modified file 'data/tribes/buildings/productionsites/barbarians/wood_hardener/init.lua'
--- data/tribes/buildings/productionsites/barbarians/wood_hardener/init.lua 2016-09-03 14:59:10 +0000
+++ data/tribes/buildings/productionsites/barbarians/wood_hardener/init.lua 2017-07-03 17:39:38 +0000
@@ -38,7 +38,7 @@
38 },38 },
3939
40 aihints = {40 aihints = {
41 forced_after = 250,41 basic_amount = 1,
42 prohibited_till = 250,42 prohibited_till = 250,
43 very_weak_ai_limit = 1,43 very_weak_ai_limit = 1,
44 weak_ai_limit = 244 weak_ai_limit = 2
4545
=== modified file 'data/tribes/buildings/productionsites/empire/armorsmithy/init.lua'
--- data/tribes/buildings/productionsites/empire/armorsmithy/init.lua 2016-10-30 19:06:01 +0000
+++ data/tribes/buildings/productionsites/empire/armorsmithy/init.lua 2017-07-03 17:39:38 +0000
@@ -43,7 +43,6 @@
4343
44 aihints = {44 aihints = {
45 prohibited_till = 700,45 prohibited_till = 700,
46 forced_after = 900
47 },46 },
4847
49 working_positions = {48 working_positions = {
5049
=== modified file 'data/tribes/buildings/productionsites/empire/bakery/init.lua'
--- data/tribes/buildings/productionsites/empire/bakery/init.lua 2017-02-10 09:40:17 +0000
+++ data/tribes/buildings/productionsites/empire/bakery/init.lua 2017-07-03 17:39:38 +0000
@@ -37,7 +37,7 @@
3737
38 aihints = {38 aihints = {
39 prohibited_till = 600,39 prohibited_till = 600,
40 forced_after = 70040 basic_amount = 1
41 },41 },
4242
43 working_positions = {43 working_positions = {
4444
=== modified file 'data/tribes/buildings/productionsites/empire/barracks/init.lua'
--- data/tribes/buildings/productionsites/empire/barracks/init.lua 2017-02-10 09:40:17 +0000
+++ data/tribes/buildings/productionsites/empire/barracks/init.lua 2017-07-03 17:39:38 +0000
@@ -35,7 +35,6 @@
35 },35 },
3636
37 aihints = {37 aihints = {
38 forced_after = 1000,
39 very_weak_ai_limit = 1,38 very_weak_ai_limit = 1,
40 weak_ai_limit = 339 weak_ai_limit = 3
41 },40 },
4241
=== modified file 'data/tribes/buildings/productionsites/empire/brewery/init.lua'
--- data/tribes/buildings/productionsites/empire/brewery/init.lua 2016-09-03 14:59:10 +0000
+++ data/tribes/buildings/productionsites/empire/brewery/init.lua 2017-07-03 17:39:38 +0000
@@ -31,7 +31,6 @@
31 },31 },
3232
33 aihints = {33 aihints = {
34 forced_after = 900,
35 prohibited_till = 600,34 prohibited_till = 600,
36 very_weak_ai_limit = 1,35 very_weak_ai_limit = 1,
37 weak_ai_limit = 236 weak_ai_limit = 2
3837
=== modified file 'data/tribes/buildings/productionsites/empire/farm/init.lua'
--- data/tribes/buildings/productionsites/empire/farm/init.lua 2016-01-28 05:24:34 +0000
+++ data/tribes/buildings/productionsites/empire/farm/init.lua 2017-07-03 17:39:38 +0000
@@ -30,8 +30,8 @@
30 },30 },
3131
32 aihints = {32 aihints = {
33 space_consumer = true,33 basic_amount = 1,
34 forced_after = 90034 space_consumer = true
35 },35 },
3636
37 working_positions = {37 working_positions = {
3838
=== modified file 'data/tribes/buildings/productionsites/empire/inn/init.lua'
--- data/tribes/buildings/productionsites/empire/inn/init.lua 2016-10-26 19:21:32 +0000
+++ data/tribes/buildings/productionsites/empire/inn/init.lua 2017-07-03 17:39:38 +0000
@@ -31,7 +31,6 @@
31 },31 },
3232
33 aihints = {33 aihints = {
34 forced_after = 900,
35 prohibited_till = 60034 prohibited_till = 600
36 },35 },
3736
3837
=== modified file 'data/tribes/buildings/productionsites/empire/marblemine/init.lua'
--- data/tribes/buildings/productionsites/empire/marblemine/init.lua 2016-09-03 14:59:10 +0000
+++ data/tribes/buildings/productionsites/empire/marblemine/init.lua 2017-07-03 17:39:38 +0000
@@ -38,7 +38,8 @@
38 aihints = {38 aihints = {
39 mines = "stones",39 mines = "stones",
40 mines_percent = 50,40 mines_percent = 50,
41 prohibited_till = 45041 prohibited_till = 450,
42 basic_amount = 1
42 },43 },
4344
44 working_positions = {45 working_positions = {
4546
=== modified file 'data/tribes/buildings/productionsites/empire/piggery/init.lua'
--- data/tribes/buildings/productionsites/empire/piggery/init.lua 2016-09-03 14:59:10 +0000
+++ data/tribes/buildings/productionsites/empire/piggery/init.lua 2017-07-03 17:39:38 +0000
@@ -33,7 +33,6 @@
33 },33 },
3434
35 aihints = {35 aihints = {
36 forced_after = 1800
37 },36 },
3837
39 working_positions = {38 working_positions = {
4039
=== modified file 'data/tribes/buildings/productionsites/empire/sawmill/init.lua'
--- data/tribes/buildings/productionsites/empire/sawmill/init.lua 2016-09-03 14:59:10 +0000
+++ data/tribes/buildings/productionsites/empire/sawmill/init.lua 2017-07-03 17:39:38 +0000
@@ -31,7 +31,7 @@
31 },31 },
3232
33 aihints = {33 aihints = {
34 forced_after = 250,34 basic_amount = 2,
35 prohibited_till = 250,35 prohibited_till = 250,
36 very_weak_ai_limit = 1,36 very_weak_ai_limit = 1,
37 weak_ai_limit = 237 weak_ai_limit = 2
3838
=== modified file 'data/tribes/buildings/productionsites/empire/sheepfarm/init.lua'
--- data/tribes/buildings/productionsites/empire/sheepfarm/init.lua 2016-09-03 14:59:10 +0000
+++ data/tribes/buildings/productionsites/empire/sheepfarm/init.lua 2017-07-03 17:39:38 +0000
@@ -31,7 +31,7 @@
31 },31 },
3232
33 aihints = {33 aihints = {
34 prohibited_till = 60034 prohibited_till = 300
35 },35 },
3636
37 working_positions = {37 working_positions = {
3838
=== modified file 'data/tribes/buildings/productionsites/empire/stonemasons_house/init.lua'
--- data/tribes/buildings/productionsites/empire/stonemasons_house/init.lua 2016-09-03 14:59:10 +0000
+++ data/tribes/buildings/productionsites/empire/stonemasons_house/init.lua 2017-07-03 17:39:38 +0000
@@ -32,7 +32,7 @@
32 },32 },
3333
34 aihints = {34 aihints = {
35 forced_after = 400,35 basic_amount = 1,
36 prohibited_till = 400,36 prohibited_till = 400,
37 very_weak_ai_limit = 1,37 very_weak_ai_limit = 1,
38 weak_ai_limit = 238 weak_ai_limit = 2
3939
=== modified file 'data/tribes/buildings/productionsites/empire/tavern/init.lua'
--- data/tribes/buildings/productionsites/empire/tavern/init.lua 2016-10-26 19:21:32 +0000
+++ data/tribes/buildings/productionsites/empire/tavern/init.lua 2017-07-03 17:39:38 +0000
@@ -33,7 +33,7 @@
33 },33 },
3434
35 aihints = {35 aihints = {
36 forced_after = 900,36 basic_amount = 1,
37 prohibited_till = 30037 prohibited_till = 300
38 },38 },
3939
4040
=== modified file 'data/tribes/buildings/productionsites/empire/toolsmithy/init.lua'
--- data/tribes/buildings/productionsites/empire/toolsmithy/init.lua 2016-09-03 14:59:10 +0000
+++ data/tribes/buildings/productionsites/empire/toolsmithy/init.lua 2017-07-03 17:39:38 +0000
@@ -32,7 +32,6 @@
32 },32 },
3333
34 aihints = {34 aihints = {
35 forced_after = 400,
36 prohibited_till = 40035 prohibited_till = 400
37 },36 },
3837
3938
=== modified file 'data/tribes/buildings/productionsites/empire/vineyard/init.lua'
--- data/tribes/buildings/productionsites/empire/vineyard/init.lua 2015-12-11 16:54:00 +0000
+++ data/tribes/buildings/productionsites/empire/vineyard/init.lua 2017-07-03 17:39:38 +0000
@@ -29,7 +29,7 @@
2929
30 aihints = {30 aihints = {
31 space_consumer = true,31 space_consumer = true,
32 forced_after = 30032 basic_amount = 1
33 },33 },
3434
35 working_positions = {35 working_positions = {
3636
=== modified file 'data/tribes/buildings/productionsites/empire/weaponsmithy/init.lua'
--- data/tribes/buildings/productionsites/empire/weaponsmithy/init.lua 2016-10-30 19:06:01 +0000
+++ data/tribes/buildings/productionsites/empire/weaponsmithy/init.lua 2017-07-03 17:39:38 +0000
@@ -39,7 +39,8 @@
39 },39 },
4040
41 aihints = {41 aihints = {
42 prohibited_till = 90042 prohibited_till = 900,
43 forced_after = 3600
43 },44 },
4445
45 working_positions = {46 working_positions = {
4647
=== modified file 'data/tribes/buildings/productionsites/empire/winery/init.lua'
--- data/tribes/buildings/productionsites/empire/winery/init.lua 2016-09-03 14:59:10 +0000
+++ data/tribes/buildings/productionsites/empire/winery/init.lua 2017-07-03 17:39:38 +0000
@@ -33,10 +33,10 @@
33 },33 },
3434
35 aihints = {35 aihints = {
36 forced_after = 600,
37 prohibited_till = 600,36 prohibited_till = 600,
38 very_weak_ai_limit = 1,37 very_weak_ai_limit = 1,
39 weak_ai_limit = 238 weak_ai_limit = 2,
39 basic_amount = 1
40 },40 },
4141
42 working_positions = {42 working_positions = {
4343
=== modified file 'data/tribes/buildings/trainingsites/atlanteans/dungeon/init.lua'
--- data/tribes/buildings/trainingsites/atlanteans/dungeon/init.lua 2017-02-10 09:40:17 +0000
+++ data/tribes/buildings/trainingsites/atlanteans/dungeon/init.lua 2017-07-03 17:39:38 +0000
@@ -112,7 +112,6 @@
112 },112 },
113113
114 aihints = {114 aihints = {
115 trainingsite_type = "advanced",
116 prohibited_till = 1500,115 prohibited_till = 1500,
117 very_weak_ai_limit = 0,116 very_weak_ai_limit = 0,
118 weak_ai_limit = 1117 weak_ai_limit = 1
119118
=== modified file 'data/tribes/buildings/trainingsites/atlanteans/labyrinth/init.lua'
--- data/tribes/buildings/trainingsites/atlanteans/labyrinth/init.lua 2017-02-10 09:40:17 +0000
+++ data/tribes/buildings/trainingsites/atlanteans/labyrinth/init.lua 2017-07-03 17:39:38 +0000
@@ -36,7 +36,6 @@
36 aihints = {36 aihints = {
37 prohibited_till = 900,37 prohibited_till = 900,
38 forced_after = 1500,38 forced_after = 1500,
39 trainingsite_type = "basic",
40 very_weak_ai_limit = 1,39 very_weak_ai_limit = 1,
41 weak_ai_limit = 240 weak_ai_limit = 2
42 },41 },
4342
=== modified file 'data/tribes/buildings/trainingsites/barbarians/battlearena/init.lua'
--- data/tribes/buildings/trainingsites/barbarians/battlearena/init.lua 2017-02-10 09:40:17 +0000
+++ data/tribes/buildings/trainingsites/barbarians/battlearena/init.lua 2017-07-03 17:39:38 +0000
@@ -48,7 +48,6 @@
48 aihints = {48 aihints = {
49 prohibited_till = 900,49 prohibited_till = 900,
50 forced_after = 1500,50 forced_after = 1500,
51 trainingsite_type = "basic",
52 very_weak_ai_limit = 1,51 very_weak_ai_limit = 1,
53 weak_ai_limit = 352 weak_ai_limit = 3
54 },53 },
5554
=== modified file 'data/tribes/buildings/trainingsites/barbarians/trainingcamp/init.lua'
--- data/tribes/buildings/trainingsites/barbarians/trainingcamp/init.lua 2017-02-10 09:40:17 +0000
+++ data/tribes/buildings/trainingsites/barbarians/trainingcamp/init.lua 2017-07-03 17:39:38 +0000
@@ -41,7 +41,6 @@
4141
42 aihints = {42 aihints = {
43 prohibited_till = 1500,43 prohibited_till = 1500,
44 trainingsite_type = "advanced",
45 very_weak_ai_limit = 0,44 very_weak_ai_limit = 0,
46 weak_ai_limit = 145 weak_ai_limit = 1
47 },46 },
4847
=== modified file 'data/tribes/buildings/trainingsites/empire/arena/init.lua'
--- data/tribes/buildings/trainingsites/empire/arena/init.lua 2017-03-23 07:36:36 +0000
+++ data/tribes/buildings/trainingsites/empire/arena/init.lua 2017-07-03 17:39:38 +0000
@@ -37,7 +37,6 @@
37 },37 },
3838
39 aihints = {39 aihints = {
40 trainingsite_type = "basic",
41 trainingsites_max_percent = 20,40 trainingsites_max_percent = 20,
42 prohibited_till = 900,41 prohibited_till = 900,
43 very_weak_ai_limit = 1,42 very_weak_ai_limit = 1,
4443
=== modified file 'data/tribes/buildings/trainingsites/empire/colosseum/init.lua'
--- data/tribes/buildings/trainingsites/empire/colosseum/init.lua 2017-02-10 09:40:17 +0000
+++ data/tribes/buildings/trainingsites/empire/colosseum/init.lua 2017-07-03 17:39:38 +0000
@@ -34,7 +34,6 @@
3434
35 aihints = {35 aihints = {
36 prohibited_till = 1200,36 prohibited_till = 1200,
37 trainingsite_type = "basic",
38 forced_after = 1800,37 forced_after = 1800,
39 very_weak_ai_limit = 1,38 very_weak_ai_limit = 1,
40 weak_ai_limit = 239 weak_ai_limit = 2
4140
=== modified file 'data/tribes/buildings/trainingsites/empire/trainingcamp/init.lua'
--- data/tribes/buildings/trainingsites/empire/trainingcamp/init.lua 2017-02-10 09:40:17 +0000
+++ data/tribes/buildings/trainingsites/empire/trainingcamp/init.lua 2017-07-03 17:39:38 +0000
@@ -35,7 +35,6 @@
3535
36 aihints = {36 aihints = {
37 prohibited_till = 1500,37 prohibited_till = 1500,
38 trainingsite_type = "advanced",
39 very_weak_ai_limit = 0,38 very_weak_ai_limit = 0,
40 weak_ai_limit = 139 weak_ai_limit = 1
41 },40 },
4241
=== modified file 'data/tribes/empire.lua'
--- data/tribes/empire.lua 2017-04-30 10:30:02 +0000
+++ data/tribes/empire.lua 2017-07-03 17:39:38 +0000
@@ -326,4 +326,9 @@
326 headquarters = "empire_headquarters",326 headquarters = "empire_headquarters",
327 port = "empire_port",327 port = "empire_port",
328 barracks = "empire_barracks",328 barracks = "empire_barracks",
329 bakery = "empire_bakery",
330 ironore = "iron_ore",
331 rawlog = "log",
332 refinedlog = "planks",
333 granite = "granite",
329}334}
330335
=== modified file 'src/ai/ai_help_structs.cc'
--- src/ai/ai_help_structs.cc 2017-01-25 18:55:59 +0000
+++ src/ai/ai_help_structs.cc 2017-07-03 17:39:38 +0000
@@ -20,6 +20,7 @@
20#include "ai/ai_help_structs.h"20#include "ai/ai_help_structs.h"
2121
22#include "base/macros.h"22#include "base/macros.h"
23#include "base/time_string.h"
23#include "logic/map.h"24#include "logic/map.h"
24#include "logic/player.h"25#include "logic/player.h"
2526
@@ -27,6 +28,8 @@
27constexpr int kRoadNotFound = -1000;28constexpr int kRoadNotFound = -1000;
28constexpr int kShortcutWithinSameEconomy = 1000;29constexpr int kShortcutWithinSameEconomy = 1000;
29constexpr int kRoadToDifferentEconomy = 10000;30constexpr int kRoadToDifferentEconomy = 10000;
31constexpr int kUpperDefaultMutationLimit = 200;
32constexpr int kLowerDefaultMutationLimit = 150;
3033
31namespace Widelands {34namespace Widelands {
3235
@@ -102,15 +105,12 @@
102// When looking for unowned terrain to acquire, we are actually105// When looking for unowned terrain to acquire, we are actually
103// only interested in fields we can walk on.106// only interested in fields we can walk on.
104// Fields should either be completely unowned or owned by an opposing player107// Fields should either be completely unowned or owned by an opposing player
105FindNodeUnowned::FindNodeUnowned(Player* p, Game& g, bool oe)108FindEnemyNodeWalkable::FindEnemyNodeWalkable(Player* p, Game& g) : player(p), game(g) {
106 : player(p), game(g), only_enemies(oe) {
107}109}
108110
109bool FindNodeUnowned::accept(const Map&, const FCoords& fc) const {111bool FindEnemyNodeWalkable::accept(const Map&, const FCoords& fc) const {
110 return (fc.field->nodecaps() & MOVECAPS_WALK) &&112 return ((fc.field->nodecaps() & MOVECAPS_WALK) && (fc.field->get_owned_by() > 0) &&
111 ((fc.field->get_owned_by() == 0) ||113 player->is_hostile(*game.get_player(fc.field->get_owned_by())));
112 player->is_hostile(*game.get_player(fc.field->get_owned_by()))) &&
113 (!only_enemies || (fc.field->get_owned_by() != 0));
114}114}
115115
116// Sometimes we need to know how many nodes our allies owns116// Sometimes we need to know how many nodes our allies owns
@@ -127,11 +127,23 @@
127// When looking for unowned terrain to acquire, we must127// When looking for unowned terrain to acquire, we must
128// pay speciall attention to fields where mines can be built.128// pay speciall attention to fields where mines can be built.
129// Fields should be completely unowned129// Fields should be completely unowned
130FindNodeUnownedMineable::FindNodeUnownedMineable(Player* p, Game& g) : player(p), game(g) {130FindNodeUnownedMineable::FindNodeUnownedMineable(Player* p, Game& g, int32_t t)
131 : player(p), game(g), ore_type(t) {
131}132}
132133
133bool FindNodeUnownedMineable::accept(const Map&, const FCoords& fc) const {134bool FindNodeUnownedMineable::accept(const Map&, const FCoords& fc) const {
134 return (fc.field->nodecaps() & BUILDCAPS_MINE) && (fc.field->get_owned_by() == 0);135 if (ore_type == INVALID_INDEX) {
136 return (fc.field->nodecaps() & BUILDCAPS_MINE) && (fc.field->get_owned_by() == neutral());
137 }
138 return (fc.field->nodecaps() & BUILDCAPS_MINE) && (fc.field->get_owned_by() == neutral()) &&
139 fc.field->get_resources() == ore_type;
140}
141
142FindNodeUnownedBuildable::FindNodeUnownedBuildable(Player* p, Game& g) : player(p), game(g) {
143}
144
145bool FindNodeUnownedBuildable::accept(const Map&, const FCoords& fc) const {
146 return (fc.field->nodecaps() & BUILDCAPS_SIZEMASK) && (fc.field->get_owned_by() == neutral());
135}147}
136148
137// Unowned but walkable fields nearby149// Unowned but walkable fields nearby
@@ -139,7 +151,7 @@
139}151}
140152
141bool FindNodeUnownedWalkable::accept(const Map&, const FCoords& fc) const {153bool FindNodeUnownedWalkable::accept(const Map&, const FCoords& fc) const {
142 return (fc.field->nodecaps() & MOVECAPS_WALK) && (fc.field->get_owned_by() == 0);154 return (fc.field->nodecaps() & MOVECAPS_WALK) && (fc.field->get_owned_by() == neutral());
143}155}
144156
145// Looking only for mines-capable fields nearby157// Looking only for mines-capable fields nearby
@@ -181,14 +193,35 @@
181 : flag(&f), cost(c), distance(d) {193 : flag(&f), cost(c), distance(d) {
182}194}
183195
196EventTimeQueue::EventTimeQueue() {
197}
198
199void EventTimeQueue::push(const uint32_t production_time) {
200 queue.push(production_time);
201}
202
203uint32_t EventTimeQueue::count(const uint32_t current_time) {
204 strip_old(current_time);
205 return queue.size();
206}
207
208void EventTimeQueue::strip_old(const uint32_t current_time) {
209 while (!queue.empty() && queue.front() < current_time - duration_) {
210 queue.pop();
211 }
212}
213
184BuildableField::BuildableField(const Widelands::FCoords& fc)214BuildableField::BuildableField(const Widelands::FCoords& fc)
185 : coords(fc),215 : coords(fc),
186 field_info_expiration(20000),216 field_info_expiration(20000),
187 preferred(false),217 preferred(false),
188 enemy_nearby(0),218 enemy_nearby(0),
219 enemy_accessible_(false),
220 enemy_wh_nearby(false),
189 unowned_land_nearby(0),221 unowned_land_nearby(0),
190 near_border(false),222 near_border(false),
191 unowned_mines_spots_nearby(0),223 unowned_mines_spots_nearby(0),
224 unowned_iron_mines_nearby(false),
192 trees_nearby(0),225 trees_nearby(0),
193 // explanation of starting values226 // explanation of starting values
194 // this is done to save some work for AI (CPU utilization)227 // this is done to save some work for AI (CPU utilization)
@@ -209,15 +242,22 @@
209 area_military_capacity(0),242 area_military_capacity(0),
210 military_loneliness(1000),243 military_loneliness(1000),
211 military_in_constr_nearby(0),244 military_in_constr_nearby(0),
212 area_military_presence(0),245 own_military_presence(0),
246 enemy_military_presence(0),
247 ally_military_presence(0),
213 military_stationed(0),248 military_stationed(0),
214 unconnected_nearby(false),249 unconnected_nearby(false),
215 military_unstationed(0),250 military_unstationed(0),
216 is_portspace(false),251 own_non_military_nearby(0),
252 is_portspace(Widelands::ExtendedBool::kUnset),
217 port_nearby(false),253 port_nearby(false),
218 portspace_nearby(Widelands::ExtendedBool::kUnset),254 portspace_nearby(Widelands::ExtendedBool::kUnset),
219 max_buildcap_nearby(0),255 max_buildcap_nearby(0),
220 last_resources_check_time(0) {256 last_resources_check_time(0),
257 military_score_(0),
258 inland(false),
259 local_soldier_capacity(0),
260 is_militarysite(false) {
221}261}
222262
223int32_t BuildableField::own_military_sites_nearby_() {263int32_t BuildableField::own_military_sites_nearby_() {
@@ -240,6 +280,19 @@
240 return cnt_built + cnt_under_construction;280 return cnt_built + cnt_under_construction;
241}281}
242282
283bool BuildingObserver::is(BuildingAttribute attribute) const {
284 return is_what.count(attribute) == 1;
285}
286
287void BuildingObserver::set_is(const BuildingAttribute attribute) {
288 is_what.insert(attribute);
289}
290
291void BuildingObserver::unset_is(const BuildingAttribute attribute) {
292 is_what.erase(attribute);
293 assert(!is(attribute));
294}
295
243Widelands::AiModeBuildings BuildingObserver::aimode_limit_status() {296Widelands::AiModeBuildings BuildingObserver::aimode_limit_status() {
244 if (total_count() > cnt_limit_by_aimode) {297 if (total_count() > cnt_limit_by_aimode) {
245 return Widelands::AiModeBuildings::kLimitExceeded;298 return Widelands::AiModeBuildings::kLimitExceeded;
@@ -250,7 +303,7 @@
250 }303 }
251}304}
252bool BuildingObserver::buildable(Widelands::Player& p) {305bool BuildingObserver::buildable(Widelands::Player& p) {
253 return is_buildable && p.is_building_type_allowed(id);306 return is(BuildingAttribute::kBuildable) && p.is_building_type_allowed(id);
254}307}
255308
256// Computer player does not get notification messages about enemy militarysites309// Computer player does not get notification messages about enemy militarysites
@@ -264,16 +317,769 @@
264 attack_soldiers_strength(0),317 attack_soldiers_strength(0),
265 defenders_strength(0),318 defenders_strength(0),
266 stationed_soldiers(0),319 stationed_soldiers(0),
267 last_time_attackable(std::numeric_limits<uint32_t>::max()),320 last_time_seen(0),
268 last_tested(0),321 last_tested(0),
269 score(0),322 score(0),
270 mines_nearby(Widelands::ExtendedBool::kUnset),323 mines_nearby(Widelands::ExtendedBool::kUnset),
271 no_attack_counter(0) {324 last_time_attacked(0),
325 attack_counter(0) {
272}326}
273327
274// as all mines have 3 levels, AI does not know total count of mines per mined material328// as all mines have 3 levels, AI does not know total count of mines per mined material
275// so this observer will be used for this329// so this observer will be used for this
276MineTypesObserver::MineTypesObserver() : in_construction(0), finished(0) {330MineTypesObserver::MineTypesObserver()
331 : in_construction(0), finished(0), is_critical(false), unoccupied(0) {
332}
333
334ExpansionType::ExpansionType() {
335 type = ExpansionMode::kResources;
336}
337
338void ExpansionType::set_expantion_type(const ExpansionMode etype) {
339 type = etype;
340}
341
342ManagementData::ManagementData() {
343 score = 1;
344 primary_parent = 255;
345 next_neuron_id = 0;
346 performance_change = 0;
347}
348
349// Initialization of neuron. Neuron is defined by curve (type) and weight [-kWeightRange, kWeightRange]
350// third argument is just id
351Neuron::Neuron(int8_t w, uint8_t f, uint16_t i) : weight(w), type(f), id(i) {
352 assert(type < neuron_curves.size());
353 assert(weight >= -kNeuronWeightLimit && weight <= kNeuronWeightLimit);
354 recalculate();
355}
356
357// Weight, or rather value in range [-kWeightRange, kWeightRange]. Automatically adjusts the weight to the range in case of
358// overflow.
359void Neuron::set_weight(int8_t w) {
360 weight = Neuron::clip_weight_to_range(w);
361}
362
363// Neuron stores calculated values in an array of size 21.
364// This has to be recalculated when the weight or curve type change
365void Neuron::recalculate() {
366 assert(neuron_curves.size() > type);
367 for (uint8_t i = 0; i <= kNeuronMaxPosition; i += 1) {
368 results[i] = weight * neuron_curves[type][i] / kNeuronWeightLimit;
369 }
370}
371
372// The Following two functions return Neuron values on position
373int8_t Neuron::get_result(const size_t pos) {
374 assert(pos <= kNeuronMaxPosition);
375 return results[pos];
376}
377
378// get value corresponding to input in range 0-20, if you are out of range
379// the input will be cropped
380int8_t Neuron::get_result_safe(int32_t pos, const bool absolute) {
381 // pos has to be normalized into range 0 - 20(kNeuronMaxPosition)
382 pos = std::max(0, std::min(static_cast<int>(kNeuronMaxPosition), pos));
383
384 assert(pos <= static_cast<int32_t>(kNeuronMaxPosition));
385 assert(pos >= 0);
386 assert(results[pos] >= -kNeuronWeightLimit && results[pos] <= kNeuronWeightLimit);
387
388 if (absolute) {
389 return std::abs(results[pos]);
390 }
391 return results[pos];
392}
393
394// Setting the type of curve
395void Neuron::set_type(uint8_t new_type) {
396 assert(new_type < neuron_curves.size());
397 type = new_type;
398}
399
400// FNeuron is basically a single uint32_t integer, and the AI can query every bit of that uint32_t
401FNeuron::FNeuron(uint32_t c, uint16_t i) {
402 core = c;
403 id = i;
404}
405
406// Returning a result depending on combinations of 5 bools
407// Bools are completely anonymous, but can present any yes/no inputs, e.g. imagine the AI that is
408// to figure out if it should attack from a militarysite. The inputs can be:
409// bool1 - are we stronger than the enemy?
410// bool2 - do we have a basic economy established?
411// bool3 - do we have local predominance?
412// bool4 - has our strength grown during the last 60 minutes?
413// bool5 - are there mines in the vicinity?
414// These five bools can create 32 combinations = yes/no answers.
415// In fact this can be perceived as a complicated if..then structure, but one that can
416// adjust automatically as a part of training.
417// Or rather it is a 5-dimensional table with 2 columns in every dimension :)
418// In fact this concept if very demanding for training so we don't use it much
419bool FNeuron::get_result(
420 const bool bool1, const bool bool2, const bool bool3, const bool bool4, const bool bool5) {
421 return core.test(bool1 * 16 + bool2 * 8 + bool3 * 4 + bool4 * 2 + bool5);
422}
423
424// Returning bool on a position
425bool FNeuron::get_position(const uint8_t pos) {
426 assert(pos < kFNeuronBitSize);
427 return core.test(pos);
428}
429
430// Returning numerical value of FNeuron. Used for saving and priting into log
431uint32_t FNeuron::get_int() {
432 return core.to_ulong();
433}
434
435// This is basically a mutation of FNeuron
436void FNeuron::flip_bit(const uint8_t pos) {
437 assert(pos < kFNeuronBitSize);
438 core.flip(pos);
439}
440
441// Shifting the value in range -kWeightRange to kWeightRange, if zero_align is true, it is now allowed to shift
442// from negative to positive and vice versa, 0 must be used.
443int8_t ManagementData::shift_weight_value(const int8_t old_value, const bool aggressive) {
444
445 int16_t halfVArRange = 50;
446 if (aggressive) {
447 halfVArRange = 200;
448 }
449
450 const int16_t upper_limit = std::min<int16_t>(old_value + halfVArRange, kNeuronWeightLimit);
451 const int16_t bottom_limit = std::max<int16_t>(old_value - halfVArRange, -kNeuronWeightLimit);
452 int16_t new_value = bottom_limit + std::rand() % (upper_limit - bottom_limit + 1);
453
454 if (!aggressive && ((old_value > 0 && new_value < 0) || (old_value < 0 && new_value > 0))) {
455 new_value = 0;
456 }
457
458 new_value = Neuron::clip_weight_to_range(new_value);
459 return static_cast<int8_t>(new_value);
460}
461
462// Used to score performance of AI
463// Should be disabled for "production"
464void ManagementData::review(const uint32_t gametime,
465 PlayerNumber pn,
466 const uint32_t land,
467 const uint32_t max_e_land,
468 const uint32_t old_land,
469 const uint16_t attackers,
470 const int16_t trained_soldiers,
471 const int16_t latest_attackers,
472 const uint16_t conq_ws) {
473
474 const int16_t main_bonus =
475 ((static_cast<int32_t>(land - old_land) > 0 && land > max_e_land * 5 / 6 && attackers > 0 &&
476 trained_soldiers > 0 && latest_attackers > 0) ?
477 kBonus :
478 0);
479
480 const int16_t land_delta_bonus = static_cast<int16_t>(land - old_land) * kLandDeltaMultiplier;
481
482 score = land / kCurrentLandDivider + land_delta_bonus + main_bonus +
483 attackers * kAttackersMultiplier + ((attackers > 0) ? kAttackBonus : -kAttackBonus) +
484 trained_soldiers * kTrainedSoldiersScore + +kConqueredWhBonus + conq_ws;
485
486 log(" %2d %s: reviewing AI mngm. data, sc: %5d Pr.p: %d (l: %4d / %4d / %4d, "
487 "at:%4d(%3d), ts:%4d(%2d), ConqWH:%2d)\n",
488 pn, gamestring_with_leading_zeros(gametime), score, primary_parent,
489 land / kCurrentLandDivider, main_bonus, land_delta_bonus,
490 attackers * kAttackersMultiplier, latest_attackers,
491 trained_soldiers * kTrainedSoldiersScore, trained_soldiers, conq_ws);
492
493 if (score < -10000 || score > 30000) {
494 log(
495 "%2d %s: reviewing AI mngm. data, score too extreme: %4d\n",
496 pn, gamestring_with_leading_zeros(gametime), score);
497 }
498 assert(score > -10000 && score < 100000);
499}
500
501// Here we generate new AI DNA (no mutation yet) and push them into persistent data
502// this can cause inconsistency between local and persistent
503void ManagementData::new_dna_for_persistent(const uint8_t pn, const Widelands::AiType type) {
504
505 ai_type = type;
506
507 log ("%2d: DNA initialization... \n", pn);
508
509 // AutoSCore_AIDNA_1
510 const std::vector<int16_t> AI_initial_military_numbers_A =
511 { 18, -42, 21, 59, -7, -78, -22, 81, 48, 0, // AutoContent_01_AIDNA_1
512 -82, 45, -96, 16, 70, -30, 33, 79, -78, -42, // AutoContent_02_AIDNA_1
513 79, -16, 34, 46, -22, 0, 45, -29, 53, 51, // AutoContent_03_AIDNA_1
514 24, 47, -27, 80, -86, 46, -63, -47, 20, -63, // AutoContent_04_AIDNA_1
515 78, 51, -11, -77, 20, 38, 6, 37, -64, -41, // AutoContent_05_AIDNA_1
516 -3, -55, 62, 0, 64, -92, 4, -89, 71, -18, // AutoContent_06_AIDNA_1
517 -87, 56, 17, -34, -69, 24, -57, 84, 40, -51, // AutoContent_07_AIDNA_1
518 0, 44, 0, -2, -11, -4, -96, -35, -29, -12, // AutoContent_08_AIDNA_1
519 71, -98, -25, 50, 97, 74, 0, 65, -60, 23, // AutoContent_09_AIDNA_1
520 38, 53, 74, 0, -43, 27, 32, 37, -24, -65, // AutoContent_10_AIDNA_1
521 16, -42, 19, -94, -28, 83, -55, -63, 16, -41, // AutoContent_11_AIDNA_1
522 28, -3, 0, -87, 32, 5, 4, 6, -20, 62, // AutoContent_12_AIDNA_1
523 85, 0, 58, 48, -80, -20, -49, 71, 60, 8, // AutoContent_13_AIDNA_1
524 -52, 59, 100, -74, 0, -36, -9, 80, 41, -67, // AutoContent_14_AIDNA_1
525 0, 15, -96, -51, -21, 11, -27, -30, 76, -47 // AutoContent_15_AIDNA_1
526 }
527 ;
528
529 assert(kMagicNumbersSize == AI_initial_military_numbers_A.size());
530
531 const std::vector<int8_t> input_weights_A =
532 // 0 1 2 3 4 5 6 7 8 9
533 { 48, -85, -26, 47, -93, -22, -91, 84, 24, -12, // AutoContent_16_AIDNA_1
534 98, -59, -89, 76, 81, 95, -91, -90, -56, -15, // AutoContent_17_AIDNA_1
535 -65, -18, 6, -65, 41, 38, 47, -31, 79, 23, // AutoContent_18_AIDNA_1
536 16, 25, -59, 0, -38, -85, -60, -42, 0, -70, // AutoContent_19_AIDNA_1
537 -78, -86, -87, -55, 92, -63, -21, -76, 4, 87, // AutoContent_20_AIDNA_1
538 58, -40, 71, -90, -72, 0, -47, -94, -15, 66, // AutoContent_21_AIDNA_1
539 -32, 9, 67, -47, -44, -76, -53, 57, -31, -47, // AutoContent_22_AIDNA_1
540 0, -28, -16, 48, 41, -45, 36, -8, 51, -49 // AutoContent_23_AIDNA_1
541 }
542 ;
543 const std::vector<int8_t> input_func_A =
544 { 1, 0, 1, 2, 2, 1, 0, 0, 0, 0, // AutoContent_24_AIDNA_1
545 2, 1, 2, 2, 2, 1, 2, 2, 2, 1, // AutoContent_25_AIDNA_1
546 2, 2, 0, 2, 2, 1, 0, 1, 0, 2, // AutoContent_26_AIDNA_1
547 1, 2, 2, 1, 2, 1, 0, 1, 2, 1, // AutoContent_27_AIDNA_1
548 2, 1, 2, 0, 0, 1, 2, 0, 0, 0, // AutoContent_28_AIDNA_1
549 1, 0, 0, 1, 0, 1, 0, 0, 1, 1, // AutoContent_29_AIDNA_1
550 2, 0, 1, 2, 0, 2, 2, 2, 1, 0, // AutoContent_30_AIDNA_1
551 2, 1, 2, 2, 1, 1, 0, 2, 2, 1 // AutoContent_31_AIDNA_1
552 }
553 ;
554 assert(kNeuronPoolSize == input_func_A.size());
555 assert(kNeuronPoolSize == input_weights_A.size());
556
557 const std::vector<uint32_t> f_neurons_A =
558 { 471130763, 1322756799, 1148682382, 2713953719, 194460207, 18113635, 2947490886, 3275944172, 3438582086, 856208494, // AutoContent_32_AIDNA_1
559 1326156684, 986431571, 3465514749, 1962749574, 1523585333, 1376482111, 1223335901, 2962231598, 657710612, 578259960, // AutoContent_33_AIDNA_1
560 1271222963, 2915927856, 3396846486, 1743568169, 2679432920, 410834609, 134904175, 2968201710, 2132567223, 2248461478, // AutoContent_34_AIDNA_1
561 161963959, 3295327519, 670058472, 2013696856, 3608400883, 496651103, 733137541, 2952748738, 3307293853, 3886490843, // AutoContent_35_AIDNA_1
562 3233788172, 715230539, 2583635732, 4271028953, 1217674278, 4043323645, 1857109651, 2181897047, 2825979187, 3081298269, // AutoContent_36_AIDNA_1
563 1277901018, 1255642150, 2384261818, 2866704864, 755617465, 835768208, 1394358417, 4012239945, 2601238115, 3933467106 // AutoContent_37_AIDNA_1
564 };
565 assert(kFNeuronPoolSize == f_neurons_A.size());
566
567
568 // AutoSCore_AIDNA_2
569 const std::vector<int16_t> AI_initial_military_numbers_B =
570 { 18, -42, 21, 59, -7, -78, -22, 81, 48, 0, // AutoContent_01_AIDNA_2
571 -55, 45, -96, 16, 70, -30, 33, 79, -78, -42, // AutoContent_02_AIDNA_2
572 79, -16, 34, 46, -22, 0, 45, -33, 53, 51, // AutoContent_03_AIDNA_2
573 49, 47, -27, 80, -86, 46, -63, -47, 20, -63, // AutoContent_04_AIDNA_2
574 78, 51, 23, -77, 20, 38, 6, 37, -64, -41, // AutoContent_05_AIDNA_2
575 -3, -55, 62, 0, 64, -92, 4, -89, 71, -18, // AutoContent_06_AIDNA_2
576 -87, 56, 17, -34, -69, 24, -57, 84, 40, -51, // AutoContent_07_AIDNA_2
577 0, 44, 0, -2, -11, -4, -96, -35, -29, -12, // AutoContent_08_AIDNA_2
578 71, -98, -25, 50, 97, 74, 0, 65, -60, 23, // AutoContent_09_AIDNA_2
579 38, 53, 74, 0, -15, 27, 32, 37, -24, -65, // AutoContent_10_AIDNA_2
580 16, -42, 19, -94, -28, 83, -55, -63, 16, -41, // AutoContent_11_AIDNA_2
581 28, -3, 0, -87, 32, 5, 4, 6, -20, 62, // AutoContent_12_AIDNA_2
582 85, 0, 58, 48, -80, -20, -49, 71, 60, 8, // AutoContent_13_AIDNA_2
583 -52, 59, 100, -74, 0, -36, -9, 80, 41, -67, // AutoContent_14_AIDNA_2
584 0, 15, -96, -51, -21, 11, -27, -30, 76, -47 // AutoContent_15_AIDNA_2
585 }
586 ;
587 assert(kMagicNumbersSize == AI_initial_military_numbers_B.size());
588
589 const std::vector<int8_t> input_weights_B =
590 { 48, -85, -26, 47, -93, -22, -91, 84, 50, -12, // AutoContent_16_AIDNA_2
591 98, -59, -89, 76, 81, 95, -91, -90, -56, -15, // AutoContent_17_AIDNA_2
592 -65, -18, 6, -65, 41, 38, 47, -31, 79, 23, // AutoContent_18_AIDNA_2
593 16, 25, -59, 0, -38, -85, -60, -42, 0, -70, // AutoContent_19_AIDNA_2
594 -78, -86, -87, -55, 92, -63, -21, -76, 4, 87, // AutoContent_20_AIDNA_2
595 58, -40, 71, -90, -72, 0, -47, -94, -15, 66, // AutoContent_21_AIDNA_2
596 -32, 9, 67, -47, -44, -76, -53, 57, -31, -47, // AutoContent_22_AIDNA_2
597 0, -28, -16, 48, 41, -45, 36, -8, 51, -49 // AutoContent_23_AIDNA_2
598}
599 ;
600
601 const std::vector<int8_t> input_func_B =
602 { 1, 0, 1, 2, 2, 1, 0, 0, 0, 0, // AutoContent_24_AIDNA_2
603 2, 1, 2, 2, 2, 1, 2, 2, 2, 1, // AutoContent_25_AIDNA_2
604 2, 2, 0, 2, 2, 1, 0, 1, 0, 2, // AutoContent_26_AIDNA_2
605 1, 2, 2, 1, 2, 1, 0, 1, 2, 1, // AutoContent_27_AIDNA_2
606 2, 1, 2, 0, 0, 1, 2, 0, 0, 0, // AutoContent_28_AIDNA_2
607 1, 0, 0, 1, 0, 1, 0, 0, 1, 1, // AutoContent_29_AIDNA_2
608 2, 0, 1, 2, 0, 2, 2, 2, 1, 0, // AutoContent_30_AIDNA_2
609 2, 1, 2, 2, 1, 1, 0, 2, 2, 1 // AutoContent_31_AIDNA_2
610}
611 ;
612 assert(kNeuronPoolSize == input_func_B.size());
613 assert(kNeuronPoolSize == input_weights_B.size());
614
615
616 const std::vector<uint32_t> f_neurons_B =
617 { 471130763, 1322756799, 1148682382, 2713953719, 194460207, 18113635, 2947490886, 3275944172, 3438582022, 855676014, // AutoContent_32_AIDNA_2
618 1326156684, 986431571, 3465514749, 1962749574, 1523650869, 1376482111, 2347409353, 2962227502, 657710612, 578259960, // AutoContent_33_AIDNA_2
619 1271222963, 2915927856, 3396846486, 1743568169, 2679432920, 410834609, 134904175, 2968201710, 2132567223, 2248461478, // AutoContent_34_AIDNA_2
620 161963959, 3295327519, 670058472, 2013696856, 4145271795, 496651103, 733211269, 2952748738, 1159810205, 3886490843, // AutoContent_35_AIDNA_2
621 3225153820, 732007755, 2583635732, 4271028825, 1217674278, 4043323645, 1857109651, 2249005911, 2825979187, 3081298269, // AutoContent_36_AIDNA_2
622 1277901018, 1255642150, 2384261818, 2866704864, 755617465, 835768208, 1394096273, 4012239945, 2609626723, 3932418530 // AutoContent_37_AIDNA_2
623 };
624 assert(kFNeuronPoolSize == f_neurons_B.size());
625
626
627 // AutoSCore_AIDNA_3
628 const std::vector<int16_t> AI_initial_military_numbers_C =
629 { 18, -42, 63, 82, -7, -78, -22, 81, 48, 0, // AutoContent_01_AIDNA_3
630 -55, 55, -96, 16, 70, -30, 33, 79, -78, -42, // AutoContent_02_AIDNA_3
631 79, -16, 34, 46, 0, 0, 0, -29, 53, 51, // AutoContent_03_AIDNA_3
632 24, 47, -27, 42, -86, 46, -63, -47, 20, -63, // AutoContent_04_AIDNA_3
633 78, 31, 98, -73, 20, 38, 44, 37, -64, -41, // AutoContent_05_AIDNA_3
634 -3, -55, 67, 0, 64, -92, 4, -89, 71, -60, // AutoContent_06_AIDNA_3
635 -87, 56, 17, -34, -69, 24, -57, 50, 40, -51, // AutoContent_07_AIDNA_3
636 -34, 44, 0, -2, -11, -4, -96, -35, -29, -12, // AutoContent_08_AIDNA_3
637 68, -98, -25, 50, 97, 74, 0, 65, -60, 23, // AutoContent_09_AIDNA_3
638 38, 53, 74, 0, -15, 27, 32, 61, -24, -65, // AutoContent_10_AIDNA_3
639 16, -42, 19, -94, -65, 83, -55, -63, 16, -41, // AutoContent_11_AIDNA_3
640 74, -3, 0, -87, 32, 5, 4, 6, -70, 62, // AutoContent_12_AIDNA_3
641 85, 0, 58, 48, -80, -20, -49, 71, 60, 8, // AutoContent_13_AIDNA_3
642 -52, 30, 69, -74, 0, -36, -57, 80, 64, -67, // AutoContent_14_AIDNA_3
643 0, 15, -96, -51, -21, 0, -33, -30, 76, -47 // AutoContent_15_AIDNA_3
644 }
645
646 ;
647
648 assert(kMagicNumbersSize == AI_initial_military_numbers_C.size());
649
650 const std::vector<int8_t> input_weights_C =
651 { 48, -85, -26, 47, -65, -19, -91, 84, 92, -12, // AutoContent_16_AIDNA_3
652 78, -59, -89, 76, 81, 95, -91, -90, -56, -15, // AutoContent_17_AIDNA_3
653 -65, -18, 6, -65, 17, 38, 47, -45, 79, 23, // AutoContent_18_AIDNA_3
654 16, 25, -59, 36, -38, -85, -60, -42, 0, -70, // AutoContent_19_AIDNA_3
655 -78, -86, -87, -55, 92, -63, -21, -76, 4, 87, // AutoContent_20_AIDNA_3
656 58, -40, 71, -90, -72, 0, -47, -94, -15, 95, // AutoContent_21_AIDNA_3
657 -32, 9, 67, -47, -44, -76, -53, 57, -31, -47, // AutoContent_22_AIDNA_3
658 0, -28, -16, 48, 41, -45, 36, -8, 63, -49 // AutoContent_23_AIDNA_3
659 }
660 ;
661 const std::vector<int8_t> input_func_C =
662 { 1, 0, 1, 2, 2, 1, 0, 0, 0, 0, // AutoContent_24_AIDNA_3
663 2, 1, 2, 2, 1, 1, 2, 2, 2, 1, // AutoContent_25_AIDNA_3
664 2, 2, 0, 2, 2, 1, 0, 1, 0, 2, // AutoContent_26_AIDNA_3
665 1, 2, 2, 1, 2, 1, 0, 1, 2, 1, // AutoContent_27_AIDNA_3
666 2, 1, 2, 0, 0, 1, 2, 0, 0, 0, // AutoContent_28_AIDNA_3
667 1, 0, 0, 1, 0, 2, 0, 0, 1, 1, // AutoContent_29_AIDNA_3
668 2, 0, 1, 2, 0, 2, 2, 2, 1, 0, // AutoContent_30_AIDNA_3
669 2, 1, 2, 2, 1, 1, 0, 2, 2, 1 // AutoContent_31_AIDNA_3
670 }
671 ;
672 assert(kNeuronPoolSize == input_func_C.size());
673 assert(kNeuronPoolSize == input_weights_C.size());
674
675 const std::vector<uint32_t> f_neurons_C =
676 { 202828425, 1322625717, 1148682382, 2244191679, 194456367, 26493027, 2947491014, 3410163948, 3438582086, 856208494, // AutoContent_32_AIDNA_3
677 1259048860, 986431571, 3457662708, 1954360966, 1523650869, 1376351039, 1223335901, 2997887274, 657657361, 645368312, // AutoContent_33_AIDNA_3
678 1271218867, 2915927856, 3933717470, 2011479337, 2645864080, 408737457, 2282387823, 2968205806, 1597793527, 2248461494, // AutoContent_34_AIDNA_3
679 161963959, 1147843615, 670058474, 2013712728, 4145271795, 496651102, 724812677, 2952748738, 1629834973, 3819381979, // AutoContent_35_AIDNA_3
680 3233788172, 732007755, 2583635734, 4271028825, 1217670182, 4043323645, 1857109659, 2249005911, 2834367795, 3072909661, // AutoContent_36_AIDNA_3
681 1278949528, 1792513063, 2384261690, 2732487136, 755615385, 835767184, 1393834641, 4012239945, 2601238115, 2859725290 // AutoContent_37_AIDNA_3
682 };
683 assert(kFNeuronPoolSize == f_neurons_C.size());
684
685
686 // AutoSCore_AIDNA_4
687 const std::vector<int16_t> AI_initial_military_numbers_D =
688 { 18, -42, 21, 59, -7, -78, -22, 81, 48, 0, // AutoContent_01_AIDNA_4
689 -55, 45, -96, 16, 70, -30, 33, 79, -78, -42, // AutoContent_02_AIDNA_4
690 79, -16, 34, 46, -22, 0, 45, -29, 53, 51, // AutoContent_03_AIDNA_4
691 24, 47, -27, 80, -86, 46, -63, -47, 20, -63, // AutoContent_04_AIDNA_4
692 78, 51, -25, -77, 20, 38, 6, 37, -64, -41, // AutoContent_05_AIDNA_4
693 -3, -55, 62, 0, 64, -92, 4, -89, 71, -18, // AutoContent_06_AIDNA_4
694 -87, 56, 17, -34, -69, 24, -57, 84, 40, -51, // AutoContent_07_AIDNA_4
695 0, 44, 0, -2, -11, -4, -96, -35, -29, -12, // AutoContent_08_AIDNA_4
696 71, -98, -25, 50, 97, 74, 0, 65, -60, 23, // AutoContent_09_AIDNA_4
697 38, 53, 74, 0, -15, 27, 32, 37, -24, -65, // AutoContent_10_AIDNA_4
698 16, -61, 19, -94, -28, 83, -55, -63, 16, -41, // AutoContent_11_AIDNA_4
699 28, -3, 0, -87, 32, 5, 4, 6, -20, 62, // AutoContent_12_AIDNA_4
700 85, 0, 58, 48, -80, -20, -49, 71, 60, 8, // AutoContent_13_AIDNA_4
701 -52, 59, 100, -74, 0, -36, -9, 80, 41, -67, // AutoContent_14_AIDNA_4
702 0, 15, -96, -51, -21, 11, -27, -30, 76, -47 // AutoContent_15_AIDNA_4
703 }
704 ;
705 assert(kMagicNumbersSize == AI_initial_military_numbers_D.size());
706
707 const std::vector<int8_t> input_weights_D =
708 { 48, -85, -26, 47, -93, -22, -91, 84, 50, -12, // AutoContent_16_AIDNA_4
709 98, -59, -89, 76, 81, 95, -91, -90, -56, -15, // AutoContent_17_AIDNA_4
710 -65, -18, 6, -65, 41, 38, 47, -31, 79, 23, // AutoContent_18_AIDNA_4
711 16, 25, -59, 0, -38, -85, -60, -42, 0, -70, // AutoContent_19_AIDNA_4
712 -78, -86, -87, -55, 92, -63, -21, -76, 4, 87, // AutoContent_20_AIDNA_4
713 58, -40, 71, -90, -72, 0, -47, -94, -15, 66, // AutoContent_21_AIDNA_4
714 -32, 9, 67, -47, -44, -76, -53, 57, -31, -47, // AutoContent_22_AIDNA_4
715 0, -28, -16, 48, 41, -45, 36, -8, 63, -49 // AutoContent_23_AIDNA_4
716 }
717 ;
718
719 const std::vector<int8_t> input_func_D =
720 { 1, 0, 1, 2, 2, 1, 0, 0, 0, 0, // AutoContent_24_AIDNA_4
721 2, 1, 2, 2, 2, 1, 2, 2, 2, 1, // AutoContent_25_AIDNA_4
722 2, 2, 0, 2, 2, 1, 0, 1, 0, 2, // AutoContent_26_AIDNA_4
723 1, 2, 2, 1, 2, 1, 0, 1, 2, 1, // AutoContent_27_AIDNA_4
724 2, 1, 2, 0, 0, 1, 2, 0, 0, 0, // AutoContent_28_AIDNA_4
725 1, 0, 0, 1, 0, 1, 0, 0, 1, 1, // AutoContent_29_AIDNA_4
726 2, 0, 1, 2, 0, 2, 2, 2, 1, 0, // AutoContent_30_AIDNA_4
727 2, 1, 2, 2, 1, 1, 0, 2, 2, 1 // AutoContent_31_AIDNA_4
728 }
729 ;
730 assert(kNeuronPoolSize == input_func_D.size());
731 assert(kNeuronPoolSize == input_weights_D.size());
732
733 const std::vector<uint32_t> f_neurons_D =
734 { 471130763, 1322756799, 1148682382, 2713953719, 194460175, 18113635, 2947490886, 3275944172, 3438582214, 856208494, // AutoContent_32_AIDNA_4
735 1326156684, 449560659, 3465512701, 1962749574, 1523650869, 1376482111, 2347409353, 2962227502, 657710614, 578259960, // AutoContent_33_AIDNA_4
736 1271222963, 2915927856, 3396846486, 1743568169, 2679432920, 410834611, 134904175, 2968201710, 2132567223, 2248461478, // AutoContent_34_AIDNA_4
737 161963959, 3295327519, 670058472, 2013696856, 3608400883, 496651103, 733137541, 2952748738, 1159810205, 3886490843, // AutoContent_35_AIDNA_4
738 3225153820, 732007755, 2583635732, 4271028825, 1217674278, 4043323645, 1857109651, 2248481623, 3899721011, 3081298269, // AutoContent_36_AIDNA_4
739 1277901016, 1255642150, 2384261818, 2866704864, 755617465, 835768208, 1394358417, 4012239945, 2601238115, 3933467106 // AutoContent_37_AIDNA_4
740 };
741 assert(kFNeuronPoolSize == f_neurons_D.size());
742
743 primary_parent = std::rand() % 4;
744 const uint8_t parent2 = std::rand() % 4;
745
746 log (" ... Primary parent: %d, secondary parent: %d\n", primary_parent, parent2);
747
748 // First setting of military numbers, they go directly to persistent data
749 for (uint16_t i = 0; i < kMagicNumbersSize; i += 1) {
750 // Child inherits DNA with probability 5:1 from main parent
751 uint8_t dna_donor = (std::rand() % kSecondParentProbability > 0) ? primary_parent : parent2;
752 if (i == kMutationRatePosition) { // Overwriting
753 dna_donor = primary_parent;
754 }
755
756 switch (dna_donor) {
757 case 0 :
758 set_military_number_at(i, AI_initial_military_numbers_A[i]);
759 break;
760 case 1 :
761 set_military_number_at(i, AI_initial_military_numbers_B[i]);
762 break;
763 case 2 :
764 set_military_number_at(i, AI_initial_military_numbers_C[i]);
765 break;
766 case 3 :
767 set_military_number_at(i, AI_initial_military_numbers_D[i]);
768 break;
769 default:
770 log ("parent %d?\n", dna_donor);
771 NEVER_HERE();
772 }
773 }
774
775 pd->neuron_weights.clear();
776 pd->neuron_functs.clear();
777 pd->f_neurons.clear();
778
779 for (uint16_t i = 0; i < kNeuronPoolSize; i += 1) {
780 const uint8_t dna_donor = (std::rand() % kSecondParentProbability > 0) ? primary_parent : parent2;
781
782 switch (dna_donor) {
783 case 0 :
784 pd->neuron_weights.push_back(input_weights_A[i]);
785 pd->neuron_functs.push_back(input_func_A[i]);
786 break;
787 case 1 :
788 pd->neuron_weights.push_back(input_weights_B[i]);
789 pd->neuron_functs.push_back(input_func_B[i]);
790 break;
791 case 2 :
792 pd->neuron_weights.push_back(input_weights_C[i]);
793 pd->neuron_functs.push_back(input_func_C[i]);
794 break;
795 case 3 :
796 pd->neuron_weights.push_back(input_weights_D[i]);
797 pd->neuron_functs.push_back(input_func_D[i]);
798 break;
799 default:
800 log ("parent %d?\n", dna_donor);
801 NEVER_HERE();
802 }
803 }
804
805
806 for (uint16_t i = 0; i < kFNeuronPoolSize; i += 1) {
807 const uint8_t dna_donor = (std::rand() % kSecondParentProbability > 0) ? primary_parent : parent2;
808 switch (dna_donor) {
809 case 0 :
810 pd->f_neurons.push_back(f_neurons_A[i]);
811 break;
812 case 1 :
813 pd->f_neurons.push_back(f_neurons_B[i]);
814 break;
815 case 2 :
816 pd->f_neurons.push_back(f_neurons_C[i]);
817 break;
818 case 3 :
819 pd->f_neurons.push_back(f_neurons_D[i]);
820 break;
821 default:
822 log ("parent %d?\n", dna_donor);
823 NEVER_HERE();
824 }
825 }
826
827 pd->magic_numbers_size = kMagicNumbersSize;
828 pd->neuron_pool_size = kNeuronPoolSize;
829 pd->f_neuron_pool_size = kFNeuronPoolSize;
830
831}
832// Decides if mutation takes place and how intensive it will be
833MutatingIntensity ManagementData::do_mutate(const uint8_t is_preferred, const int16_t mutation_probability) {
834 if (is_preferred > 0) {
835 return MutatingIntensity::kAgressive;
836 }
837 if (std::rand() % mutation_probability == 0) {
838 return MutatingIntensity::kNormal;
839 }
840 return MutatingIntensity::kNo;
841}
842
843// Mutating, but all done on persistent data
844void ManagementData::mutate(const uint8_t pn) {
845
846 int16_t probability =
847 shift_weight_value(get_military_number_at(kMutationRatePosition), false) + 101;
848 if (probability > kUpperDefaultMutationLimit) {
849 probability = kUpperDefaultMutationLimit;
850 }
851 if (probability < kLowerDefaultMutationLimit) {
852 probability = kLowerDefaultMutationLimit;
853 }
854
855 set_military_number_at(kMutationRatePosition, probability - 101);
856
857 // decreasing probability (or rather increasing probability of mutation) if weaker player
858 if (ai_type == Widelands::AiType::kWeak) {
859 probability /= 2;
860 log("%2d: Weak mode, increasing mutation probability to 1 / %d\n", pn, probability);
861 } else if (ai_type == Widelands::AiType::kVeryWeak) {
862 probability /= 4;
863 log("%2d: Very weak mode, increasing mutation probability to 1 / %d\n", pn, probability);
864 }
865
866 assert(probability > 0 && probability <= 201);
867
868 log("%2d: mutating DNA with probability 1 / %3d:\n", pn, probability);
869
870 if (probability < 201) {
871
872 // Modifying pool of Military numbers
873 {
874 // Preferred numbers are ones that will be mutated agressively in full range [-kWeightRange, kWeightRange]
875 std::set<int32_t> preferred_numbers = {};
876
877 for (uint16_t i = 0; i < kMagicNumbersSize; i += 1) {
878 if (i == kMutationRatePosition) { // mutated above
879 continue;
880 }
881
882 const MutatingIntensity mutating_intensity = do_mutate(preferred_numbers.count(i) > 0, probability);
883
884 if (mutating_intensity != MutatingIntensity::kNo) {
885 const int16_t old_value = get_military_number_at(i);
886 const int16_t new_value = shift_weight_value(get_military_number_at(i), mutating_intensity == MutatingIntensity::kAgressive);
887 set_military_number_at(i, new_value);
888 log(" Magic number %3d: value changed: %4d -> %4d %s\n", i, old_value,
889 new_value, (mutating_intensity == MutatingIntensity::kAgressive) ? "aggressive" : "");
890 }
891 }
892 }
893
894 // Modifying pool of neurons
895 {
896 // Neurons to be mutated more agressively
897 std::set<int32_t> preferred_neurons = {};
898 for (auto& item : neuron_pool) {
899
900 const MutatingIntensity mutating_intensity = do_mutate(preferred_neurons.count(item.get_id()) > 0, probability);
901
902 if (mutating_intensity != MutatingIntensity::kNo) {
903 const int16_t old_value = item.get_weight();
904 if (std::rand() % 4 == 0) {
905 assert(!neuron_curves.empty());
906 item.set_type(std::rand() % neuron_curves.size());
907 pd->neuron_functs[item.get_id()] = item.get_type();
908 } else {
909 int16_t new_value = shift_weight_value(item.get_weight(), mutating_intensity == MutatingIntensity::kAgressive);
910 item.set_weight(new_value);
911 pd->neuron_weights[item.get_id()] = item.get_weight();
912 }
913 log(" Neuron %2d: weight: %4d -> %4d, new curve: %d %s\n", item.get_id(),
914 old_value, item.get_weight(), item.get_type(),
915 (mutating_intensity == MutatingIntensity::kAgressive) ? "aggressive" : "");
916
917 item.recalculate();
918 }
919 }
920 }
921
922 // Modifying pool of f-neurons
923 {
924 // FNeurons to be mutated more agressively
925 std::set<int32_t> preferred_f_neurons = {};
926 for (auto& item : f_neuron_pool) {
927 uint8_t changed_bits = 0;
928 // is this a preferred neuron
929 if (preferred_f_neurons.count(item.get_id()) > 0) {
930 for (uint8_t i = 0; i < kFNeuronBitSize; i += 1) {
931 if (std::rand() % 5 == 0) {
932 item.flip_bit(i);
933 changed_bits += 1;
934 }
935 }
936 } else { // normal mutation
937 for (uint8_t i = 0; i < kFNeuronBitSize; i += 1) {
938 if (std::rand() % (probability * 3) == 0) {
939 item.flip_bit(i);
940 changed_bits += 1;
941 }
942 }
943 }
944
945 if (changed_bits) {
946 pd->f_neurons[item.get_id()] = item.get_int();
947 log(" F-Neuron %2d: new value: %13ul, changed bits: %2d %s\n",
948 item.get_id(), item.get_int(), changed_bits,
949 (preferred_f_neurons.count(item.get_id()) > 0) ? "aggressive" : "");
950 }
951 }
952 }
953 }
954
955 test_consistency();
956}
957
958// Now we copy persistent to local
959void ManagementData::copy_persistent_to_local() {
960
961 assert(pd->neuron_weights.size() == kNeuronPoolSize);
962 assert(pd->neuron_functs.size() == kNeuronPoolSize);
963 neuron_pool.clear();
964 for (uint32_t i = 0; i < kNeuronPoolSize; i = i + 1) {
965 neuron_pool.push_back(Neuron(pd->neuron_weights[i], pd->neuron_functs[i], i));
966 }
967
968 assert(pd->f_neurons.size() == kFNeuronPoolSize);
969 f_neuron_pool.clear();
970 for (uint32_t i = 0; i < kFNeuronPoolSize; i = i + 1) {
971 f_neuron_pool.push_back(FNeuron(pd->f_neurons[i], i));
972 }
973
974 pd->magic_numbers_size = kMagicNumbersSize;
975 pd->neuron_pool_size = kNeuronPoolSize;
976 pd->f_neuron_pool_size = kFNeuronPoolSize;
977
978 test_consistency();
979 log(" ... DNA initialized\n");
980}
981
982void ManagementData::test_consistency(bool itemized) {
983
984 assert(pd->neuron_weights.size() == pd->neuron_pool_size);
985 assert(pd->neuron_functs.size() == pd->neuron_pool_size);
986 assert(neuron_pool.size() == pd->neuron_pool_size);
987 assert(neuron_pool.size() == kNeuronPoolSize);
988
989 assert(pd->magic_numbers_size == kMagicNumbersSize);
990 assert(pd->magic_numbers.size() == kMagicNumbersSize);
991
992 assert(pd->f_neurons.size() == pd->f_neuron_pool_size);
993 assert(f_neuron_pool.size() == pd->f_neuron_pool_size);
994 assert(f_neuron_pool.size() == kFNeuronPoolSize);
995
996 if (itemized) {
997 // comparing contents of neuron and fneuron pools
998 for (uint16_t i = 0; i < kNeuronPoolSize; i += 1) {
999 assert(pd->neuron_weights[i] == neuron_pool[i].get_weight());
1000 assert(pd->neuron_functs[i] == neuron_pool[i].get_type());
1001 assert(neuron_pool[i].get_id() == i);
1002 }
1003 for (uint16_t i = 0; i < kFNeuronPoolSize; i += 1) {
1004 assert(pd->f_neurons[i] == f_neuron_pool[i].get_int());
1005 assert(f_neuron_pool[i].get_id() == i);
1006 }
1007 }
1008
1009 return;
1010}
1011
1012// Print DNA data to console, used for training
1013// TODO(tiborb): Once we will have AI dumped into files, this should be removed
1014// Also, used only for training
1015void ManagementData::dump_data() {
1016 // dumping new numbers
1017 log(" actual military_numbers (%lu):\n {", pd->magic_numbers.size());
1018 uint16_t itemcounter = 1;
1019 uint16_t line_counter = 1;
1020 for (const auto& item : pd->magic_numbers) {
1021 log(" %3d%s", item, (&item != &pd->magic_numbers.back()) ? ", " : " ");
1022 if (itemcounter % 10 == 0) {
1023 log(" // AutoContent_%02d\n ", line_counter);
1024 line_counter += 1;
1025 }
1026 ++itemcounter;
1027 }
1028 log("}\n");
1029
1030 log(" actual neuron setup:\n ");
1031 log("{ ");
1032 itemcounter = 1;
1033 for (auto& item : neuron_pool) {
1034 log(" %3d%s", item.get_weight(), (&item != &neuron_pool.back()) ? ", " : " ");
1035 if (itemcounter % 10 == 0) {
1036 log(" // AutoContent_%02d\n ", line_counter);
1037 line_counter += 1;
1038 }
1039 ++itemcounter;
1040 }
1041 log("}\n { ");
1042 itemcounter = 1;
1043 for (auto& item : neuron_pool) {
1044 log(" %3d%s", item.get_type(), (&item != &neuron_pool.back()) ? ", " : " ");
1045 if (itemcounter % 10 == 0) {
1046 log(" // AutoContent_%02d\n ", line_counter);
1047 line_counter += 1;
1048 }
1049 ++itemcounter;
1050 }
1051 log("}\n");
1052
1053 log(" actual f-neuron setup:\n ");
1054 log("{ ");
1055 itemcounter = 1;
1056 for (auto& item : f_neuron_pool) {
1057 log(" %8u%s", item.get_int(), (&item != &f_neuron_pool.back()) ? ", " : " ");
1058 if (itemcounter % 10 == 0) {
1059 log(" // AutoContent_%02d\n ", line_counter);
1060 line_counter += 1;
1061 }
1062 ++itemcounter;
1063 }
1064 log("}\n");
1065}
1066
1067// Querying military number at a possition
1068int16_t ManagementData::get_military_number_at(uint8_t pos) {
1069 assert(pos < kMagicNumbersSize);
1070 return pd->magic_numbers[pos];
1071}
1072
1073// Setting military number (persistent numbers are used also for local use)
1074void ManagementData::set_military_number_at(const uint8_t pos, int16_t value) {
1075 assert(pos < kMagicNumbersSize);
1076
1077 while (pos >= pd->magic_numbers.size()) {
1078 pd->magic_numbers.push_back(0);
1079 }
1080
1081 value = Neuron::clip_weight_to_range(value);
1082 pd->magic_numbers[pos] = value;
277}1083}
2781084
279uint16_t MineTypesObserver::total_count() const {1085uint16_t MineTypesObserver::total_count() const {
@@ -292,7 +1098,7 @@
292 : due_time(time), id(t), priority(p), descr(d) {1098 : due_time(time), id(t), priority(p), descr(d) {
293}1099}
2941100
295bool SchedulerTask::operator<(SchedulerTask other) const {1101bool SchedulerTask::operator<(const SchedulerTask& other) const {
296 return priority > other.priority;1102 return priority > other.priority;
297}1103}
2981104
@@ -450,9 +1256,7 @@
450 }1256 }
451}1257}
4521258
453bool FlagsForRoads::get_winner(uint32_t* winner_hash, uint32_t pos) {1259bool FlagsForRoads::get_winner(uint32_t* winner_hash) {
454 assert(pos == 1 || pos == 2);
455 uint32_t counter = 1;
456 // If AI can ask for 2nd position, but there is only one viable candidate1260 // If AI can ask for 2nd position, but there is only one viable candidate
457 // we return the first one of course1261 // we return the first one of course
458 bool has_winner = false;1262 bool has_winner = false;
@@ -466,37 +1270,98 @@
466 *winner_hash = candidate_flag.coords_hash;1270 *winner_hash = candidate_flag.coords_hash;
467 has_winner = true;1271 has_winner = true;
4681272
469 if (counter == pos) {1273 if (std::rand() % 3 > 0) {
1274 // with probability of 2/3 we accept this flag
470 return true;1275 return true;
471 } else if (counter < pos) {
472 counter += 1;
473 } else {
474 break;
475 }1276 }
476 }1277 }
1278
477 if (has_winner) {1279 if (has_winner) {
478 return true;1280 return true;
479 }1281 }
480 return false;1282 return false;
481}1283}
4821284
483// This is an struct that stores strength of players, info on teams and provides some outputs from1285PlayersStrengths::PlayersStrengths() : update_time(0) {
484// these data1286}
485PlayersStrengths::PlayerStat::PlayerStat() : team_number(0), players_power(0) {1287
486}1288// Default constructor
487PlayersStrengths::PlayerStat::PlayerStat(Widelands::TeamNumber tc, uint32_t pp)1289PlayersStrengths::PlayerStat::PlayerStat()
488 : team_number(tc), players_power(pp) {1290 : team_number(0),
1291 is_enemy(false),
1292 players_power(0),
1293 old_players_power(0),
1294 old60_players_power(0),
1295 players_casualities(0) {
1296}
1297
1298// Constructor to be used
1299PlayersStrengths::PlayerStat::PlayerStat(Widelands::TeamNumber tc,
1300 bool e,
1301 uint32_t pp,
1302 uint32_t op,
1303 uint32_t o60p,
1304 uint32_t cs,
1305 uint32_t land,
1306 uint32_t oland,
1307 uint32_t o60l)
1308 : team_number(tc),
1309 is_enemy(e),
1310 players_power(pp),
1311 old_players_power(op),
1312 old60_players_power(o60p),
1313 players_casualities(cs),
1314 players_land(land),
1315 old_players_land(oland),
1316 old60_players_land(o60l) {
1317 last_time_seen = kNever;
489}1318}
4901319
491// Inserting/updating data1320// Inserting/updating data
492void PlayersStrengths::add(Widelands::PlayerNumber pn, Widelands::TeamNumber tn, uint32_t pp) {1321// We keep information for
493 if (all_stats.count(pn) == 0) {1322// - player strength / power
494 all_stats.insert(std::pair<Widelands::PlayerNumber, PlayerStat>(pn, PlayerStat(tn, pp)));1323// - player casualties
1324// - player land
1325// We store actual values, but for some of them we store also
1326// - old = 15 mins ago
1327// - old60 = 60 mins ago
1328// e.g. players_power / old_players_power / old60_players_power
1329// we recieve also player and team numbers to figure out if we are enemies, or in the team
1330void PlayersStrengths::add(Widelands::PlayerNumber pn,
1331 Widelands::PlayerNumber opn,
1332 Widelands::TeamNumber mytn,
1333 Widelands::TeamNumber pltn,
1334 uint32_t pp,
1335 uint32_t op,
1336 uint32_t o60p,
1337 uint32_t cs,
1338 uint32_t land,
1339 uint32_t oland,
1340 uint32_t o60l) {
1341 if (all_stats.count(opn) == 0) {
1342 bool enemy = false;
1343 if (pn == opn) {
1344 ;
1345 } else if (pltn == 0 || mytn == 0) {
1346 enemy = true;
1347 } else if (pltn != mytn) {
1348 enemy = true;
1349 }
1350 this_player_number = pn;
1351 all_stats.insert(std::make_pair(
1352 opn, PlayerStat(pltn, enemy, pp, op, o60p, cs, land, oland, o60l)));
495 } else {1353 } else {
496 all_stats[pn].players_power = pp;1354 all_stats[opn].players_power = pp;
1355 all_stats[opn].old_players_power = op;
1356 all_stats[opn].old60_players_power = o60p;
1357 all_stats[opn].players_casualities = cs;
1358 all_stats[opn].players_land = land;
1359 all_stats[opn].old_players_land = oland;
1360 all_stats[opn].old60_players_land = oland;
497 }1361 }
498}1362}
4991363
1364// After statistics for team members are updated, this calculation is needed
500void PlayersStrengths::recalculate_team_power() {1365void PlayersStrengths::recalculate_team_power() {
501 team_powers.clear();1366 team_powers.clear();
502 for (auto& item : all_stats) {1367 for (auto& item : all_stats) {
@@ -510,6 +1375,186 @@
510 }1375 }
511}1376}
5121377
1378// This just goes over information about all enemies and where they were seen the last time
1379bool PlayersStrengths::any_enemy_seen_lately(const uint32_t gametime) {
1380 for (auto& item : all_stats) {
1381 if (item.second.is_enemy && player_seen_lately(item.first, gametime)) {
1382 return true;
1383 }
1384 }
1385 return false;
1386}
1387
1388// Returns count of nearby enemies
1389uint8_t PlayersStrengths::enemies_seen_lately_count(const uint32_t gametime) {
1390 uint8_t count = 0;
1391 for (auto& item : all_stats) {
1392 if (item.second.is_enemy && player_seen_lately(item.first, gametime)) {
1393 count += 1;
1394 }
1395 }
1396 return count;
1397}
1398
1399// When we see enemy, we use this to store the time
1400void PlayersStrengths::set_last_time_seen(const uint32_t seentime, Widelands::PlayerNumber pn) {
1401 if (all_stats.count(pn) == 0) {
1402 return;
1403 }
1404 all_stats[pn].last_time_seen = seentime;
1405}
1406
1407bool PlayersStrengths::get_is_enemy(Widelands::PlayerNumber pn) {
1408 if (all_stats.count(pn) == 0) {
1409 // Should happen only rarely so we print a warning here
1410 log("%d: WARNING: player has no statistics yet\n", this_player_number);
1411 return false;
1412 }
1413 return all_stats[pn].is_enemy;
1414}
1415
1416// Was the player seen less then 2 minutes ago
1417bool PlayersStrengths::player_seen_lately(Widelands::PlayerNumber pn, const uint32_t gametime) {
1418 if (all_stats.count(pn) == 0) {
1419 // Should happen only rarely so we print a warning here
1420 log("%d: WARNING: player has no statistics yet\n", this_player_number);
1421 return false;
1422 }
1423 if (all_stats[pn].last_time_seen == kNever) {
1424 return false;
1425 }
1426 if (all_stats[pn].last_time_seen + (2U * 60U * 1000U) > gametime) {
1427 return true;
1428 }
1429 return false;
1430}
1431
1432// This is the strength of a player
1433uint32_t PlayersStrengths::get_player_power(Widelands::PlayerNumber pn) {
1434 if (all_stats.count(pn) > 0) {
1435 return all_stats[pn].players_power;
1436 };
1437 return 0;
1438}
1439
1440// This is the land size owned by player
1441uint32_t PlayersStrengths::get_player_land(Widelands::PlayerNumber pn) {
1442 if (all_stats.count(pn) > 0) {
1443 return all_stats[pn].players_land;
1444 };
1445 return 0;
1446}
1447
1448// Calculates the strength of the enemies seen within the last 2 minutes
1449uint32_t PlayersStrengths::get_visible_enemies_power(const uint32_t gametime) {
1450 uint32_t pw = 0;
1451 for (auto& item : all_stats) {
1452 if (get_is_enemy(item.first) && player_seen_lately(item.first, gametime)) {
1453 pw += item.second.players_power;
1454 }
1455 }
1456 return pw;
1457}
1458
1459uint32_t PlayersStrengths::get_enemies_average_power() {
1460 uint32_t sum = 0;
1461 uint8_t count = 0;
1462 for (auto& item : all_stats) {
1463 if (get_is_enemy(item.first)) {
1464 sum += item.second.players_power;
1465 ++count;
1466 }
1467 }
1468 if (count > 0) {
1469 return sum / count;
1470 }
1471 return 0;
1472}
1473
1474uint32_t PlayersStrengths::get_enemies_average_land() {
1475 uint32_t sum = 0;
1476 uint8_t count = 0;
1477 for (auto& item : all_stats) {
1478 if (get_is_enemy(item.first)) {
1479 sum += item.second.players_land;
1480 ++count;
1481 }
1482 }
1483 if (count > 0) {
1484 return sum / count;
1485 }
1486 return 0;
1487}
1488
1489// Strength of stronger player
1490uint32_t PlayersStrengths::get_enemies_max_power() {
1491 uint32_t power = 0;
1492 for (auto& item : all_stats) {
1493 if (get_is_enemy(item.first)) {
1494 power = std::max<uint32_t>(power, item.second.players_power);
1495 }
1496 }
1497 return power;
1498}
1499
1500uint32_t PlayersStrengths::get_enemies_max_land() {
1501 uint32_t land = 0;
1502 for (auto& item : all_stats) {
1503 if (get_is_enemy(item.first)) {
1504 land = std::max<uint32_t>(land, item.second.players_land);
1505 }
1506 }
1507 return land;
1508}
1509
1510uint32_t PlayersStrengths::get_old_player_power(Widelands::PlayerNumber pn) {
1511 if (all_stats.count(pn) > 0) {
1512 return all_stats[pn].old_players_power;
1513 }
1514 return 0;
1515}
1516
1517uint32_t PlayersStrengths::get_old60_player_power(Widelands::PlayerNumber pn) {
1518 if (all_stats.count(pn) > 0) {
1519 return all_stats[pn].old60_players_power;
1520 }
1521 return 0;
1522}
1523
1524uint32_t PlayersStrengths::get_old_player_land(Widelands::PlayerNumber pn) {
1525 if (all_stats.count(pn) == 0) {
1526 log(" %d: Players statistics are still empty\n", pn);
1527 return 0;
1528 }
1529 return all_stats[pn].old_players_land;
1530}
1531
1532uint32_t PlayersStrengths::get_old60_player_land(Widelands::PlayerNumber pn) {
1533 if (all_stats.count(pn) == 0) {
1534 log(" %d: Players statistics are still empty\n", pn);
1535 return 0;
1536 }
1537 return all_stats[pn].old60_players_land;
1538}
1539
1540uint32_t PlayersStrengths::get_old_visible_enemies_power(const uint32_t gametime) {
1541 uint32_t pw = 0;
1542 for (auto& item : all_stats) {
1543 if (get_is_enemy(item.first) && player_seen_lately(item.first, gametime)) {
1544 pw += item.second.old_players_power;
1545 }
1546 }
1547 return pw;
1548}
1549
1550// This is casualities of player
1551uint32_t PlayersStrengths::get_player_casualities(Widelands::PlayerNumber pn) {
1552 if (all_stats.count(pn) > 0) {
1553 return all_stats[pn].players_casualities;
1554 }
1555 return 0;
1556}
1557
513// This is strength of player plus third of strength of other members of his team1558// This is strength of player plus third of strength of other members of his team
514uint32_t PlayersStrengths::get_modified_player_power(Widelands::PlayerNumber pn) {1559uint32_t PlayersStrengths::get_modified_player_power(Widelands::PlayerNumber pn) {
515 uint32_t result = 0;1560 uint32_t result = 0;
@@ -517,19 +1562,24 @@
517 if (all_stats.count(pn) > 0) {1562 if (all_stats.count(pn) > 0) {
518 result = all_stats[pn].players_power;1563 result = all_stats[pn].players_power;
519 team = all_stats[pn].team_number;1564 team = all_stats[pn].team_number;
520 };1565 }
521 if (team > 0 && team_powers.count(team) > 0) {1566 if (team > 0 && team_powers.count(team) > 0) {
522 result = result + (team_powers[team] - result) / 3;1567 result = result + (team_powers[team] - result) / 3;
523 };1568 }
524 return result;1569 return result;
525}1570}
5261571
1572// Are the player in the same team
527bool PlayersStrengths::players_in_same_team(Widelands::PlayerNumber pl1,1573bool PlayersStrengths::players_in_same_team(Widelands::PlayerNumber pl1,
528 Widelands::PlayerNumber pl2) {1574 Widelands::PlayerNumber pl2) {
529 if (all_stats.count(pl1) > 0 && all_stats.count(pl2) > 0 && pl1 != pl2) {1575 assert(all_stats.count(pl1) > 0);
1576 assert(all_stats.count(pl2) > 0);
1577 if (pl1 == pl2) {
1578 return false;
1579 } else if (all_stats[pl1].team_number > 0 &&
1580 all_stats[pl1].team_number == all_stats[pl2].team_number) {
530 // team number 0 = no team1581 // team number 0 = no team
531 return all_stats[pl1].team_number > 0 &&1582 return true;
532 all_stats[pl1].team_number == all_stats[pl2].team_number;
533 } else {1583 } else {
534 return false;1584 return false;
535 }1585 }
@@ -551,4 +1601,19 @@
551 return my_strength > strongest_opponent_strength + 50;1601 return my_strength > strongest_opponent_strength + 50;
552}1602}
5531603
554} // namespace WIdelands1604// Update_time is used to prevent too frequent updates of statistics
1605void PlayersStrengths::set_update_time(const uint32_t gametime) {
1606 update_time = gametime;
1607}
1608
1609uint32_t PlayersStrengths::get_update_time() {
1610 return update_time;
1611}
1612
1613ProductionSiteObserver::ProductionSiteObserver()
1614 : no_resources_since(kNever),
1615 upgrade_pending(false),
1616 dismantle_pending_since(kNever) {
1617}
1618
1619} // namespace Widelands
5551620
=== modified file 'src/ai/ai_help_structs.h'
--- src/ai/ai_help_structs.h 2017-06-24 08:47:46 +0000
+++ src/ai/ai_help_structs.h 2017-07-03 17:39:38 +0000
@@ -21,6 +21,7 @@
21#define WL_AI_AI_HELP_STRUCTS_H21#define WL_AI_AI_HELP_STRUCTS_H
2222
23#include <list>23#include <list>
24#include <queue>
24#include <unordered_set>25#include <unordered_set>
2526
26#include "ai/ai_hints.h"27#include "ai/ai_hints.h"
@@ -43,6 +44,8 @@
4344
44enum class ExtendedBool : uint8_t { kUnset, kTrue, kFalse };45enum class ExtendedBool : uint8_t { kUnset, kTrue, kFalse };
4546
47enum class MutatingIntensity : uint8_t { kNo, kNormal, kAgressive };
48
46enum class BuildingNecessity : uint8_t {49enum class BuildingNecessity : uint8_t {
47 kForced,50 kForced,
48 kNeeded,51 kNeeded,
@@ -54,6 +57,33 @@
54 kForbidden57 kForbidden
55};58};
5659
60// A building type can have no, one or multiple of these attributes
61enum class BuildingAttribute : uint8_t {
62 kBakery,
63 kRanger,
64 kBuildable,
65 kLumberjack,
66 kPort,
67 kNeedsRocks,
68 kWell,
69 kNeedsCoast,
70 kHunter,
71 kFisher,
72 kShipyard,
73 kBarracks,
74 kSpaceConsumer,
75 kRecruitment,
76 kBuildingMatProducer,
77 kUpgradeSubstitutes,
78 kUpgradeExtends,
79 kLogRefiner,
80 kIronMine
81};
82
83enum class AiType : uint8_t { kVeryWeak, kWeak, kNormal };
84
85enum class ExpansionMode : uint8_t { kResources = 0, kSpace = 1, kEconomy = 2, kBoth = 3 };
86
57enum class AiModeBuildings : uint8_t { kAnotherAllowed, kOnLimit, kLimitExceeded };87enum class AiModeBuildings : uint8_t { kAnotherAllowed, kOnLimit, kLimitExceeded };
5888
59enum class SchedulerTaskId : uint8_t {89enum class SchedulerTaskId : uint8_t {
@@ -74,9 +104,28 @@
74 kCheckTrainingsites,104 kCheckTrainingsites,
75 kCountMilitaryVacant,105 kCountMilitaryVacant,
76 kCheckEnemySites,106 kCheckEnemySites,
107 kManagementUpdate,
108 kUpdateStats,
77 kUnset109 kUnset
78};110};
79111
112// This is a simplification of a curve, to avoid repeated calculation
113const std::vector<std::vector<int8_t>> neuron_curves = {
114 {0, 5, 10, 15, 20, 25, 30, 35, 40, 45, 50, 55, 60, 65, 70, 75, 80, 85, 90, 95, 100},
115 {0, 0, 1, 2, 4, 6, 9, 12, 16, 20, 25, 30, 36, 42, 49, 56, 64, 72, 81, 90, 100},
116 {0, 17, 25, 32, 38, 44, 49, 53, 58, 62, 66, 70, 74, 78, 81, 84, 88, 91, 94, 97, 100},
117};
118
119constexpr int kMagicNumbersSize = 150;
120constexpr int kNeuronPoolSize = 80;
121constexpr int kFNeuronPoolSize = 60;
122constexpr int kFNeuronBitSize = 32;
123constexpr int kMutationRatePosition = 42;
124// TODO(tiborb): this should be replaced by command line switch
125constexpr bool kAITrainingMode = false;
126
127constexpr uint32_t kNever = std::numeric_limits<uint32_t>::max();
128
80struct CheckStepRoadAI {129struct CheckStepRoadAI {
81 CheckStepRoadAI(Player* const pl, uint8_t const mc, bool const oe);130 CheckStepRoadAI(Player* const pl, uint8_t const mc, bool const oe);
82131
@@ -112,17 +161,14 @@
112 Game& game;161 Game& game;
113};162};
114163
115// When looking for unowned terrain to acquire, we are actually164// We need to count walkable fields owned by enemy
116// only interested in fields we can walk on.165struct FindEnemyNodeWalkable {
117// Fields should either be completely unowned or owned by an opposing player_166 FindEnemyNodeWalkable(Player* p, Game& g);
118struct FindNodeUnowned {
119 FindNodeUnowned(Player* p, Game& g, bool oe = false);
120167
121 bool accept(const Map&, const FCoords& fc) const;168 bool accept(const Map&, const FCoords& fc) const;
122169
123 Player* player;170 Player* player;
124 Game& game;171 Game& game;
125 bool only_enemies;
126};172};
127173
128// Sometimes we need to know how many nodes our allies owns174// Sometimes we need to know how many nodes our allies owns
@@ -140,7 +186,19 @@
140// pay speciall attention to fields where mines can be built.186// pay speciall attention to fields where mines can be built.
141// Fields should be completely unowned187// Fields should be completely unowned
142struct FindNodeUnownedMineable {188struct FindNodeUnownedMineable {
143 FindNodeUnownedMineable(Player* p, Game& g);189 FindNodeUnownedMineable(Player* p, Game& g, int32_t t = INVALID_INDEX);
190
191 bool accept(const Map&, const FCoords& fc) const;
192
193 Player* player;
194 Game& game;
195 int32_t ore_type;
196};
197
198// When looking for unowned terrain to acquire, we must
199// consider if any buildings can be built on unowned land.
200struct FindNodeUnownedBuildable {
201 FindNodeUnownedBuildable(Player* p, Game& g);
144202
145 bool accept(const Map&, const FCoords& fc) const;203 bool accept(const Map&, const FCoords& fc) const;
146204
@@ -216,6 +274,18 @@
216 int32_t distance;274 int32_t distance;
217};275};
218276
277struct EventTimeQueue {
278 EventTimeQueue();
279
280 void push(uint32_t);
281 uint32_t count(uint32_t);
282 void strip_old(uint32_t);
283
284private:
285 uint32_t duration_ = 20 * 60 * 1000;
286 std::queue<uint32_t> queue;
287};
288
219struct WalkableSpot {289struct WalkableSpot {
220 Coords coords;290 Coords coords;
221 bool has_flag;291 bool has_flag;
@@ -238,11 +308,17 @@
238308
239 bool preferred;309 bool preferred;
240 bool enemy_nearby;310 bool enemy_nearby;
311 bool enemy_accessible_;
241312
242 uint8_t unowned_land_nearby;313 bool enemy_wh_nearby;
314 uint16_t unowned_land_nearby;
315 uint16_t enemy_owned_land_nearby;
316 uint16_t unowned_buildable_spots_nearby;
317 uint16_t nearest_buildable_spot_nearby;
243 // to identify that field is too close to border and no production building should be built there318 // to identify that field is too close to border and no production building should be built there
244 bool near_border;319 bool near_border;
245 uint8_t unowned_mines_spots_nearby;320 uint16_t unowned_mines_spots_nearby;
321 uint16_t unowned_iron_mines_nearby;
246 uint8_t trees_nearby;322 uint8_t trees_nearby;
247 uint8_t rocks_nearby;323 uint8_t rocks_nearby;
248 int16_t water_nearby;324 int16_t water_nearby;
@@ -264,22 +340,29 @@
264 // are construction sites that will change this once they are built340 // are construction sites that will change this once they are built
265 int16_t military_in_constr_nearby;341 int16_t military_in_constr_nearby;
266 // actual count of soldiers in nearby buldings342 // actual count of soldiers in nearby buldings
267 int16_t area_military_presence;343 int16_t own_military_presence;
344 int16_t enemy_military_presence;
345 int16_t enemy_military_sites; // Including unfinished
346 int16_t ally_military_presence;
268 // stationed (manned) military buildings nearby347 // stationed (manned) military buildings nearby
269 int16_t military_stationed;348 int16_t military_stationed;
270 // stationed (manned) military buildings nearby
271 // unconnected buildings nearby349 // unconnected buildings nearby
272 bool unconnected_nearby;350 bool unconnected_nearby;
273 int16_t military_unstationed;351 int16_t military_unstationed;
274 bool is_portspace;352 int16_t own_non_military_nearby;
353 bool defense_msite_allowed;
354 Widelands::ExtendedBool is_portspace;
275 bool port_nearby; // to increase priority if a port is nearby,355 bool port_nearby; // to increase priority if a port is nearby,
276 // especially for new colonies356 // especially for new colonies
277 Widelands::ExtendedBool portspace_nearby; // prefer military buildings closer to the portspace357 Widelands::ExtendedBool portspace_nearby; // prefer military buildings closer to the portspace
278 int32_t max_buildcap_nearby;358 int32_t max_buildcap_nearby;
279 // it is not necessary to check resources (stones, fish...) too frequently as they do not change359 // It is not necessary to check resources (stones, fish...) too frequently as they do not change
280 // fast360 // fast. This stores the time of the last check.
281 // this stores time of last check
282 uint32_t last_resources_check_time;361 uint32_t last_resources_check_time;
362 int32_t military_score_;
363 bool inland;
364 uint16_t local_soldier_capacity;
365 bool is_militarysite;
283366
284 std::vector<uint8_t> consumers_nearby;367 std::vector<uint8_t> consumers_nearby;
285 std::vector<uint8_t> producers_nearby;368 std::vector<uint8_t> producers_nearby;
@@ -322,33 +405,27 @@
322 Widelands::AiModeBuildings aimode_limit_status();405 Widelands::AiModeBuildings aimode_limit_status();
323 bool buildable(Widelands::Player& p);406 bool buildable(Widelands::Player& p);
324407
408 // Convenience functions for is_what
409 bool is(BuildingAttribute) const;
410 void set_is(BuildingAttribute);
411 void unset_is(BuildingAttribute);
412
325 char const* name;413 char const* name;
326 Widelands::DescriptionIndex id;414 Widelands::DescriptionIndex id;
327 Widelands::BuildingDescr const* desc;415 Widelands::BuildingDescr const* desc;
328416
329 Type type;417 Type type;
330418
331 bool plants_trees;
332 bool recruitment; // is "producing" workers?
333 Widelands::BuildingNecessity new_building;419 Widelands::BuildingNecessity new_building;
334 uint32_t new_building_overdue;420 uint32_t new_building_overdue;
335 int32_t primary_priority;421 int32_t primary_priority;
336 bool is_buildable;422
337 bool need_trees; // lumberjack = true
338 bool need_rocks; // quarry = true
339 bool mines_water; // wells
340 bool need_water; // fisher, fish_breeder = true
341 bool is_hunter; // need to identify hunters
342 bool is_fisher; // need to identify fishers
343 bool is_port;
344 bool is_shipyard;
345 bool space_consumer; // farm, vineyard... = true
346 bool expansion_type; // military building used that can be used to control area423 bool expansion_type; // military building used that can be used to control area
347 bool fighting_type; // military building built near enemies424 bool fighting_type; // military building built near enemies
348 bool mountain_conqueror; // military building built near mountains425 bool mountain_conqueror; // military building built near mountains
349 uint32_t prohibited_till; // do not build before (ms)426 uint32_t prohibited_till; // do not build before (ms)
350 uint32_t forced_after; // do not wait until ware is needed427 uint32_t forced_after; // do not wait until ware is needed
351 TrainingSiteType trainingsite_type;428 uint8_t max_trainingsites_proportion;
352429
353 uint16_t unconnected_count; // to any warehouse (count of such buildings)430 uint16_t unconnected_count; // to any warehouse (count of such buildings)
354431
@@ -358,16 +435,9 @@
358435
359 std::vector<Widelands::DescriptionIndex> inputs;436 std::vector<Widelands::DescriptionIndex> inputs;
360 std::vector<Widelands::DescriptionIndex> outputs;437 std::vector<Widelands::DescriptionIndex> outputs;
438 std::vector<Widelands::DescriptionIndex> positions;
361 std::vector<Widelands::DescriptionIndex> critical_building_material;439 std::vector<Widelands::DescriptionIndex> critical_building_material;
362440
363 bool produces_building_material;
364
365 // an enhancement to this building:
366 // produces all wares as current building, and perhaps more
367 bool upgrade_substitutes;
368 // produces some additional wares
369 bool upgrade_extends;
370
371 // It seems that fish and meat are subsitutes (for trainingsites), so441 // It seems that fish and meat are subsitutes (for trainingsites), so
372 // when testing if a trainingsite is supplied enough442 // when testing if a trainingsite is supplied enough
373 // we count the wares together443 // we count the wares together
@@ -388,7 +458,7 @@
388 int32_t cnt_upgrade_pending; // number of buildings that are to be upgraded458 int32_t cnt_upgrade_pending; // number of buildings that are to be upgraded
389459
390 // used to track amount of wares produced by building460 // used to track amount of wares produced by building
391 uint32_t stocklevel;461 uint32_t stocklevel_count;
392 uint32_t stocklevel_time; // time when stocklevel_ was last time recalculated462 uint32_t stocklevel_time; // time when stocklevel_ was last time recalculated
393 uint32_t last_dismantle_time;463 uint32_t last_dismantle_time;
394 uint32_t construction_decision_time;464 uint32_t construction_decision_time;
@@ -397,25 +467,27 @@
397 uint32_t unoccupied_count;467 uint32_t unoccupied_count;
398468
399 bool build_material_shortage;469 bool build_material_shortage;
470
471private:
472 std::set<BuildingAttribute> is_what;
400};473};
401474
402struct ProductionSiteObserver {475struct ProductionSiteObserver {
476 ProductionSiteObserver();
403 Widelands::ProductionSite* site;477 Widelands::ProductionSite* site;
404 uint32_t built_time;478 uint32_t built_time;
405 uint32_t unoccupied_till;479 uint32_t unoccupied_till;
406 uint8_t stats_zero;
407 uint32_t no_resources_since;480 uint32_t no_resources_since;
408 bool upgrade_pending;481 bool upgrade_pending;
482 uint32_t dismantle_pending_since;
409 BuildingObserver* bo;483 BuildingObserver* bo;
410};484};
411485
412struct MilitarySiteObserver {486struct MilitarySiteObserver {
413 Widelands::MilitarySite* site;487 Widelands::MilitarySite* site;
414 BuildingObserver* bo;488 BuildingObserver* bo;
415 uint8_t checks;489 uint16_t understaffed;
416 // when considering attack most military sites are inside territory and should be skipped during490 uint32_t last_change; // to prevent switching the occupancy policy too fast
417 // evaluation
418 bool enemies_nearby;
419 uint32_t built_time;491 uint32_t built_time;
420};492};
421493
@@ -457,13 +529,15 @@
457529
458 bool is_warehouse;530 bool is_warehouse;
459 int32_t attack_soldiers_strength;531 int32_t attack_soldiers_strength;
532 int32_t attack_soldiers_competency;
460 int32_t defenders_strength;533 int32_t defenders_strength;
461 uint8_t stationed_soldiers;534 uint8_t stationed_soldiers;
462 uint32_t last_time_attackable;535 uint32_t last_time_seen;
463 uint32_t last_tested;536 uint32_t last_tested;
464 int16_t score;537 int16_t score;
465 Widelands::ExtendedBool mines_nearby;538 Widelands::ExtendedBool mines_nearby;
466 int16_t no_attack_counter;539 uint32_t last_time_attacked;
540 uint32_t attack_counter;
467};541};
468542
469// as all mines have 3 levels, AI does not know total count of mines per mined material543// as all mines have 3 levels, AI does not know total count of mines per mined material
@@ -475,6 +549,122 @@
475549
476 uint16_t in_construction;550 uint16_t in_construction;
477 uint16_t finished;551 uint16_t finished;
552 bool is_critical;
553 uint16_t unoccupied;
554};
555
556constexpr int kNeuronWeightLimit = 100;
557constexpr size_t kNeuronMaxPosition = 20;
558constexpr size_t kSecondParentProbability = 50;
559
560// A bunch of parameters used for trainig AI (for calculation of fitness function result)
561constexpr int16_t kCurrentLandDivider = 2;
562constexpr int16_t kLandDeltaMultiplier = 1;
563constexpr int16_t kBonus = 1000;
564constexpr int16_t kAttackersMultiplier = 1;
565constexpr int16_t kAttackBonus = 100;
566constexpr int16_t kTrainedSoldiersScore = 250;
567constexpr int16_t kConqueredWhBonus = 500;
568
569struct Neuron {
570 static int clip_weight_to_range(int w) {
571 assert(w < 125);
572 assert(w > -125);
573 return std::max(-kNeuronWeightLimit, std::min(kNeuronWeightLimit, w));
574 }
575
576 Neuron(int8_t, uint8_t, uint16_t);
577 void recalculate();
578 void set_weight(int8_t w);
579 int8_t get_weight() {
580 return weight;
581 }
582 int8_t get_result(size_t);
583 int8_t get_result_safe(int32_t, bool = false);
584 void set_type(uint8_t);
585 uint8_t get_type() {
586 return type;
587 }
588 uint16_t get_id() {
589 return id;
590 }
591
592private:
593 int8_t results[21]; // kPositions + 1
594 int8_t weight;
595 uint8_t type;
596 uint16_t id;
597};
598
599struct FNeuron {
600 FNeuron(uint32_t, uint16_t);
601
602 void flip_bit(uint8_t);
603 bool get_result(bool, bool, bool, bool bool4 = true, bool bool5 = true);
604 bool get_position(uint8_t);
605 uint32_t get_int();
606 uint16_t get_id() {
607 return id;
608 };
609
610private:
611 std::bitset<kFNeuronBitSize> core;
612 uint16_t id;
613};
614
615struct ExpansionType {
616 ExpansionType();
617
618 void set_expantion_type(ExpansionMode);
619 ExpansionMode get_expansion_type() {
620 return type;
621 };
622
623private:
624 ExpansionMode type;
625};
626
627// This is to keep all data related to AI magic numbers
628struct ManagementData {
629 ManagementData();
630
631 std::vector<Neuron> neuron_pool;
632 std::vector<FNeuron> f_neuron_pool;
633 Widelands::Player::AiPersistentState* pd;
634
635 void mutate(PlayerNumber = 0);
636 void new_dna_for_persistent(uint8_t, Widelands::AiType);
637 void copy_persistent_to_local();
638 void review(
639 uint32_t, PlayerNumber, uint32_t, uint32_t, uint32_t, uint16_t, int16_t, int16_t, uint16_t);
640 void dump_data();
641 uint16_t new_neuron_id() {
642 ++next_neuron_id;
643 return next_neuron_id - 1;
644 };
645 void reset_neuron_id() {
646 next_neuron_id = 0;
647 }
648 uint16_t new_bi_neuron_id() {
649 ++next_bi_neuron_id;
650 return next_bi_neuron_id - 1;
651 };
652 void reset_bi_neuron_id() {
653 next_bi_neuron_id = 0;
654 }
655 int16_t get_military_number_at(uint8_t);
656 void set_military_number_at(uint8_t, int16_t);
657 MutatingIntensity do_mutate(uint8_t, int16_t);
658 int8_t shift_weight_value(int8_t, bool = true);
659 void test_consistency(bool = false);
660
661private:
662 int32_t score;
663 uint8_t primary_parent;
664 uint16_t next_neuron_id;
665 uint16_t next_bi_neuron_id;
666 uint16_t performance_change;
667 Widelands::AiType ai_type;
478};668};
479669
480// this is used to count militarysites by their size670// this is used to count militarysites by their size
@@ -492,7 +682,7 @@
492 const uint8_t p,682 const uint8_t p,
493 const char* d);683 const char* d);
494684
495 bool operator<(SchedulerTask other) const;685 bool operator<(const SchedulerTask& other) const;
496686
497 uint32_t due_time;687 uint32_t due_time;
498 Widelands::SchedulerTaskId id;688 Widelands::SchedulerTaskId id;
@@ -560,34 +750,87 @@
560 // Updating walking distance over existing roads750 // Updating walking distance over existing roads
561 void set_road_distance(Widelands::Coords coords, int32_t distance);751 void set_road_distance(Widelands::Coords coords, int32_t distance);
562 // Finally we query the flag that we will build a road to752 // Finally we query the flag that we will build a road to
563 bool get_winner(uint32_t* winner_hash, uint32_t pos);753 bool get_winner(uint32_t* winner_hash);
564};754};
565755
566// This is a struct that stores strength of players, info on teams and provides some outputs from756// This is a struct that stores strength of players, info on teams and provides some outputs from
567// these data757// these data
568struct PlayersStrengths {758struct PlayersStrengths {
759private:
569 struct PlayerStat {760 struct PlayerStat {
570 PlayerStat();761 PlayerStat();
571 PlayerStat(Widelands::TeamNumber tc, uint32_t pp);762 PlayerStat(Widelands::TeamNumber tc,
763 bool en,
764 uint32_t pp,
765 uint32_t op,
766 uint32_t o60p,
767 uint32_t cs,
768 uint32_t land,
769 uint32_t oland,
770 uint32_t o60l);
572771
573 Widelands::TeamNumber team_number;772 Widelands::TeamNumber team_number;
773 bool is_enemy;
574 uint32_t players_power;774 uint32_t players_power;
775 uint32_t old_players_power;
776 uint32_t old60_players_power;
777 uint32_t players_casualities;
778 uint32_t last_time_seen;
779 uint32_t players_land;
780 uint32_t old_players_land;
781 uint32_t old60_players_land;
575 };782 };
576783
784public:
785 PlayersStrengths();
577 // Inserting/updating data786 // Inserting/updating data
578 void add(Widelands::PlayerNumber pn, Widelands::TeamNumber tn, uint32_t pp);787 void add(Widelands::PlayerNumber pn,
788 Widelands::PlayerNumber opn,
789 Widelands::TeamNumber mytn,
790 Widelands::TeamNumber pltn,
791 uint32_t pp,
792 uint32_t op,
793 uint32_t o60p,
794 uint32_t cs,
795 uint32_t land,
796 uint32_t oland,
797 uint32_t o60l);
579 void recalculate_team_power();798 void recalculate_team_power();
580799
581 // This is strength of player plus third of strength of other members of his team800 // This is strength of player plus third of strength of other members of his team
582 uint32_t get_modified_player_power(Widelands::PlayerNumber pn);801 uint32_t get_modified_player_power(Widelands::PlayerNumber pn);
802 uint32_t get_player_power(Widelands::PlayerNumber pn);
803 uint32_t get_old_player_power(Widelands::PlayerNumber pn);
804 uint32_t get_old60_player_power(Widelands::PlayerNumber pn);
805 uint32_t get_player_land(Widelands::PlayerNumber pn);
806 uint32_t get_old_player_land(Widelands::PlayerNumber pn);
807 uint32_t get_old60_player_land(Widelands::PlayerNumber pn);
808 uint32_t get_visible_enemies_power(uint32_t);
809 uint32_t get_enemies_average_power();
810 uint32_t get_enemies_average_land();
811 uint32_t get_enemies_max_power();
812 uint32_t get_enemies_max_land();
813 uint32_t get_old_visible_enemies_power(uint32_t);
814 uint32_t get_player_casualities(Widelands::PlayerNumber pn);
583 bool players_in_same_team(Widelands::PlayerNumber pl1, Widelands::PlayerNumber pl2);815 bool players_in_same_team(Widelands::PlayerNumber pl1, Widelands::PlayerNumber pl2);
584 bool strong_enough(Widelands::PlayerNumber pl);816 bool strong_enough(Widelands::PlayerNumber pl);
817 void set_last_time_seen(uint32_t, Widelands::PlayerNumber);
818 bool player_seen_lately(Widelands::PlayerNumber, uint32_t);
819 bool get_is_enemy(Widelands::PlayerNumber);
820 uint8_t enemies_seen_lately_count(uint32_t);
821 bool any_enemy_seen_lately(uint32_t);
822 PlayerNumber this_player_number;
823 void set_update_time(uint32_t);
824 uint32_t get_update_time();
585825
826private:
586 // This is the core part of this struct827 // This is the core part of this struct
587 std::map<Widelands::PlayerNumber, PlayerStat> all_stats;828 std::map<Widelands::PlayerNumber, PlayerStat> all_stats;
588829
589 // Number of team, sum of players' strength830 // Number of team, sum of players' strength
590 std::map<Widelands::TeamNumber, uint32_t> team_powers;831 std::map<Widelands::TeamNumber, uint32_t> team_powers;
832
833 uint32_t update_time;
591};834};
592} // namespace Widelands835} // namespace Widelands
593836
594837
=== modified file 'src/ai/ai_hints.cc'
--- src/ai/ai_hints.cc 2017-05-25 07:16:05 +0000
+++ src/ai/ai_hints.cc 2017-07-03 17:39:38 +0000
@@ -38,27 +38,19 @@
38 table->has_key("mountain_conqueror") ? table->get_bool("mountain_conqueror") : false),38 table->has_key("mountain_conqueror") ? table->get_bool("mountain_conqueror") : false),
39 shipyard_(table->has_key("shipyard") ? table->get_bool("shipyard") : false),39 shipyard_(table->has_key("shipyard") ? table->get_bool("shipyard") : false),
40 prohibited_till_(table->has_key("prohibited_till") ? table->get_int("prohibited_till") : 0),40 prohibited_till_(table->has_key("prohibited_till") ? table->get_int("prohibited_till") : 0),
41 basic_amount_(table->has_key("basic_amount") ? table->get_int("basic_amount") : 0),
41 // 10 days default42 // 10 days default
42 forced_after_(table->has_key("forced_after") ? table->get_int("forced_after") : 864000),43 forced_after_(table->has_key("forced_after") ? table->get_int("forced_after") : 864000),
43 mines_percent_(table->has_key("mines_percent") ? table->get_int("mines_percent") : 100),44 mines_percent_(table->has_key("mines_percent") ? table->get_int("mines_percent") : 100),
44 very_weak_ai_limit_(45 very_weak_ai_limit_(
45 table->has_key("very_weak_ai_limit") ? table->get_int("very_weak_ai_limit") : -1),46 table->has_key("very_weak_ai_limit") ? table->get_int("very_weak_ai_limit") : -1),
46 weak_ai_limit_(table->has_key("weak_ai_limit") ? table->get_int("weak_ai_limit") : -1),47 weak_ai_limit_(table->has_key("weak_ai_limit") ? table->get_int("weak_ai_limit") : -1),
47 trainingsite_type_(TrainingSiteType::kNoTS),
48 trainingsites_max_percent_(table->has_key("trainingsites_max_percent") ?48 trainingsites_max_percent_(table->has_key("trainingsites_max_percent") ?
49 table->get_int("trainingsites_max_percent") :49 table->get_int("trainingsites_max_percent") :
50 0) {50 0) {
51
52 if (table->has_key("trainingsite_type")) {
53 if (table->get_string("trainingsite_type") == "basic") {
54 trainingsite_type_ = TrainingSiteType::kBasic;
55 } else if (table->get_string("trainingsite_type") == "advanced") {
56 trainingsite_type_ = TrainingSiteType::kAdvanced;
57 }
58 }
59}51}
6052
61void BuildingHints::set_trainingsites_max_percent(uint8_t percent) {53void BuildingHints::set_trainingsites_max_percent(int percent) {
62 trainingsites_max_percent_ = percent;54 trainingsites_max_percent_ = percent;
63}55}
6456
6557
=== modified file 'src/ai/ai_hints.h'
--- src/ai/ai_hints.h 2017-06-24 08:47:46 +0000
+++ src/ai/ai_hints.h 2017-07-03 17:39:38 +0000
@@ -28,8 +28,6 @@
28#include "base/macros.h"28#include "base/macros.h"
29#include "scripting/lua_table.h"29#include "scripting/lua_table.h"
3030
31enum class TrainingSiteType : uint8_t { kNoTS = 0, kBasic = 1, kAdvanced = 2 };
32
33/// This struct is used to read out the data given in [aihints] section of a31/// This struct is used to read out the data given in [aihints] section of a
34/// buildings conf file. It is used to tell the computer player about the32/// buildings conf file. It is used to tell the computer player about the
35/// special properties of a building.33/// special properties of a building.
@@ -95,6 +93,10 @@
95 return prohibited_till_;93 return prohibited_till_;
96 }94 }
9795
96 uint32_t basic_amount() const {
97 return basic_amount_;
98 }
99
98 uint32_t get_forced_after() const {100 uint32_t get_forced_after() const {
99 return forced_after_;101 return forced_after_;
100 }102 }
@@ -111,11 +113,7 @@
111 return weak_ai_limit_;113 return weak_ai_limit_;
112 }114 }
113115
114 TrainingSiteType get_trainingsite_type() const {116 void set_trainingsites_max_percent(int percent);
115 return trainingsite_type_;
116 }
117
118 void set_trainingsites_max_percent(uint8_t percent);
119117
120 uint8_t trainingsites_max_percent() const;118 uint8_t trainingsites_max_percent() const;
121119
@@ -133,11 +131,11 @@
133 bool mountain_conqueror_;131 bool mountain_conqueror_;
134 bool shipyard_;132 bool shipyard_;
135 int32_t prohibited_till_;133 int32_t prohibited_till_;
134 uint32_t basic_amount_;
136 int32_t forced_after_;135 int32_t forced_after_;
137 int8_t mines_percent_;136 int8_t mines_percent_;
138 int16_t very_weak_ai_limit_;137 int16_t very_weak_ai_limit_;
139 int16_t weak_ai_limit_;138 int16_t weak_ai_limit_;
140 TrainingSiteType trainingsite_type_;
141 int trainingsites_max_percent_;139 int trainingsites_max_percent_;
142140
143 DISALLOW_COPY_AND_ASSIGN(BuildingHints);141 DISALLOW_COPY_AND_ASSIGN(BuildingHints);
144142
=== modified file 'src/ai/defaultai.cc'
--- src/ai/defaultai.cc 2017-06-24 20:22:19 +0000
+++ src/ai/defaultai.cc 2017-07-03 17:39:38 +0000
@@ -62,13 +62,16 @@
62constexpr int kMinBFCheckInterval = 5 * 1000;62constexpr int kMinBFCheckInterval = 5 * 1000;
63constexpr int kMinMFCheckInterval = 19 * 1000;63constexpr int kMinMFCheckInterval = 19 * 1000;
64constexpr int kMarineDecisionInterval = 20 * 1000;64constexpr int kMarineDecisionInterval = 20 * 1000;
65constexpr int kRemainingBasicBuildingsResetTime = 1 * 60 * 1000;
6566
66// following two are used for roads management, for creating shortcuts and dismantling dispensable67// following two are used for roads management, for creating shortcuts and dismantling dispensable
67// roads68// roads
68constexpr int32_t kSpotsTooLittle = 15;69constexpr int32_t kSpotsTooLittle = 15;
69constexpr int32_t kSpotsEnough = 25;70constexpr int32_t kSpotsEnough = 25;
7071
71// this is intended for map developers, by default should be off72constexpr uint16_t kTargetQuantCap = 30;
73
74// this is intended for map developers & testers, should be off by default
72constexpr bool kPrintStats = false;75constexpr bool kPrintStats = false;
7376
74// for scheduler77// for scheduler
@@ -81,37 +84,29 @@
81DefaultAI::VeryWeakImpl DefaultAI::very_weak_impl;84DefaultAI::VeryWeakImpl DefaultAI::very_weak_impl;
8285
83/// Constructor of DefaultAI86/// Constructor of DefaultAI
84DefaultAI::DefaultAI(Game& ggame, PlayerNumber const pid, DefaultAI::Type const t)87DefaultAI::DefaultAI(Game& ggame, PlayerNumber const pid, Widelands::AiType const t)
85 : ComputerPlayer(ggame, pid),88 : ComputerPlayer(ggame, pid),
86 type_(t),89 type_(t),
87 player_(nullptr),90 player_(nullptr),
88 tribe_(nullptr),91 tribe_(nullptr),
92 attackers_count_(0),
89 next_ai_think_(0),93 next_ai_think_(0),
90 scheduler_delay_counter_(0),94 scheduler_delay_counter_(0),
91 wood_policy_(WoodPolicy::kAllowRangers),95 wood_policy_(WoodPolicy::kAllowRangers),
92 num_prod_constructionsites(0),96 numof_psites_in_constr(0),
93 num_ports(0),97 num_ports(0),
94 numof_warehouses_(0),98 numof_warehouses_(0),
99 numof_warehouses_in_const_(0),
95 military_last_dismantle_(0),100 military_last_dismantle_(0),
96 military_last_build_(0),101 military_last_build_(0),
97 time_of_last_construction_(0),102 time_of_last_construction_(0),
98 next_mine_construction_due_(0),103 next_mine_construction_due_(0),
99 ts_basic_count_(0),104 fishers_count_(0),
100 ts_basic_const_count_(0),105 bakeries_count_(),
101 ts_advanced_count_(0),106 ts_finished_count_(0),
102 ts_advanced_const_count_(0),107 ts_in_const_count_(0),
103 ts_without_trainers_(0),108 ts_without_trainers_(0),
104 inhibit_road_building_(0),109 inhibit_road_building_(0),
105 last_road_dismantled_(0),
106 enemy_last_seen_(kNever),
107 vacant_mil_positions_(0),
108 last_attack_time_(0),
109 enemysites_check_delay_(60),
110 spots_(0),
111 new_buildings_stop_(false),
112 resource_necessity_territory_(100),
113 resource_necessity_mines_(100),
114 resource_necessity_water_(0),
115 resource_necessity_water_needed_(false),110 resource_necessity_water_needed_(false),
116 highest_nonmil_prio_(0),111 highest_nonmil_prio_(0),
117 seafaring_economy(false),112 seafaring_economy(false),
@@ -249,6 +244,8 @@
249244
250 const int32_t delay_time = gametime - taskPool.front().due_time;245 const int32_t delay_time = gametime - taskPool.front().due_time;
251246
247 Map& map = game().map();
248
252 // Here we decide how many jobs will be run now (none - 5)249 // Here we decide how many jobs will be run now (none - 5)
253 // in case no job is due now, it can be zero250 // in case no job is due now, it can be zero
254 uint32_t jobs_to_run_count = (delay_time < 0) ? 0 : 1;251 uint32_t jobs_to_run_count = (delay_time < 0) ? 0 : 1;
@@ -400,7 +397,7 @@
400 // checking 3 mines if possible397 // checking 3 mines if possible
401 {398 {
402 int32_t mines_to_check = (mines_.size() < 5) ? mines_.size() : 5;399 int32_t mines_to_check = (mines_.size() < 5) ? mines_.size() : 5;
403 for (int j = 0; j < mines_to_check; j += 1) {400 for (int j = 0; j < mines_to_check; ++j) {
404 // every run of check_mines_() checks one mine401 // every run of check_mines_() checks one mine
405 if (check_mines_(gametime)) {402 if (check_mines_(gametime)) {
406 // if significant change takes place do not go on403 // if significant change takes place do not go on
@@ -411,9 +408,11 @@
411 break;408 break;
412 case SchedulerTaskId::kCheckMilitarysites:409 case SchedulerTaskId::kCheckMilitarysites:
413 // just to be sure the value is reset410 // just to be sure the value is reset
414 // 4 seconds is really fine411 if (check_militarysites(gametime)) {
415 set_taskpool_task_time(gametime + 4 * 1000, SchedulerTaskId::kCheckMilitarysites);412 set_taskpool_task_time(gametime + 15 * 1000, SchedulerTaskId::kCheckMilitarysites);
416 check_militarysites(gametime);413 } else {
414 set_taskpool_task_time(gametime + 4 * 1000, SchedulerTaskId::kCheckMilitarysites);
415 }
417 break;416 break;
418 case SchedulerTaskId::kCheckTrainingsites:417 case SchedulerTaskId::kCheckTrainingsites:
419 set_taskpool_task_time(418 set_taskpool_task_time(
@@ -422,7 +421,7 @@
422 break;421 break;
423 case SchedulerTaskId::kCountMilitaryVacant:422 case SchedulerTaskId::kCountMilitaryVacant:
424 count_military_vacant_positions();423 count_military_vacant_positions();
425 set_taskpool_task_time(gametime + 45 * 1000, SchedulerTaskId::kCountMilitaryVacant);424 set_taskpool_task_time(gametime + 25 * 1000, SchedulerTaskId::kCountMilitaryVacant);
426 break;425 break;
427 case SchedulerTaskId::kWareReview:426 case SchedulerTaskId::kWareReview:
428 if (check_economies()) { // economies must be consistent427 if (check_economies()) { // economies must be consistent
@@ -435,13 +434,38 @@
435 if (check_economies()) { // economies must be consistent434 if (check_economies()) { // economies must be consistent
436 return;435 return;
437 }436 }
438 set_taskpool_task_time(gametime + 30 * 60 * 1000, SchedulerTaskId::kPrintStats);437 set_taskpool_task_time(gametime + 10 * 60 * 1000, SchedulerTaskId::kPrintStats);
439 print_stats();438 print_stats(gametime);
440 break;439 break;
441 case SchedulerTaskId::kCheckEnemySites:440 case SchedulerTaskId::kCheckEnemySites:
442 check_enemy_sites(gametime);441 check_enemy_sites(gametime);
443 set_taskpool_task_time(gametime + 19 * 1000, SchedulerTaskId::kCheckEnemySites);442 set_taskpool_task_time(gametime + 19 * 1000, SchedulerTaskId::kCheckEnemySites);
444 break;443 break;
444 case SchedulerTaskId::kManagementUpdate:
445 // This task is used for training the AI, so it should be usually disabled
446 { // statistics for spotted warehouses
447 uint16_t conquered_wh = 0;
448 for (auto coords : enemy_warehouses) {
449 if (get_land_owner(map, coords) == player_number()) {
450 ++conquered_wh;
451 }
452 };
453 if (!enemy_warehouses.empty())
454 log("Conquered warehouses: %d / %lu\n", conquered_wh, enemy_warehouses.size());
455 management_data.review(gametime, player_number(),
456 player_statistics.get_player_land(player_number()),
457 player_statistics.get_enemies_max_land(),
458 player_statistics.get_old60_player_land(player_number()),
459 attackers_count_, soldier_trained_log.count(gametime),
460 soldier_attacks_log.count(gametime), conquered_wh);
461 set_taskpool_task_time(
462 gametime + kManagementUpdateInterval, SchedulerTaskId::kManagementUpdate);
463 }
464 break;
465 case SchedulerTaskId::kUpdateStats:
466 update_player_stat(gametime);
467 set_taskpool_task_time(gametime + kStatUpdateInterval, SchedulerTaskId::kUpdateStats);
468 break;
445 case SchedulerTaskId::kUnset:469 case SchedulerTaskId::kUnset:
446 NEVER_HERE();470 NEVER_HERE();
447 }471 }
@@ -474,7 +498,92 @@
474498
475 const DescriptionIndex& nr_buildings = game().tribes().nrbuildings();499 const DescriptionIndex& nr_buildings = game().tribes().nrbuildings();
476500
477 // Collect information about the different buildings that our tribe can have501 // The data struct below is owned by Player object, the purpose is to have them saved therein
502 persistent_data = player_->get_mutable_ai_persistent_state();
503 management_data.pd = player_->get_mutable_ai_persistent_state();
504 const bool create_basic_buildings_list = (gametime < kRemainingBasicBuildingsResetTime);
505
506 if (persistent_data->initialized == kFalse) {
507 // As all data are initialized without given values, they must be populated with reasonable
508 // values first
509 persistent_data->colony_scan_area = kColonyScanStartArea;
510 persistent_data->trees_around_cutters = 0;
511 persistent_data->initialized = kTrue;
512 persistent_data->last_attacked_player = std::numeric_limits<int16_t>::max();
513 persistent_data->expedition_start_time = kNoExpedition;
514 persistent_data->ships_utilization = 200;
515 persistent_data->no_more_expeditions = kFalse;
516 persistent_data->target_military_score = 100;
517 persistent_data->least_military_score = 0;
518 persistent_data->ai_productionsites_ratio = std::rand() % 5 + 7;
519 persistent_data->ai_personality_mil_upper_limit = 100;
520
521 // all zeroes
522 assert(persistent_data->neuron_weights.empty());
523 assert(persistent_data->neuron_functs.empty());
524 assert(persistent_data->magic_numbers_size == 0);
525 assert(persistent_data->neuron_pool_size == 0);
526 assert(persistent_data->magic_numbers.empty());
527
528 // AI's DNA population
529 management_data.new_dna_for_persistent(player_number(), type_);
530 management_data.copy_persistent_to_local();
531 management_data.mutate(player_number());
532 if (kAITrainingMode) {
533 management_data.dump_data();
534 }
535
536 management_data.test_consistency(true);
537 assert(management_data.get_military_number_at(42) ==
538 management_data.get_military_number_at(kMutationRatePosition));
539
540 } else if (persistent_data->initialized == kTrue) {
541 // Doing some consistency checks
542 check_range<uint32_t>(
543 persistent_data->expedition_start_time, gametime, "expedition_start_time");
544 check_range<uint16_t>(persistent_data->ships_utilization, 0, 10000, "ships_utilization_");
545
546 // for backward consistency
547 if (persistent_data->ai_personality_mil_upper_limit <
548 persistent_data->target_military_score) {
549 persistent_data->ai_personality_mil_upper_limit = persistent_data->target_military_score;
550 }
551 if (persistent_data->least_military_score > persistent_data->target_military_score) {
552 persistent_data->least_military_score = persistent_data->target_military_score;
553 }
554
555 if (kAITrainingMode) {
556 log("%2d: reinitializing dna (kAITrainingMode set true)", player_number());
557 management_data.new_dna_for_persistent(player_number(), type_);
558 management_data.copy_persistent_to_local();
559 management_data.mutate(player_number());
560
561 } else {
562 management_data.copy_persistent_to_local();
563 }
564
565 management_data.test_consistency(true);
566 if (kAITrainingMode) {
567 management_data.dump_data();
568 }
569
570 log(" %2d: %lu basic buildings in savegame file. %s\n", player_number(),
571 persistent_data->remaining_basic_buildings.size(),
572 (create_basic_buildings_list) ?
573 "New list will be recreated though (kAITrainingMode is true)" :
574 "");
575
576 } else {
577 throw wexception("Corrupted AI data");
578 }
579
580 // Even if we have basic buildings from savefile, we ignore them and recreate them based
581 // on lua conf files
582 if (create_basic_buildings_list) {
583 persistent_data->remaining_basic_buildings.clear();
584 persistent_data->remaining_buildings_size = 0;
585 }
586
478 for (DescriptionIndex building_index = 0; building_index < nr_buildings; ++building_index) {587 for (DescriptionIndex building_index = 0; building_index < nr_buildings; ++building_index) {
479 const BuildingDescr& bld = *tribe_->get_building_descr(building_index);588 const BuildingDescr& bld = *tribe_->get_building_descr(building_index);
480 if (!tribe_->has_building(building_index) && bld.type() != MapObjectType::MILITARYSITE) {589 if (!tribe_->has_building(building_index) && bld.type() != MapObjectType::MILITARYSITE) {
@@ -494,7 +603,7 @@
494 bo.cnt_target = 1; // default for everything603 bo.cnt_target = 1; // default for everything
495 bo.cnt_limit_by_aimode = std::numeric_limits<int32_t>::max();604 bo.cnt_limit_by_aimode = std::numeric_limits<int32_t>::max();
496 bo.cnt_upgrade_pending = 0;605 bo.cnt_upgrade_pending = 0;
497 bo.stocklevel = 0;606 bo.stocklevel_count = 0;
498 bo.stocklevel_time = 0;607 bo.stocklevel_time = 0;
499 bo.last_dismantle_time = 0;608 bo.last_dismantle_time = 0;
500 // this is set to negative number, otherwise the AI would wait 25 sec609 // this is set to negative number, otherwise the AI would wait 25 sec
@@ -508,23 +617,41 @@
508 bo.unconnected_count = 0;617 bo.unconnected_count = 0;
509 bo.new_building_overdue = 0;618 bo.new_building_overdue = 0;
510 bo.primary_priority = 0;619 bo.primary_priority = 0;
511 bo.is_buildable = bld.is_buildable();620 if (bld.is_buildable()) {
512 bo.need_trees = bh.is_logproducer();621 bo.set_is(BuildingAttribute::kBuildable);
513 bo.need_rocks = bh.is_graniteproducer();622 }
514 bo.need_water = bh.get_needs_water();623 if (bh.is_logproducer()) {
515 bo.mines_water = bh.mines_water();624 bo.set_is(BuildingAttribute::kLumberjack);
516 bo.recruitment = bh.for_recruitment();625 }
517 bo.space_consumer = bh.is_space_consumer();626 if (bh.is_graniteproducer()) {
627 bo.set_is(BuildingAttribute::kNeedsRocks);
628 }
629 if (create_basic_buildings_list &&
630 bh.basic_amount() > 0) { // This is the very begining of the game
631 persistent_data->remaining_basic_buildings[bo.id] = bh.basic_amount();
632 ++persistent_data->remaining_buildings_size;
633 }
634 if (bh.get_needs_water()) {
635 bo.set_is(BuildingAttribute::kNeedsCoast);
636 }
637 if (bh.mines_water()) {
638 bo.set_is(BuildingAttribute::kWell);
639 }
640 if (bh.is_space_consumer()) {
641 bo.set_is(BuildingAttribute::kSpaceConsumer);
642 }
643 if (bh.for_recruitment()) {
644 bo.set_is(BuildingAttribute::kRecruitment);
645 }
518 bo.expansion_type = bh.is_expansion_type();646 bo.expansion_type = bh.is_expansion_type();
519 bo.fighting_type = bh.is_fighting_type();647 bo.fighting_type = bh.is_fighting_type();
520 bo.mountain_conqueror = bh.is_mountain_conqueror();648 bo.mountain_conqueror = bh.is_mountain_conqueror();
521 bo.prohibited_till = bh.get_prohibited_till() * 1000; // value in conf is in seconds649 bo.prohibited_till = bh.get_prohibited_till() * 1000; // value in conf is in seconds
522 bo.forced_after = bh.get_forced_after() * 1000; // value in conf is in seconds650 bo.forced_after = bh.get_forced_after() * 1000; // value in conf is in seconds
523 bo.is_port = bld.get_isport();651 if (bld.get_isport()) {
524 bo.trainingsite_type = TrainingSiteType::kNoTS;652 bo.set_is(BuildingAttribute::kPort);
525 bo.upgrade_substitutes = false;653 }
526 bo.upgrade_extends = false;654 bo.max_trainingsites_proportion = 100;
527 bo.produces_building_material = false;
528 bo.max_preciousness = 0;655 bo.max_preciousness = 0;
529 bo.max_needed_preciousness = 0;656 bo.max_needed_preciousness = 0;
530657
@@ -534,18 +661,16 @@
534661
535 // I just presume cut wood is named "log" in the game662 // I just presume cut wood is named "log" in the game
536 if (tribe_->safe_ware_index("log") == bo.production_hint) {663 if (tribe_->safe_ware_index("log") == bo.production_hint) {
537 bo.plants_trees = true;664 bo.set_is(BuildingAttribute::kRanger);
538 } else {
539 bo.plants_trees = false;
540 }665 }
541666
542 // Is total count of this building limited by AI mode?667 // Is total count of this building limited by AI mode?
543 if (type_ == DefaultAI::Type::kVeryWeak && bh.get_very_weak_ai_limit() >= 0) {668 if (type_ == Widelands::AiType::kVeryWeak && bh.get_very_weak_ai_limit() >= 0) {
544 bo.cnt_limit_by_aimode = bh.get_very_weak_ai_limit();669 bo.cnt_limit_by_aimode = bh.get_very_weak_ai_limit();
545 log(" %d: AI 'very weak' mode: applying limit %d building(s) for %s\n", player_number(),670 log(" %d: AI 'very weak' mode: applying limit %d building(s) for %s\n", player_number(),
546 bo.cnt_limit_by_aimode, bo.name);671 bo.cnt_limit_by_aimode, bo.name);
547 }672 }
548 if (type_ == DefaultAI::Type::kWeak && bh.get_weak_ai_limit() >= 0) {673 if (type_ == Widelands::AiType::kWeak && bh.get_weak_ai_limit() >= 0) {
549 bo.cnt_limit_by_aimode = bh.get_weak_ai_limit();674 bo.cnt_limit_by_aimode = bh.get_weak_ai_limit();
550 log(" %d: AI 'weak' mode: applying limit %d building(s) for %s\n", player_number(),675 log(" %d: AI 'weak' mode: applying limit %d building(s) for %s\n", player_number(),
551 bo.cnt_limit_by_aimode, bo.name);676 bo.cnt_limit_by_aimode, bo.name);
@@ -562,6 +687,11 @@
562 for (const DescriptionIndex& temp_output : prod.output_ware_types()) {687 for (const DescriptionIndex& temp_output : prod.output_ware_types()) {
563 bo.outputs.push_back(temp_output);688 bo.outputs.push_back(temp_output);
564 }689 }
690 for (const auto temp_position : prod.working_positions()) {
691 bo.positions.push_back(temp_position.first);
692 }
693
694 iron_ore_id = tribe_->ironore();
565695
566 if (bo.type == BuildingObserver::Type::kMine) {696 if (bo.type == BuildingObserver::Type::kMine) {
567 // get the resource needed by the mine697 // get the resource needed by the mine
@@ -575,23 +705,36 @@
575 if (mines_per_type.count(bo.mines) == 0) {705 if (mines_per_type.count(bo.mines) == 0) {
576 mines_per_type[bo.mines] = MineTypesObserver();706 mines_per_type[bo.mines] = MineTypesObserver();
577 }707 }
708 // Identify iron mines based on output
709 if (bo.outputs[0] == iron_ore_id) {
710 bo.set_is(BuildingAttribute::kIronMine);
711 mines_per_type[bo.mines].is_critical = true;
712 }
578 }713 }
579714
580 // here we identify hunters715 // here we identify hunters
581 if (bo.outputs.size() == 1 && tribe_->safe_ware_index("meat") == bo.outputs.at(0)) {716 if (bo.outputs.size() == 1 && tribe_->safe_ware_index("meat") == bo.outputs.at(0)) {
582 bo.is_hunter = true;717 bo.set_is(BuildingAttribute::kHunter);
583 } else {
584 bo.is_hunter = false;
585 }718 }
586719
587 // and fishers720 // and fishers
588 if (bo.outputs.size() == 1 && tribe_->safe_ware_index("fish") == bo.outputs.at(0)) {721 if (bo.outputs.size() == 1 && tribe_->safe_ware_index("fish") == bo.outputs.at(0)) {
589 bo.is_fisher = true;722 bo.set_is(BuildingAttribute::kFisher);
590 } else {
591 bo.is_fisher = false;
592 }723 }
593724
594 bo.is_shipyard = bh.is_shipyard();725 if (bh.is_shipyard()) {
726 bo.set_is(BuildingAttribute::kShipyard);
727 }
728 if (building_index == tribe_->barracks()) {
729 bo.set_is(BuildingAttribute::kBarracks);
730 }
731 if (building_index == tribe_->bakery()) {
732 bo.set_is(BuildingAttribute::kBakery);
733 }
734 // Identify refined log producer
735 if (bo.outputs.size() == 1 && bo.outputs[0] == tribe_->refinedlog()) {
736 bo.set_is(BuildingAttribute::kLogRefiner);
737 }
595738
596 // now we find out if the upgrade of the building is a full substitution739 // now we find out if the upgrade of the building is a full substitution
597 // (produces all wares as current one)740 // (produces all wares as current one)
@@ -607,10 +750,10 @@
607 }750 }
608 // now testing outputs of current building751 // now testing outputs of current building
609 // and comparing752 // and comparing
610 bo.upgrade_substitutes = true;753 bo.set_is(BuildingAttribute::kUpgradeSubstitutes);
611 for (DescriptionIndex ware : bo.outputs) {754 for (DescriptionIndex ware : bo.outputs) {
612 if (enh_outputs.count(ware) == 0) {755 if (enh_outputs.count(ware) == 0) {
613 bo.upgrade_substitutes = false;756 bo.unset_is(BuildingAttribute::kUpgradeSubstitutes);
614 break;757 break;
615 }758 }
616 }759 }
@@ -620,40 +763,50 @@
620 for (const DescriptionIndex& ware : bo.outputs) {763 for (const DescriptionIndex& ware : bo.outputs) {
621 cur_outputs.insert(ware);764 cur_outputs.insert(ware);
622 }765 }
623 bo.upgrade_extends = false;766 // Does upgraded building produce any different outputs?
624 for (DescriptionIndex ware : enh_outputs) {767 for (DescriptionIndex ware : enh_outputs) {
625 if (cur_outputs.count(ware) == 0) {768 if (cur_outputs.count(ware) == 0) {
626 bo.upgrade_extends = true;769 bo.set_is(BuildingAttribute::kUpgradeExtends);
627 break;770 break;
628 }771 }
629 }772 }
630 }773 }
631774
632 // now we identify producers of critical build materials775 // now we identify producers of critical build materials
633 // hardwood now
634 for (DescriptionIndex ware : bo.outputs) {776 for (DescriptionIndex ware : bo.outputs) {
635 // iterating over wares subsitutes777 // building material except for trivial material
636 if (tribe_->ware_index("wood") == ware || tribe_->ware_index("blackwood") == ware ||778 if (tribe_->is_construction_material(ware) &&
637 tribe_->ware_index("marble") == ware || tribe_->ware_index("planks") == ware) {779 !(ware == tribe_->rawlog() || ware == tribe_->granite())) {
638 bo.produces_building_material = true;780 bo.set_is(BuildingAttribute::kBuildingMatProducer);
639 }781 if (bo.type == BuildingObserver::Type::kMine) {
640 }782 has_critical_mines = true;
783 mines_per_type[bo.mines].is_critical = true;
784 }
785 }
786 }
787
788 for (const auto& temp_buildcosts : prod.buildcost()) {
789 // building material except for trivial material
790 if (tribe_->is_construction_material(temp_buildcosts.first) &&
791 !(temp_buildcosts.first == tribe_->rawlog() ||
792 temp_buildcosts.first == tribe_->granite())) {
793 bo.critical_building_material.push_back(temp_buildcosts.first);
794 }
795 }
796
641 continue;797 continue;
642 }798 }
643799
644 // now for every military building, we fill critical_building_material vector800 // now for every military building, we fill critical_building_material vector
645 // with critical construction wares801 // with critical construction wares
646 // non critical are excluded (see below)
647 if (bld.type() == MapObjectType::MILITARYSITE) {802 if (bld.type() == MapObjectType::MILITARYSITE) {
648 bo.type = BuildingObserver::Type::kMilitarysite;803 bo.type = BuildingObserver::Type::kMilitarysite;
649 const MilitarySiteDescr& milit = dynamic_cast<const MilitarySiteDescr&>(bld);804 const MilitarySiteDescr& milit = dynamic_cast<const MilitarySiteDescr&>(bld);
650 for (const auto& temp_buildcosts : milit.buildcost()) {805 for (const auto& temp_buildcosts : milit.buildcost()) {
651 // bellow are non-critical wares (well, various types of wood)806 // Below are non-critical wares (well, various types of wood)
652 if (tribe_->ware_index("log") == temp_buildcosts.first ||807 if (temp_buildcosts.first == tribe_->rawlog() ||
653 tribe_->ware_index("blackwood") == temp_buildcosts.first ||808 temp_buildcosts.first == tribe_->refinedlog())
654 tribe_->ware_index("planks") == temp_buildcosts.first)
655 continue;809 continue;
656
657 bo.critical_building_material.push_back(temp_buildcosts.first);810 bo.critical_building_material.push_back(temp_buildcosts.first);
658 }811 }
659 continue;812 continue;
@@ -666,6 +819,8 @@
666819
667 if (bld.type() == MapObjectType::TRAININGSITE) {820 if (bld.type() == MapObjectType::TRAININGSITE) {
668 bo.type = BuildingObserver::Type::kTrainingsite;821 bo.type = BuildingObserver::Type::kTrainingsite;
822 bo.max_trainingsites_proportion = bh.trainingsites_max_percent();
823 assert(bo.max_trainingsites_proportion <= 100);
669 const TrainingSiteDescr& train = dynamic_cast<const TrainingSiteDescr&>(bld);824 const TrainingSiteDescr& train = dynamic_cast<const TrainingSiteDescr&>(bld);
670 for (const auto& temp_input : train.input_wares()) {825 for (const auto& temp_input : train.input_wares()) {
671 bo.inputs.push_back(temp_input.first);826 bo.inputs.push_back(temp_input.first);
@@ -678,19 +833,17 @@
678 bo.substitute_inputs.insert(temp_input.first);833 bo.substitute_inputs.insert(temp_input.first);
679 }834 }
680835
836 // Creating vector with critical material, to be used to discourage
837 // building of new sites if ware is lacking
681 for (const auto& temp_buildcosts : train.buildcost()) {838 for (const auto& temp_buildcosts : train.buildcost()) {
682 // critical wares for trainingsites839 // building material except for trivial material
683 if (tribe_->ware_index("spidercloth") == temp_buildcosts.first ||840 if (!(temp_buildcosts.first == tribe_->rawlog() ||
684 tribe_->ware_index("gold") == temp_buildcosts.first ||841 temp_buildcosts.first == tribe_->refinedlog() ||
685 tribe_->ware_index("grout") == temp_buildcosts.first) {842 temp_buildcosts.first == tribe_->granite())) {
686 bo.critical_building_material.push_back(temp_buildcosts.first);843 bo.critical_building_material.push_back(temp_buildcosts.first);
687 }844 }
688 }845 }
689 }846 }
690 bo.trainingsite_type = bh.get_trainingsite_type();
691 // it would behave badly if no type was set
692 // make sure all TS have its type set properly in conf files
693 assert(bo.trainingsite_type != TrainingSiteType::kNoTS);
694 continue;847 continue;
695 }848 }
696849
@@ -700,6 +853,16 @@
700 }853 }
701 }854 }
702855
856 // We must verify that some buildings has been identified
857 // Also note that the AI assumes that some buildings are unique, if you want to
858 // create e.g. two barracks or bakeries, the impact on the AI must be considered
859 assert(count_buildings_with_attribute(BuildingAttribute::kBarracks) == 1);
860 assert(count_buildings_with_attribute(BuildingAttribute::kBakery) == 1);
861 assert(count_buildings_with_attribute(BuildingAttribute::kLogRefiner) == 1);
862 assert(count_buildings_with_attribute(BuildingAttribute::kIronMine) >= 1);
863 // If there will be a tribe with more than 3 mines of the same type, just increase the number
864 assert(count_buildings_with_attribute(BuildingAttribute::kIronMine) <= 3);
865
703 // atlanteans they consider water as a resource866 // atlanteans they consider water as a resource
704 // (together with mines, rocks and wood)867 // (together with mines, rocks and wood)
705 if (tribe_->name() == "atlanteans") {868 if (tribe_->name() == "atlanteans") {
@@ -743,13 +906,21 @@
743 "check unbuildable fields"));906 "check unbuildable fields"));
744 taskPool.push_back(SchedulerTask(std::max<uint32_t>(gametime, 15 * 60 * 1000),907 taskPool.push_back(SchedulerTask(std::max<uint32_t>(gametime, 15 * 60 * 1000),
745 SchedulerTaskId::kWareReview, 9, "wares review"));908 SchedulerTaskId::kWareReview, 9, "wares review"));
746 taskPool.push_back(SchedulerTask(std::max<uint32_t>(gametime, 30 * 60 * 1000),909 taskPool.push_back(SchedulerTask(std::max<uint32_t>(gametime, 10 * 60 * 1000),
747 SchedulerTaskId::kPrintStats, 9, "print statistics"));910 SchedulerTaskId::kPrintStats, 9, "print statistics"));
748 taskPool.push_back(SchedulerTask(std::max<uint32_t>(gametime, 1 * 60 * 1000),911 taskPool.push_back(SchedulerTask(std::max<uint32_t>(gametime, 1 * 60 * 1000),
749 SchedulerTaskId::kCountMilitaryVacant, 2,912 SchedulerTaskId::kCountMilitaryVacant, 2,
750 "count military vacant"));913 "count military vacant"));
751 taskPool.push_back(SchedulerTask(std::max<uint32_t>(gametime, 10 * 60 * 1000),914 taskPool.push_back(SchedulerTask(std::max<uint32_t>(gametime, 10 * 60 * 1000),
752 SchedulerTaskId::kCheckEnemySites, 6, "check enemy sites"));915 SchedulerTaskId::kCheckEnemySites, 6, "check enemy sites"));
916 if (kAITrainingMode) {
917 taskPool.push_back(SchedulerTask(std::max<uint32_t>(gametime, 10 * 1000),
918 SchedulerTaskId::kManagementUpdate, 8, "reviewing"));
919 }
920 taskPool.push_back(SchedulerTask(std::max<uint32_t>(gametime, 9 * 1000),
921 SchedulerTaskId::kUpdateStats, 6, "update player stats"));
922 taskPool.push_back(SchedulerTask(
923 std::max<uint32_t>(gametime, 10 * 1000), SchedulerTaskId::kUpdateStats, 15, "review"));
753924
754 Map& map = game().map();925 Map& map = game().map();
755926
@@ -821,7 +992,8 @@
821992
822 // blocking space consumers vicinity (when reloading a game)993 // blocking space consumers vicinity (when reloading a game)
823 for (const ProductionSiteObserver& ps_obs : productionsites) {994 for (const ProductionSiteObserver& ps_obs : productionsites) {
824 if (ps_obs.bo->space_consumer && !ps_obs.bo->plants_trees) {995 if (ps_obs.bo->is(BuildingAttribute::kSpaceConsumer) &&
996 !ps_obs.bo->is(BuildingAttribute::kRanger)) {
825 MapRegion<Area<FCoords>> mr(997 MapRegion<Area<FCoords>> mr(
826 map, Area<FCoords>(map.get_fcoords(ps_obs.site->get_position()), 4));998 map, Area<FCoords>(map.get_fcoords(ps_obs.site->get_position()), 4));
827 do {999 do {
@@ -830,45 +1002,19 @@
830 }1002 }
831 }1003 }
8321004
833 // The data struct below is owned by Player object, the purpose is to have them saved therein1005 // printing identified basic buildings if we are in the basic economy mode
834 persistent_data = player_->get_mutable_ai_persistent_state();1006 basic_economy_established = persistent_data->remaining_basic_buildings.empty();
8351007 if (!basic_economy_established) {
836 if (persistent_data->initialized == kFalse) {1008 log("%2d: Initializing in the basic economy mode, required buildings:\n", player_number());
837 // As all data are initialized without given values, they must be populated with reasonable1009 for (auto bb : persistent_data->remaining_basic_buildings) {
838 // values first1010 log(" %3d / %-25s- target %d\n", bb.first, get_building_observer(bb.first).name,
839 persistent_data->colony_scan_area = kColonyScanStartArea;1011 bb.second);
840 persistent_data->trees_around_cutters = 0;1012 }
841 persistent_data->initialized = kTrue;
842 persistent_data->last_attacked_player = std::numeric_limits<int16_t>::max();
843 persistent_data->expedition_start_time = kNoExpedition;
844 persistent_data->ships_utilization = 200;
845 persistent_data->no_more_expeditions = kFalse;
846 persistent_data->target_military_score = 0;
847 persistent_data->least_military_score = 100;
848 persistent_data->ai_personality_military_loneliness = std::rand() % 5 * 30 - 60;
849 persistent_data->ai_personality_attack_margin = std::max(std::rand() % 20 - 5, 0);
850 persistent_data->ai_productionsites_ratio = std::rand() % 5 + 7;
851 persistent_data->ai_personality_wood_difference = std::rand() % 40 - 20;
852 persistent_data->ai_personality_early_militarysites = std::rand() % 20 + 20;
853 persistent_data->last_soldier_trained = kNever;
854 } else if (persistent_data->initialized == kTrue) {
855 // Doing some consistency checks
856 check_range<uint32_t>(
857 persistent_data->expedition_start_time, gametime, "expedition_start_time");
858 check_range<uint16_t>(persistent_data->ships_utilization, 0, 10000, "ships_utilization_");
859 check_range<int16_t>(persistent_data->ai_personality_military_loneliness, -60, 60,
860 "ai_personality_military_loneliness");
861 check_range<int32_t>(
862 persistent_data->ai_personality_attack_margin, 15, "ai_personality_attack_margin");
863 check_range<uint32_t>(
864 persistent_data->ai_productionsites_ratio, 5, 15, "ai_productionsites_ratio");
865 check_range<int32_t>(persistent_data->ai_personality_wood_difference, -20, 19,
866 "ai_personality_wood_difference");
867 check_range<uint32_t>(persistent_data->ai_personality_early_militarysites, 20, 40,
868 "ai_personality_early_militarysites");
869 } else {
870 throw wexception("Corrupted AI data");
871 }1013 }
1014 assert(persistent_data->remaining_basic_buildings.size() ==
1015 persistent_data->remaining_buildings_size);
1016
1017 update_player_stat(gametime);
8721018
873 // Initialise the max duration of a single ship's expedition1019 // Initialise the max duration of a single ship's expedition
874 const uint32_t map_area = uint32_t(map.get_height()) * map.get_width();1020 const uint32_t map_area = uint32_t(map.get_height()) * map.get_width();
@@ -893,6 +1039,18 @@
893 // Current gametime is better then 'kNoExpedition'1039 // Current gametime is better then 'kNoExpedition'
894 persistent_data->expedition_start_time = gametime;1040 persistent_data->expedition_start_time = gametime;
895 }1041 }
1042
1043 // just to be sure we have iron mines identified
1044 assert(iron_ore_id != INVALID_INDEX);
1045
1046 productionsites_ratio_ = management_data.get_military_number_at(86) / 10 + 12;
1047
1048 // Just to be initialized
1049 soldier_status_ = SoldiersStatus::kEnough;
1050 vacant_mil_positions_average_ = 0;
1051 spots_avail.resize(4);
1052 trees_nearby_treshold_ = 3 + std::abs(management_data.get_military_number_at(121)) / 2;
1053 last_road_dismantled_ = 0;
896}1054}
8971055
898/**1056/**
@@ -1022,27 +1180,66 @@
1022}1180}
10231181
1024/// Updates one buildable field1182/// Updates one buildable field
1025void DefaultAI::update_buildable_field(BuildableField& field, uint16_t range, bool military) {1183void DefaultAI::update_buildable_field(BuildableField& field) {
1026 // look if there is any unowned land nearby1184 // look if there is any unowned land nearby
1027 Map& map = game().map();1185 Map& map = game().map();
1028 const uint32_t gametime = game().get_gametime();1186 const uint32_t gametime = game().get_gametime();
1029 FindNodeUnownedWalkable find_unowned_walkable(player_, game());1187 FindNodeUnownedWalkable find_unowned_walkable(player_, game());
1188 FindEnemyNodeWalkable find_enemy_owned_walkable(player_, game());
1189 FindNodeUnownedBuildable find_unowned_buildable(player_, game());
1030 FindNodeUnownedMineable find_unowned_mines_pots(player_, game());1190 FindNodeUnownedMineable find_unowned_mines_pots(player_, game());
1191 FindNodeUnownedMineable find_unowned_iron_mines(player_, game(), iron_ore_id);
1192 FindNodeAllyOwned find_ally(player_, game(), player_number());
1031 PlayerNumber const pn = player_->player_number();1193 PlayerNumber const pn = player_->player_number();
1032 const World& world = game().world();1194 const World& world = game().world();
1033 field.unowned_land_nearby =1195
1034 map.find_fields(Area<FCoords>(field.coords, range), nullptr, find_unowned_walkable);1196 constexpr uint16_t kProductionArea = 6;
1035 FindNodeAllyOwned find_ally(player_, game(), player_number());1197 constexpr uint16_t kBuildableSpotsCheckArea = 10;
1036 const int32_t AllyOwnedFields =1198 constexpr uint16_t kEnemyCheckArea = 16;
1037 map.find_fields(Area<FCoords>(field.coords, 3), nullptr, find_ally);1199 const uint16_t ms_enemy_check_area =
10381200 kEnemyCheckArea + std::abs(management_data.get_military_number_at(75)) / 10;
1039 field.near_border = false;1201 constexpr uint16_t kDistantResourcesArea = 20;
1040 if (AllyOwnedFields > 0) {1202
1203 uint16_t actual_enemy_check_area = kEnemyCheckArea;
1204 field.is_militarysite = false;
1205 if (field.coords.field->get_immovable()) {
1206 if (field.coords.field->get_immovable()->descr().type() ==
1207 Widelands::MapObjectType::MILITARYSITE) {
1208 field.is_militarysite = true;
1209 actual_enemy_check_area = ms_enemy_check_area;
1210 }
1211 }
1212
1213 field.unowned_land_nearby = map.find_fields(
1214 Area<FCoords>(field.coords, actual_enemy_check_area), nullptr, find_unowned_walkable);
1215
1216 field.enemy_owned_land_nearby = map.find_fields(
1217 Area<FCoords>(field.coords, actual_enemy_check_area), nullptr, find_enemy_owned_walkable);
1218
1219 field.nearest_buildable_spot_nearby = std::numeric_limits<uint16_t>::max();
1220 if (field.unowned_land_nearby > 0) {
1221 std::vector<Coords> found_buildable_fields;
1222
1223 field.unowned_buildable_spots_nearby =
1224 map.find_fields(Area<FCoords>(field.coords, kBuildableSpotsCheckArea),
1225 &found_buildable_fields, find_unowned_buildable);
1226 // Now iterate over fields to get nearest one
1227 for (auto& coords : found_buildable_fields) {
1228 const uint32_t cur_distance = map.calc_distance(coords, field.coords);
1229 if (cur_distance < field.nearest_buildable_spot_nearby) {
1230 field.nearest_buildable_spot_nearby = cur_distance;
1231 }
1232 }
1233 } else {
1234 field.unowned_buildable_spots_nearby = 0;
1235 }
1236
1237 // Is this near the border? Get rid of fields owned by ally
1238 if (map.find_fields(Area<FCoords>(field.coords, 3), nullptr, find_ally) ||
1239 map.find_fields(Area<FCoords>(field.coords, 3), nullptr, find_unowned_walkable)) {
1041 field.near_border = true;1240 field.near_border = true;
1042 } else if (field.unowned_land_nearby > 0) {1241 } else {
1043 if (map.find_fields(Area<FCoords>(field.coords, 4), nullptr, find_unowned_walkable) > 0) {1242 field.near_border = false;
1044 field.near_border = true;
1045 }
1046 }1243 }
10471244
1048 // are we going to count resources now?1245 // are we going to count resources now?
@@ -1054,26 +1251,39 @@
1054 field.last_resources_check_time = gametime;1251 field.last_resources_check_time = gametime;
1055 }1252 }
10561253
1057 // to save some CPU1254 // testing mines
1058 if (mines_.size() > 8 && !resource_count_now) {1255 if (resource_count_now) {
1059 field.unowned_mines_spots_nearby = 0;1256 uint32_t close_mines = map.find_fields(
1060 } else {1257 Area<FCoords>(field.coords, kProductionArea), nullptr, find_unowned_mines_pots);
1061 uint32_t close_mines =
1062 map.find_fields(Area<FCoords>(field.coords, 4), nullptr, find_unowned_mines_pots);
1063 uint32_t distant_mines =1258 uint32_t distant_mines =
1064 map.find_fields(Area<FCoords>(field.coords, (range + 6 < 14) ? 14 : range + 6), nullptr,1259 map.find_fields(Area<FCoords>(field.coords, kDistantResourcesArea), nullptr,
1260
1065 find_unowned_mines_pots);1261 find_unowned_mines_pots);
1066 distant_mines = distant_mines - close_mines;1262 distant_mines = distant_mines - close_mines;
1067 field.unowned_mines_spots_nearby = 4 * close_mines + distant_mines / 2;1263 field.unowned_mines_spots_nearby = 4 * close_mines + distant_mines / 2;
1068 if (distant_mines > 0) {1264 if (distant_mines > 0) {
1069 field.unowned_mines_spots_nearby += 15;1265 field.unowned_mines_spots_nearby += 15;
1070 }1266 }
1267 if (field.unowned_mines_spots_nearby > 0 &&
1268 // for performance considerations we count iron nodes only if we have less than 2 iron
1269 // mines now...
1270 (mines_per_type[iron_ore_id].in_construction + mines_per_type[iron_ore_id].finished) <=
1271 1) {
1272 // counting iron mines, if we have less than two iron mines
1273 field.unowned_iron_mines_nearby = map.find_fields(
1274 Area<FCoords>(field.coords, kDistantResourcesArea), nullptr, find_unowned_iron_mines);
1275 } else {
1276 field.unowned_iron_mines_nearby = 0;
1277 }
1071 }1278 }
10721279
1073 // identifying portspace fields1280 // identifying portspace fields
1074 if (!field.is_portspace) { // if we know it, no need to do it once more1281 if (field.is_portspace ==
1282 Widelands::ExtendedBool::kUnset) { // if we know it, no need to do it once more
1075 if (player_->get_buildcaps(field.coords) & BUILDCAPS_PORT) {1283 if (player_->get_buildcaps(field.coords) & BUILDCAPS_PORT) {
1076 field.is_portspace = true;1284 field.is_portspace = ExtendedBool::kTrue;
1285 } else {
1286 field.is_portspace = ExtendedBool::kFalse;
1077 }1287 }
1078 }1288 }
10791289
@@ -1090,15 +1300,20 @@
1090 }1300 }
10911301
1092 // testing if a port is nearby, such field will get a priority boost1302 // testing if a port is nearby, such field will get a priority boost
1093 uint16_t nearest_distance = std::numeric_limits<uint16_t>::max();1303 if (resource_count_now) { // misusing a bit
1094 for (const WarehouseSiteObserver& wh_obs : warehousesites) {1304 uint16_t nearest_distance = std::numeric_limits<uint16_t>::max();
1095 const uint16_t actual_distance = map.calc_distance(field.coords, wh_obs.site->get_position());1305 for (const WarehouseSiteObserver& wh_obs : warehousesites) {
1096 nearest_distance = std::min(nearest_distance, actual_distance);1306 if (wh_obs.bo->is(BuildingAttribute::kPort)) {
1097 }1307 const uint16_t actual_distance =
1098 if (nearest_distance < 15) {1308 map.calc_distance(field.coords, wh_obs.site->get_position());
1099 field.port_nearby = true;1309 nearest_distance = std::min(nearest_distance, actual_distance);
1100 } else {1310 }
1101 field.port_nearby = false;1311 }
1312 if (nearest_distance < 15) {
1313 field.port_nearby = true;
1314 } else {
1315 field.port_nearby = false;
1316 }
1102 }1317 }
11031318
1104 // testing fields in radius 1 to find biggest buildcaps.1319 // testing fields in radius 1 to find biggest buildcaps.
@@ -1115,119 +1330,63 @@
11151330
1116 assert((player_->get_buildcaps(field.coords) & BUILDCAPS_SIZEMASK) <= field.max_buildcap_nearby);1331 assert((player_->get_buildcaps(field.coords) & BUILDCAPS_SIZEMASK) <= field.max_buildcap_nearby);
11171332
1118 // collect information about resources in the area1333 // Testing surface water (once only)
1119 std::vector<ImmovableFound> immovables;1334 // TODO(GunChleoc): We can change the terrain by scripting, so we should work with notifications
1120 // Search in a radius of range1335 // here.
1121 map.find_immovables(Area<FCoords>(field.coords, range), &immovables);1336 // Let's leave this as it is for now for performance reasons - terrain change of water is
11221337 // currently only
1123 // Is this a general update or just for military consideration1338 // used in the Atlantean scenario.
1124 // (second is used in check_militarysites)1339 if (field.water_nearby == kUncalculated) {
1125 if (!military) {1340 assert(field.open_water_nearby == kUncalculated);
1126 int32_t const tree_attr = MapObjectDescr::get_attribute_id("tree");1341
1127 field.preferred = false;1342 FindNodeWater find_water(game().world());
1128 field.enemy_nearby = false;1343 field.water_nearby =
1129 field.area_military_capacity = 0;1344 map.find_fields(Area<FCoords>(field.coords, kProductionArea), nullptr, find_water);
1130 field.military_loneliness = 1000; // instead of floats(v-1345
1131 field.area_military_presence = 0;1346 if (field.water_nearby > 0) {
1132 field.military_stationed = 0;1347 FindNodeOpenWater find_open_water(game().world());
1133 field.unconnected_nearby = false;1348 field.open_water_nearby =
1134 field.trees_nearby = 0;1349 map.find_fields(Area<FCoords>(field.coords, kProductionArea), nullptr, find_open_water);
1135 field.space_consumers_nearby = 0;1350 }
1136 field.rangers_nearby = 0;1351
1137 field.producers_nearby.clear();1352 if (resource_necessity_water_needed_) { // for atlanteans
1138 field.producers_nearby.resize(wares.size());1353 field.distant_water = map.find_fields(Area<FCoords>(field.coords, kDistantResourcesArea),
1139 field.consumers_nearby.clear();1354 nullptr, find_water) -
1140 field.consumers_nearby.resize(wares.size());1355 field.water_nearby;
1141 field.supporters_nearby.clear();1356 assert(field.open_water_nearby <= field.water_nearby);
1142 field.supporters_nearby.resize(wares.size());1357 }
1143 std::vector<Coords> resource_list;1358 }
1144 std::vector<Bob*> critters_list;1359
11451360 FCoords fse;
1146 if (field.water_nearby == kUncalculated) {1361 map.get_neighbour(field.coords, WALK_SE, &fse);
1147 assert(field.open_water_nearby == kUncalculated);1362 field.preferred = false;
11481363 if (BaseImmovable const* const imm = fse.field->get_immovable()) {
1149 FindNodeWater find_water(game().world());1364 if (dynamic_cast<Flag const*>(imm) ||
1150 field.water_nearby = map.find_fields(Area<FCoords>(field.coords, 5), nullptr, find_water);1365 (dynamic_cast<Road const*>(imm) && (fse.field->nodecaps() & BUILDCAPS_FLAG))) {
11511366 field.preferred = true;
1152 if (field.water_nearby > 0) {1367 }
1153 FindNodeOpenWater find_open_water(game().world());1368 }
1154 field.open_water_nearby =1369
1155 map.find_fields(Area<FCoords>(field.coords, 5), nullptr, find_open_water);1370 // counting fields with fish
1156 }1371 if (field.water_nearby > 0 && (field.fish_nearby == kUncalculated || resource_count_now)) {
11571372 field.fish_nearby = map.find_fields(Area<FCoords>(field.coords, kProductionArea), nullptr,
1158 if (resource_necessity_water_needed_) { // for atlanteans1373 FindNodeResource(world.get_resource("fish")));
1159 field.distant_water =1374 }
1160 map.find_fields(Area<FCoords>(field.coords, 14), nullptr, find_water) -1375
1161 field.water_nearby;1376 // Counting resources that do not change fast
1162 assert(field.open_water_nearby <= field.water_nearby);1377 if (resource_count_now) {
1163 }1378 // Counting fields with critters (game)
1164 }1379 field.critters_nearby =
11651380 map.find_bobs(Area<FCoords>(field.coords, kProductionArea), nullptr, FindBobCritter());
1166 // counting fields with fish
1167 if (field.water_nearby > 0 && (field.fish_nearby == kUncalculated || resource_count_now)) {
1168 map.find_fields(Area<FCoords>(field.coords, 6), &resource_list,
1169 FindNodeResource(world.get_resource("fish")));
1170 field.fish_nearby = resource_list.size();
1171 }
1172
1173 // counting fields with critters (game)
1174 // not doing this always, this does not change fast
1175 if (resource_count_now) {
1176 map.find_bobs(Area<FCoords>(field.coords, 6), &critters_list, FindBobCritter());
1177 field.critters_nearby = critters_list.size();
1178 }
1179
1180 FCoords fse;
1181 map.get_neighbour(field.coords, WALK_SE, &fse);
1182
1183 if (BaseImmovable const* const imm = fse.field->get_immovable()) {
1184 if (dynamic_cast<Flag const*>(imm) ||
1185 (dynamic_cast<Road const*>(imm) && (fse.field->nodecaps() & BUILDCAPS_FLAG))) {
1186 field.preferred = true;
1187 }
1188 }
1189
1190 for (uint32_t i = 0; i < immovables.size(); ++i) {
1191 const BaseImmovable& base_immovable = *immovables.at(i).object;
1192
1193 if (upcast(PlayerImmovable const, player_immovable, &base_immovable)) {
1194
1195 // TODO(unknown): Only continue; if this is an opposing site
1196 // allied sites should be counted for military influence
1197 if (player_immovable->owner().player_number() != pn) {
1198 if (player_->is_hostile(player_immovable->owner())) {
1199 field.enemy_nearby = true;
1200 }
1201
1202 continue;
1203 }
1204 // here we identify the buiding (including expected building if constructionsite)
1205 // and calculate some statistics about nearby buildings
1206 if (upcast(ProductionSite const, productionsite, player_immovable)) {
1207 BuildingObserver& bo = get_building_observer(productionsite->descr().name().c_str());
1208 consider_productionsite_influence(field, immovables.at(i).coords, bo);
1209 }
1210 if (upcast(ConstructionSite const, constructionsite, player_immovable)) {
1211 const BuildingDescr& target_descr = constructionsite->building();
1212 BuildingObserver& bo = get_building_observer(target_descr.name().c_str());
1213 consider_productionsite_influence(field, immovables.at(i).coords, bo);
1214 }
1215 }
1216
1217 if (immovables.at(i).object->has_attribute(tree_attr)) {
1218 ++field.trees_nearby;
1219 }
1220 }
12211381
1222 // Rocks are not renewable, we will count them only if previous state is nonzero1382 // Rocks are not renewable, we will count them only if previous state is nonzero
1223 if (field.rocks_nearby > 0 && resource_count_now) {1383 if (field.rocks_nearby > 0) {
12241384 field.rocks_nearby = map.find_immovables(
1225 field.rocks_nearby =1385 Area<FCoords>(map.get_fcoords(field.coords), kProductionArea), nullptr,
1226 map.find_immovables(Area<FCoords>(map.get_fcoords(field.coords), 6), nullptr,1386 FindImmovableAttribute(MapObjectDescr::get_attribute_id("rocks")));
1227 FindImmovableAttribute(MapObjectDescr::get_attribute_id("rocks")));1387
12281388 // adding 5 if rocks found
1229 // adding 10 if rocks found1389 field.rocks_nearby = (field.rocks_nearby > 0) ? field.rocks_nearby + 2 : 0;
1230 field.rocks_nearby = (field.rocks_nearby > 0) ? field.rocks_nearby + 10 : 0;
1231 }1390 }
12321391
1233 // ground water is not renewable and its amount can only fall, we will count them only if1392 // ground water is not renewable and its amount can only fall, we will count them only if
@@ -1235,47 +1394,136 @@
1235 if (field.ground_water > 0) {1394 if (field.ground_water > 0) {
1236 field.ground_water = field.coords.field->get_resources_amount();1395 field.ground_water = field.coords.field->get_resources_amount();
1237 }1396 }
1238 }1397
12391398 // Counting trees nearby
1240 // The following is done always (regardless of military or not)1399 int32_t const tree_attr = MapObjectDescr::get_attribute_id("tree");
12411400 field.trees_nearby =
1242 // We get immovables with higher radius1401 map.find_immovables(Area<FCoords>(map.get_fcoords(field.coords), kProductionArea), nullptr,
1243 immovables.clear();1402 FindImmovableAttribute(tree_attr));
1244 map.find_immovables(Area<FCoords>(field.coords, (range < 11) ? 11 : range), &immovables);1403 }
1404
1405 // resetting some values
1406 field.enemy_nearby =
1407 (field.enemy_owned_land_nearby > std::abs(management_data.get_military_number_at(41) / 4)) ?
1408 true :
1409 false;
1410 if (field.enemy_owned_land_nearby == 0) {
1411 assert(!field.enemy_nearby);
1412 }
1413
1414 // resetting a bunch of values for the field
1415 field.ally_military_presence = 0;
1416 field.area_military_capacity = 0;
1417 field.consumers_nearby.clear();
1418 field.consumers_nearby.resize(wares.size());
1419 field.enemy_military_presence = 0;
1420 field.enemy_military_sites = 0;
1421 field.enemy_wh_nearby = false;
1422 field.military_in_constr_nearby = 0;
1423 field.military_loneliness = 1000;
1245 field.military_stationed = 0;1424 field.military_stationed = 0;
1246 field.military_unstationed = 0;1425 field.military_unstationed = 0;
1247 field.military_in_constr_nearby = 0;1426 field.own_military_presence = 0;
1248 field.area_military_capacity = 0;1427 field.own_non_military_nearby = 0;
1249 field.military_loneliness = 1000;1428 field.producers_nearby.clear();
1250 field.area_military_presence = 0;1429 field.producers_nearby.resize(wares.size());
1430 field.rangers_nearby = 0;
1431 field.space_consumers_nearby = 0;
1432 field.supporters_nearby.clear();
1433 field.supporters_nearby.resize(wares.size());
1251 field.unconnected_nearby = false;1434 field.unconnected_nearby = false;
12521435
1436 // collect information about productionsites nearby
1437 std::vector<ImmovableFound> immovables;
1438 // Search in a radius of range
1439 map.find_immovables(Area<FCoords>(field.coords, kProductionArea + 2), &immovables);
1440
1441 // function seems to return duplicates, so we will use serial numbers to filter them out
1442 std::set<uint32_t> unique_serials;
1443
1444 for (uint32_t i = 0; i < immovables.size(); ++i) {
1445 const BaseImmovable& base_immovable = *immovables.at(i).object;
1446 if (!unique_serials.insert(base_immovable.serial()).second) {
1447 continue; // serial was not inserted in the set, so this is a duplicate
1448 }
1449
1450 if (upcast(PlayerImmovable const, player_immovable, &base_immovable)) {
1451
1452 // TODO(unknown): Only continue if this is an opposing site
1453 // allied sites should be counted for military influence
1454 if (player_immovable->owner().player_number() != pn) {
1455 continue;
1456 }
1457 // here we identify the buiding (including expected building if constructionsite)
1458 // and calculate some statistics about nearby buildings
1459 if (player_immovable->descr().type() == MapObjectType::PRODUCTIONSITE) {
1460 BuildingObserver& bo = get_building_observer(player_immovable->descr().name().c_str());
1461 consider_productionsite_influence(field, immovables.at(i).coords, bo);
1462 } else if (upcast(ConstructionSite const, constructionsite, player_immovable)) {
1463 const BuildingDescr& target_descr = constructionsite->building();
1464 BuildingObserver& bo = get_building_observer(target_descr.name().c_str());
1465 consider_productionsite_influence(field, immovables.at(i).coords, bo);
1466 }
1467 }
1468 }
1469
1470 // Now testing military aspects
1471 immovables.clear();
1472 map.find_immovables(Area<FCoords>(field.coords, actual_enemy_check_area), &immovables);
1473
1253 // We are interested in unconnected immovables, but we must be also close to connected ones1474 // We are interested in unconnected immovables, but we must be also close to connected ones
1254 bool any_connected_imm = false;1475 bool any_connected_imm = false;
1255 bool any_unconnected_imm = false;1476 bool any_unconnected_imm = false;
1477 unique_serials.clear();
12561478
1257 for (uint32_t i = 0; i < immovables.size(); ++i) {1479 for (uint32_t i = 0; i < immovables.size(); ++i) {
1258
1259 const BaseImmovable& base_immovable = *immovables.at(i).object;1480 const BaseImmovable& base_immovable = *immovables.at(i).object;
12601481
1261 // testing if it is enemy-owned field1482 if (!unique_serials.insert(base_immovable.serial()).second) {
1262 // TODO(unknown): count such fields...1483 continue; // serial was not inserted in the set, so this is duplicate
1263 if (upcast(PlayerImmovable const, player_immovable, &base_immovable)) {
1264
1265 // TODO(unknown): Only continue; if this is an opposing site
1266 // allied sites should be counted for military influence
1267 if (player_immovable->owner().player_number() != pn) {
1268 if (player_->is_hostile(player_immovable->owner())) {
1269 field.enemy_nearby = true;
1270 }
1271 continue;
1272 }
1273 }1484 }
12741485
1275 // if we are here, immovable is ours1486 // testing if immovable is owned by someone else and collecting some statistics
1276 if (upcast(Building const, building, &base_immovable)) {1487 if (upcast(Building const, building, &base_immovable)) {
12771488
1278 // connected to warehouse1489 const PlayerNumber bpn = building->owner().player_number();
1490 if (player_statistics.get_is_enemy(bpn)) { // owned by enemy
1491 assert(!player_statistics.players_in_same_team(bpn, pn));
1492 field.enemy_nearby = true;
1493 if (upcast(MilitarySite const, militarysite, building)) {
1494 field.enemy_military_presence +=
1495 militarysite->soldier_control()->stationed_soldiers().size();
1496 ++field.enemy_military_sites;
1497 }
1498 if (upcast(ConstructionSite const, constructionsite, building)) {
1499 const BuildingDescr& target_descr = constructionsite->building();
1500 if (target_descr.type() == MapObjectType::MILITARYSITE) {
1501 ++field.enemy_military_sites;
1502 }
1503 }
1504
1505 // Warehouses are counted here too as they can host soldiers as well
1506 if (upcast(Warehouse const, warehouse, building)) {
1507 field.enemy_military_presence +=
1508 warehouse->soldier_control()->stationed_soldiers().size();
1509 ++field.enemy_military_sites;
1510 field.enemy_wh_nearby = true;
1511 enemy_warehouses.insert(building->get_position().hash());
1512 }
1513 continue;
1514 } else if (bpn != pn) { // it is an ally
1515 assert(!player_statistics.get_is_enemy(bpn));
1516 if (upcast(MilitarySite const, militarysite, building)) {
1517 field.ally_military_presence +=
1518 militarysite->soldier_control()->stationed_soldiers().size();
1519 }
1520 continue;
1521 }
1522
1523 // if we are here, the immovable is ours
1524 assert(building->owner().player_number() == pn);
1525
1526 // connected to a warehouse
1279 bool connected = !building->get_economy()->warehouses().empty();1527 bool connected = !building->get_economy()->warehouses().empty();
1280 if (connected) {1528 if (connected) {
1281 any_connected_imm = true;1529 any_connected_imm = true;
@@ -1297,7 +1545,7 @@
1297 }1545 }
1298 }1546 }
1299 } else if (!connected) {1547 } else if (!connected) {
1300 // we dont care about unconnected constructionsites1548 // we don't care about unconnected constructionsites
1301 any_unconnected_imm = true;1549 any_unconnected_imm = true;
1302 }1550 }
13031551
@@ -1308,7 +1556,7 @@
1308 if (radius > dist) {1556 if (radius > dist) {
1309 field.area_military_capacity +=1557 field.area_military_capacity +=
1310 militarysite->soldier_control()->max_soldier_capacity();1558 militarysite->soldier_control()->max_soldier_capacity();
1311 field.area_military_presence +=1559 field.own_military_presence +=
1312 militarysite->soldier_control()->stationed_soldiers().size();1560 militarysite->soldier_control()->stationed_soldiers().size();
13131561
1314 if (militarysite->soldier_control()->stationed_soldiers().empty()) {1562 if (militarysite->soldier_control()->stationed_soldiers().empty()) {
@@ -1321,12 +1569,241 @@
1321 field.military_loneliness *= static_cast<double_t>(dist) / radius;1569 field.military_loneliness *= static_cast<double_t>(dist) / radius;
1322 }1570 }
1323 }1571 }
1572 } else {
1573 ++field.own_non_military_nearby;
1324 }1574 }
1325 }1575 }
1326 }1576 }
1577
1578 assert(field.military_loneliness <= 1000);
1579
1327 if (any_unconnected_imm && any_connected_imm && field.military_in_constr_nearby == 0) {1580 if (any_unconnected_imm && any_connected_imm && field.military_in_constr_nearby == 0) {
1328 field.unconnected_nearby = true;1581 field.unconnected_nearby = true;
1329 }1582 }
1583
1584 // if there is a militarysite on the field, we try to walk to enemy
1585 field.enemy_accessible_ = false;
1586 field.local_soldier_capacity = 0;
1587 if (field.is_militarysite) {
1588 if (upcast(MilitarySite, ms, field.coords.field->get_immovable())) {
1589 if (field.enemy_nearby) {
1590 uint32_t unused1 = 0;
1591 uint16_t unused2 = 0;
1592 field.enemy_accessible_ = other_player_accessible(
1593 actual_enemy_check_area + 3, &unused1, &unused2, field.coords, WalkSearch::kEnemy);
1594 }
1595 field.local_soldier_capacity = ms->soldier_control()->max_soldier_capacity();
1596 field.is_militarysite = true;
1597 } else {
1598 NEVER_HERE();
1599 }
1600 }
1601
1602 // Calculating field score
1603 field.military_score_ = 0;
1604 field.inland = false;
1605
1606 if (!(field.enemy_nearby || field.near_border)) {
1607 field.inland = true;
1608 }
1609
1610 const uint8_t score_parts_size = 55;
1611 int32_t score_parts[score_parts_size] = {0};
1612 if (field.enemy_owned_land_nearby) {
1613 score_parts[0] = 3 *
1614 management_data.neuron_pool[73].get_result_safe(
1615 field.enemy_owned_land_nearby / 5, kAbsValue);
1616 score_parts[1] =
1617 3 *
1618 management_data.neuron_pool[76].get_result_safe(field.enemy_owned_land_nearby, kAbsValue);
1619 score_parts[2] = 3 *
1620 management_data.neuron_pool[54].get_result_safe(
1621 field.enemy_military_presence * 2, kAbsValue);
1622 score_parts[3] = 3 *
1623 management_data.neuron_pool[61].get_result_safe(
1624 field.enemy_military_presence / 3, kAbsValue);
1625 score_parts[4] =
1626 (!field.enemy_accessible_) ? (-100 + management_data.get_military_number_at(55)) : 0;
1627 score_parts[5] =
1628 2 *
1629 management_data.neuron_pool[50].get_result_safe(field.enemy_owned_land_nearby, kAbsValue);
1630
1631 score_parts[6] =
1632 field.enemy_military_sites * std::abs(management_data.get_military_number_at(67) / 2);
1633 score_parts[7] =
1634 2 *
1635 management_data.neuron_pool[34].get_result_safe(field.enemy_military_sites * 2, kAbsValue);
1636 score_parts[8] = management_data.neuron_pool[56].get_result_safe(
1637 field.enemy_military_presence * 2, kAbsValue);
1638
1639 score_parts[9] = management_data.neuron_pool[65].get_result_safe(
1640 (field.unowned_land_nearby + field.enemy_owned_land_nearby) / 2, kAbsValue);
1641 score_parts[10] = (field.enemy_accessible_) ? management_data.get_military_number_at(80) : 0;
1642
1643 score_parts[11] =
1644 -3 *
1645 management_data.neuron_pool[8].get_result_safe(
1646 (field.military_in_constr_nearby + field.military_unstationed) * 3, kAbsValue);
1647 score_parts[12] =
1648 -3 *
1649 management_data.neuron_pool[74].get_result_safe(
1650 (field.military_in_constr_nearby + field.military_unstationed) * 5, kAbsValue);
1651 score_parts[13] = ((field.military_in_constr_nearby + field.military_unstationed) > 0) ?
1652 -std::abs(management_data.get_military_number_at(32)) :
1653 0;
1654 score_parts[14] = -1 * (field.military_in_constr_nearby + field.military_unstationed) *
1655 std::abs(management_data.get_military_number_at(12));
1656
1657 score_parts[15] =
1658 -2 * management_data.neuron_pool[75].get_result_safe(field.own_military_presence);
1659 score_parts[16] = -5 * std::min<int16_t>(field.area_military_capacity, 20);
1660 score_parts[17] = 3 * management_data.get_military_number_at(28);
1661 score_parts[18] =
1662 (field.enemy_nearby) ? 3 * std::abs(management_data.get_military_number_at(68)) : 0;
1663 score_parts[19] =
1664 (field.enemy_wh_nearby) ? 3 * std::abs(management_data.get_military_number_at(132)) : 0;
1665 score_parts[58] = (field.enemy_wh_nearby) ?
1666 std::abs(management_data.get_military_number_at(135)) :
1667 -std::abs(management_data.get_military_number_at(135));
1668
1669 } else { // for expansion or inner land
1670
1671 score_parts[20] = management_data.neuron_pool[22].get_result_safe(
1672 (field.unowned_mines_spots_nearby + 2) / 3, kAbsValue);
1673 score_parts[21] = (field.unowned_mines_spots_nearby > 0) ?
1674 std::abs(management_data.get_military_number_at(58)) :
1675 0;
1676 if (expansion_type.get_expansion_type() == ExpansionMode::kResources) {
1677 score_parts[23] = 2 *
1678 management_data.neuron_pool[78].get_result_safe(
1679 (field.unowned_mines_spots_nearby + 2) / 3, kAbsValue);
1680 }
1681
1682 score_parts[24] =
1683 (field.unowned_land_nearby) ?
1684 management_data.neuron_pool[25].get_result_safe(field.water_nearby / 2, kAbsValue) :
1685 0;
1686 score_parts[25] =
1687 (field.unowned_land_nearby) ?
1688 management_data.neuron_pool[27].get_result_safe(field.trees_nearby / 2, kAbsValue) :
1689 0;
1690
1691 if (resource_necessity_water_needed_) {
1692 score_parts[26] =
1693 (field.unowned_land_nearby) ?
1694 management_data.neuron_pool[15].get_result_safe(field.water_nearby, kAbsValue) :
1695 0;
1696 score_parts[27] =
1697 resource_necessity_water_needed_ *
1698 management_data.neuron_pool[17].get_result_safe(field.distant_water, kAbsValue) / 100;
1699 }
1700 score_parts[28] =
1701 (field.unowned_land_nearby) ?
1702 management_data.neuron_pool[33].get_result_safe(field.water_nearby, kAbsValue) :
1703 0;
1704 score_parts[29] =
1705 management_data.neuron_pool[10].get_result_safe(field.military_loneliness / 50, kAbsValue);
1706
1707 score_parts[30] =
1708 -10 *
1709 management_data.neuron_pool[8].get_result_safe(
1710 3 * (field.military_in_constr_nearby + field.military_unstationed), kAbsValue);
1711 score_parts[31] =
1712 -10 *
1713 management_data.neuron_pool[31].get_result_safe(
1714 3 * (field.military_in_constr_nearby + field.military_unstationed), kAbsValue);
1715 score_parts[32] = -4 * field.military_in_constr_nearby *
1716 std::abs(management_data.get_military_number_at(82));
1717 score_parts[33] = (field.military_in_constr_nearby > 0) ?
1718 -5 * management_data.get_military_number_at(85) :
1719 0;
1720
1721 score_parts[34] = -1 *
1722 management_data.neuron_pool[4].get_result_safe(
1723 (field.area_military_capacity + 4) / 5, kAbsValue);
1724 score_parts[35] = 3 * management_data.get_military_number_at(133);
1725
1726 if (expansion_type.get_expansion_type() == ExpansionMode::kEconomy) {
1727 score_parts[36] = -100 - 4 * std::abs(management_data.get_military_number_at(139));
1728 } else if (expansion_type.get_expansion_type() == ExpansionMode::kResources ||
1729 expansion_type.get_expansion_type() == ExpansionMode::kSpace) {
1730 score_parts[37] =
1731 +100 + 4 * std::abs(management_data.get_military_number_at(139)); // The same as above
1732 }
1733 if (msites_in_constr() > 0 && field.max_buildcap_nearby == BUILDCAPS_BIG &&
1734 spots_avail.at(BUILDCAPS_BIG) <= 2) {
1735 score_parts[57] = -10 * std::abs(management_data.get_military_number_at(54));
1736 }
1737 }
1738
1739 // common inputs
1740 if (field.unowned_iron_mines_nearby > 0 && ((mines_per_type[iron_ore_id].in_construction +
1741 mines_per_type[iron_ore_id].finished) == 0)) {
1742 score_parts[40] = field.unowned_iron_mines_nearby *
1743 std::abs(management_data.get_military_number_at(92)) / 50;
1744 }
1745 if (field.unowned_iron_mines_nearby && ((mines_per_type[iron_ore_id].in_construction +
1746 mines_per_type[iron_ore_id].finished) <= 1)) {
1747 score_parts[41] = 3 * std::abs(management_data.get_military_number_at(93));
1748 }
1749
1750 score_parts[42] =
1751 (field.unowned_land_nearby) ?
1752 management_data.neuron_pool[18].get_result_safe(field.own_non_military_nearby, kAbsValue) :
1753 0;
1754
1755 score_parts[43] = 2 *
1756 management_data.neuron_pool[11].get_result_safe(
1757 field.unowned_buildable_spots_nearby, kAbsValue);
1758 score_parts[44] =
1759 management_data.neuron_pool[12].get_result_safe(field.unowned_mines_spots_nearby, kAbsValue);
1760 score_parts[45] =
1761 (field.unowned_land_nearby) ?
1762 field.military_loneliness * std::abs(management_data.get_military_number_at(53)) / 800 :
1763 0;
1764
1765 score_parts[46] =
1766 -1 * management_data.neuron_pool[55].get_result_safe(field.ally_military_presence, kAbsValue);
1767 score_parts[47] =
1768 -1 *
1769 management_data.neuron_pool[53].get_result_safe(2 * field.ally_military_presence, kAbsValue);
1770 score_parts[48] = -2 *
1771 management_data.neuron_pool[4].get_result_safe(
1772 (field.area_military_capacity + 4) / 5, kAbsValue);
1773 score_parts[49] = ((field.military_in_constr_nearby + field.military_unstationed) > 0) ?
1774 -std::abs(management_data.get_military_number_at(81)) :
1775 0;
1776 score_parts[55] = (field.military_loneliness < 10) ?
1777 2 * std::abs(management_data.get_military_number_at(141)) :
1778 0;
1779 score_parts[56] =
1780 (any_unconnected_imm) ? 2 * std::abs(management_data.get_military_number_at(23)) : 0;
1781
1782 for (uint16_t i = 0; i < score_parts_size; i++) {
1783 field.military_score_ += score_parts[i];
1784 }
1785
1786 if (kAITrainingMode) {
1787 if (field.military_score_ < -5000 || field.military_score_ > 2000) {
1788 log("Warning field.military_score_ %5d, compounds: ", field.military_score_);
1789 for (uint16_t i = 0; i < score_parts_size; i++) {
1790 log("%d, ", score_parts[i]);
1791 }
1792 log("\n");
1793 }
1794 }
1795
1796 // is new site allowed at all here?
1797 field.defense_msite_allowed = false;
1798 int16_t multiplicator = 10;
1799 if (soldier_status_ == SoldiersStatus::kBadShortage) {
1800 multiplicator = 4;
1801 } else if (soldier_status_ == SoldiersStatus::kShortage) {
1802 multiplicator = 7;
1803 }
1804 if (field.area_military_capacity < field.enemy_military_presence * multiplicator / 10) {
1805 field.defense_msite_allowed = true;
1806 }
1330}1807}
13311808
1332/// Updates one mineable field1809/// Updates one mineable field
@@ -1378,7 +1855,6 @@
13781855
1379/// Updates the production and MINE sites statistics needed for construction decision.1856/// Updates the production and MINE sites statistics needed for construction decision.
1380void DefaultAI::update_productionsite_stats() {1857void DefaultAI::update_productionsite_stats() {
1381 uint16_t fishers_count = 0; // used for atlanteans only
13821858
1383 // Reset statistics for all buildings1859 // Reset statistics for all buildings
1384 for (uint32_t i = 0; i < buildings_.size(); ++i) {1860 for (uint32_t i = 0; i < buildings_.size(); ++i) {
@@ -1400,11 +1876,6 @@
1400 productionsites.front().bo->current_stats +=1876 productionsites.front().bo->current_stats +=
1401 productionsites.front().site->get_crude_statistics();1877 productionsites.front().site->get_crude_statistics();
14021878
1403 // counting fishers
1404 if (productionsites.front().bo->is_fisher) {
1405 fishers_count += 1;
1406 }
1407
1408 // Check whether this building is completely occupied1879 // Check whether this building is completely occupied
1409 if (!productionsites.front().site->can_start_working()) {1880 if (!productionsites.front().site->can_start_working()) {
1410 productionsites.front().bo->unoccupied_count += 1;1881 productionsites.front().bo->unoccupied_count += 1;
@@ -1418,16 +1889,6 @@
1418 productionsites.pop_front();1889 productionsites.pop_front();
1419 }1890 }
14201891
1421 if (resource_necessity_water_needed_) {
1422 if (fishers_count == 0) {
1423 resource_necessity_water_ = 100;
1424 } else if (fishers_count == 1) {
1425 resource_necessity_water_ = 50;
1426 } else {
1427 resource_necessity_water_ = 10;
1428 }
1429 }
1430
1431 // for mines_ also1892 // for mines_ also
1432 // Check all available mines1893 // Check all available mines
1433 for (uint32_t i = 0; i < mines_.size(); ++i) {1894 for (uint32_t i = 0; i < mines_.size(); ++i) {
@@ -1467,29 +1928,23 @@
1467// is built.1928// is built.
1468// * Buildings are split into categories1929// * Buildings are split into categories
1469// * The logic is complex but approximately:1930// * The logic is complex but approximately:
1470// - buildings producing building material are preferred1931// - some buildings belong to "basic economy" - these are preferred
1471// - buildings identified as basic are preferred1932// - some small huts are exempt from basic economy logic
1472// - first bulding of a type is preferred1933// - first bulding of a type is preferred
1473// - buildings identified as 'direct food supplier' are built after 15 min.
1474// from game start
1475// - if a building is upgradeable, second building is also preferred
1476// (there should be no upgrade when there are not two buildings of the same type)
1477// - algorithm is trying to take into account actual utlization of buildings1934// - algorithm is trying to take into account actual utlization of buildings
1478// (the one shown in GUI/game is not reliable, it calculates own statistics)1935// (the one shown in GUI/game is not reliable, it calculates own statistics)
1479// * military buildings have own strategy, split into two situations:1936// * military buildings use genetic algorithm logic to score fields
1480// - there is no enemy
1481// - there is an enemy
1482// Currently more military buildings are built than needed1937// Currently more military buildings are built than needed
1483// and "optimization" (dismantling not needed buildings) is done afterwards1938// so there are always some vacant positions
1484bool DefaultAI::construct_building(uint32_t gametime) {1939bool DefaultAI::construct_building(uint32_t gametime) {
1485 if (buildable_fields.empty()) {1940 if (buildable_fields.empty()) {
1486 return false;1941 return false;
1487 }1942 }
1943
1488 // Just used for easy checking whether a mine or something else was built.1944 // Just used for easy checking whether a mine or something else was built.
1489 bool mine = false;1945 bool mine = false;
1490 uint32_t consumers_nearby_count = 0;1946 uint32_t consumers_nearby_count = 0;
1491 std::vector<int32_t> spots_avail;1947
1492 spots_avail.resize(4);
1493 Map& map = game().map();1948 Map& map = game().map();
14941949
1495 for (int32_t i = 0; i < 4; ++i)1950 for (int32_t i = 0; i < 4; ++i)
@@ -1503,9 +1958,6 @@
1503 spots_ += spots_avail.at(BUILDCAPS_MEDIUM);1958 spots_ += spots_avail.at(BUILDCAPS_MEDIUM);
1504 spots_ += spots_avail.at(BUILDCAPS_BIG);1959 spots_ += spots_avail.at(BUILDCAPS_BIG);
15051960
1506 // here we possible stop building of new buildings
1507 new_buildings_stop_ = false;
1508
1509 // helper variable - we need some proportion of free spots vs productionsites1961 // helper variable - we need some proportion of free spots vs productionsites
1510 // the proportion depends on size of economy1962 // the proportion depends on size of economy
1511 // this proportion defines how dense the buildings will be1963 // this proportion defines how dense the buildings will be
@@ -1522,8 +1974,22 @@
1522 }1974 }
1523 const bool has_enough_space = (spots_ > needed_spots);1975 const bool has_enough_space = (spots_ > needed_spots);
15241976
1525 // This is a replacement for simple count of mines1977 // Do we have basic economy established? Informing that we just left the basic economy mode.
1526 const int32_t virtual_mines = mines_.size() + mineable_fields.size() / 25;1978 if (!basic_economy_established && persistent_data->remaining_basic_buildings.empty()) {
1979 log("%2d: Player has achieved the basic economy at %s\n", player_number(),
1980 gamestring_with_leading_zeros(gametime));
1981 basic_economy_established = true;
1982 assert(persistent_data->remaining_buildings_size == 0);
1983 }
1984
1985 if (!basic_economy_established && player_statistics.any_enemy_seen_lately(gametime) &&
1986 management_data.f_neuron_pool[17].get_position(0)) {
1987 log("%2d: Player has not all buildings for basic economy yet (%lu missing), but enemy is "
1988 "nearby, so quitting the mode at %s\n",
1989 player_number(), persistent_data->remaining_basic_buildings.size(),
1990 gamestring_with_leading_zeros(gametime));
1991 basic_economy_established = true;
1992 }
15271993
1528 // *_military_scores are used as minimal score for a new military building1994 // *_military_scores are used as minimal score for a new military building
1529 // to be built. As AI does not traverse all building fields at once, these thresholds1995 // to be built. As AI does not traverse all building fields at once, these thresholds
@@ -1534,102 +2000,210 @@
1534 // score) and quickly falling down until it reaches the least_military_score2000 // score) and quickly falling down until it reaches the least_military_score
1535 // this one (=target_military_score) is actually used to decide if building&field is allowed2001 // this one (=target_military_score) is actually used to decide if building&field is allowed
1536 // candidate2002 // candidate
1537 // least_military_score is allowed to get bellow 100 only if there is no military site in2003
1538 // construction2004 const PlayerNumber pn = player_number();
1539 // right now in order to (try to) avoid expansion lockup2005
15402006 // Genetic algorithm is used here
1541 // Bools below are helpers to improve readability of code2007 bool inputs[2 * kFNeuronBitSize] = {0};
15422008 inputs[0] = (pow(msites_in_constr(), 2) > militarysites.size() + 2);
1543 // It is bit complicated balance building militarysites and productionsites so this is small hack2009 inputs[1] = !(pow(msites_in_constr(), 2) > militarysites.size() + 2);
1544 // to help2010 inputs[2] =
1545 // it2011 (highest_nonmil_prio_ > 18 + std::abs(management_data.get_military_number_at(29) / 10));
1546 bool needs_boost_economy = false;2012 inputs[3] =
1547 if (highest_nonmil_prio_ > 10 && has_enough_space && virtual_mines >= 5) {2013 !(highest_nonmil_prio_ > 18 + std::abs(management_data.get_military_number_at(29) / 10));
1548 needs_boost_economy = true;2014 inputs[4] = (highest_nonmil_prio_ > 18 + std::abs(management_data.get_military_number_at(48)));
1549 }2015 inputs[5] = !(highest_nonmil_prio_ > 18 + std::abs(management_data.get_military_number_at(49)));
2016 inputs[6] = ((numof_psites_in_constr + mines_in_constr()) >
2017 (productionsites.size() + mines_built()) / productionsites_ratio_);
2018 inputs[7] = !((numof_psites_in_constr + mines_in_constr()) >
2019 (productionsites.size() + mines_built()) / productionsites_ratio_);
2020
2021 inputs[8] = (has_enough_space);
2022 inputs[9] = !(has_enough_space);
2023 inputs[10] = (has_enough_space);
2024 inputs[11] = !(has_enough_space);
2025
2026 inputs[12] = (gametime > 45 * 60 * 1000);
2027 inputs[13] = !(gametime > 45 * 60 * 1000);
2028
2029 inputs[14] = (expansion_type.get_expansion_type() == ExpansionMode::kEconomy);
2030 inputs[15] = !(expansion_type.get_expansion_type() == ExpansionMode::kEconomy);
2031 inputs[16] = (expansion_type.get_expansion_type() == ExpansionMode::kSpace);
2032 inputs[17] = !(expansion_type.get_expansion_type() == ExpansionMode::kSpace);
2033
2034 inputs[18] = (player_statistics.any_enemy_seen_lately(gametime));
2035 inputs[19] = !(player_statistics.any_enemy_seen_lately(gametime));
2036 inputs[20] = (player_statistics.get_player_power(pn) >
2037 player_statistics.get_old60_player_power(pn) +
2038 std::abs(management_data.get_military_number_at(130)) / 10);
2039 inputs[21] = !(player_statistics.get_player_power(pn) >
2040 player_statistics.get_old60_player_power(pn) +
2041 std::abs(management_data.get_military_number_at(131)) / 10);
2042 inputs[22] =
2043 (player_statistics.get_player_power(pn) > player_statistics.get_old_player_power(pn));
2044 inputs[23] =
2045 !(player_statistics.get_player_power(pn) > player_statistics.get_old_player_power(pn));
2046 inputs[24] = (highest_nonmil_prio_ > 18 + management_data.get_military_number_at(65) / 10);
2047 inputs[25] = !(highest_nonmil_prio_ > 18 + management_data.get_military_number_at(65) / 10);
2048 inputs[26] = (player_statistics.get_modified_player_power(pn) >
2049 player_statistics.get_visible_enemies_power(pn));
2050 inputs[27] = (player_statistics.get_modified_player_power(pn) <=
2051 player_statistics.get_visible_enemies_power(pn));
2052 inputs[28] =
2053 (player_statistics.get_player_power(pn) > player_statistics.get_enemies_average_power());
2054 inputs[29] =
2055 !(player_statistics.get_player_power(pn) > player_statistics.get_enemies_average_power());
2056 inputs[30] =
2057 (player_statistics.get_player_power(pn) > player_statistics.get_enemies_max_power());
2058 inputs[31] =
2059 !(player_statistics.get_player_power(pn) > player_statistics.get_enemies_max_power());
2060
2061 inputs[32] = (persistent_data->least_military_score <
2062 persistent_data->ai_personality_mil_upper_limit *
2063 std::abs(management_data.get_military_number_at(69)) / 100);
2064 inputs[33] = !(persistent_data->least_military_score <
2065 persistent_data->ai_personality_mil_upper_limit *
2066 std::abs(management_data.get_military_number_at(69)) / 100);
2067 inputs[34] = player_statistics.strong_enough(pn);
2068 inputs[35] = !player_statistics.strong_enough(pn);
2069
2070 inputs[36] = (player_statistics.get_player_land(pn) < 500);
2071 inputs[37] = (player_statistics.get_player_land(pn) < 700);
2072 inputs[38] = (player_statistics.get_player_land(pn) < 900);
2073 inputs[39] = (player_statistics.get_player_land(pn) < 1100);
2074 inputs[40] = (player_statistics.get_player_land(pn) > 500);
2075 inputs[41] = (player_statistics.get_player_land(pn) > 700);
2076 inputs[42] = (player_statistics.get_player_land(pn) > 900);
2077 inputs[43] = (player_statistics.get_player_land(pn) > 1100);
2078 inputs[44] = (player_statistics.get_player_power(pn) >
2079 player_statistics.get_old60_player_power(pn) +
2080 std::abs(management_data.get_military_number_at(130)) / 10);
2081 inputs[45] = !(player_statistics.get_player_power(pn) >
2082 player_statistics.get_old60_player_power(pn) +
2083 std::abs(management_data.get_military_number_at(131)) / 10);
2084 inputs[46] =
2085 (player_statistics.get_player_power(pn) > player_statistics.get_old_player_power(pn));
2086 inputs[47] =
2087 !(player_statistics.get_player_power(pn) > player_statistics.get_old_player_power(pn));
2088 inputs[48] = (bakeries_count_ == 0);
2089 inputs[49] = (bakeries_count_ <= 1);
2090 inputs[50] = (bakeries_count_ <= 1);
2091 inputs[51] = (numof_psites_in_constr > 8);
2092 inputs[52] = (numof_psites_in_constr < 8);
2093
2094 int16_t needs_boost_economy_score = management_data.get_military_number_at(61) / 5;
2095 int16_t increase_score_limit_score = 0;
2096
2097 for (uint8_t i = 0; i < kFNeuronBitSize; ++i) {
2098 if (management_data.f_neuron_pool[51].get_position(i)) {
2099 needs_boost_economy_score += (inputs[i]) ? 1 : -1;
2100 }
2101 if (management_data.f_neuron_pool[52].get_position(i)) {
2102 increase_score_limit_score += (inputs[i]) ? 1 : -1;
2103 }
2104 if (management_data.f_neuron_pool[21].get_position(i)) {
2105 needs_boost_economy_score += (inputs[kFNeuronBitSize + i]) ? 1 : -1;
2106 }
2107 if (management_data.f_neuron_pool[22].get_position(i)) {
2108 increase_score_limit_score += (inputs[kFNeuronBitSize + i]) ? 1 : -1;
2109 }
2110 }
2111
2112 // Finding expansion policy
2113 // Do we need basic resources?
2114 // This is a replacement for simple count of mines
2115 const int32_t virtual_mines = mines_.size() + mineable_fields.size() / 15;
2116 const bool needs_fishers = resource_necessity_water_needed_ && fishers_count_ < 1;
2117
2118 if (virtual_mines < 4 || mines_per_type[iron_ore_id].total_count() < 1 || needs_fishers) {
2119 expansion_type.set_expantion_type(ExpansionMode::kResources);
2120 } else {
2121 // now we must decide if we go after spots or economy boost
2122 if (needs_boost_economy_score >= 3) {
2123 expansion_type.set_expantion_type(ExpansionMode::kEconomy);
2124 } else if (needs_boost_economy_score >= -2) {
2125 expansion_type.set_expantion_type(ExpansionMode::kBoth);
2126 } else {
2127 expansion_type.set_expantion_type(ExpansionMode::kSpace);
2128 }
2129 }
2130
2131 const bool increase_least_score_limit =
2132 (increase_score_limit_score > management_data.get_military_number_at(45) / 5);
2133
2134 uint16_t concurent_ms_in_constr_no_enemy = 1;
2135 uint16_t concurent_ms_in_constr_enemy_nearby = 2;
15502136
1551 // resetting highest_nonmil_prio_ so it can be recalculated anew2137 // resetting highest_nonmil_prio_ so it can be recalculated anew
1552 highest_nonmil_prio_ = 0;2138 highest_nonmil_prio_ = 0;
15532139
1554 const bool too_many_ms_constructionsites =2140 if (increase_least_score_limit) {
1555 (pow(msites_in_constr(), 2) > militarysites.size() + 2);
1556 const bool too_many_vacant_mil =
1557 (vacant_mil_positions_ * 3 > static_cast<int32_t>(militarysites.size()));
1558 const int32_t kUpperLimit = 325;
1559 const int32_t kBottomLimit = 40; // to prevent too dense militarysites
1560 // modifying least_military_score, down if more military sites are needed and vice versa
1561 if (too_many_ms_constructionsites || too_many_vacant_mil || needs_boost_economy) {
1562 if (persistent_data->least_military_score <2141 if (persistent_data->least_military_score <
1563 kUpperLimit) { // No sense in letting it grow too high2142 persistent_data
2143 ->ai_personality_mil_upper_limit) { // No sense in letting it grow too high
1564 persistent_data->least_military_score += 20;2144 persistent_data->least_military_score += 20;
2145 if (persistent_data->least_military_score > persistent_data->target_military_score) {
2146 persistent_data->target_military_score = persistent_data->least_military_score;
2147 }
2148 if (persistent_data->target_military_score >
2149 persistent_data->ai_personality_mil_upper_limit) {
2150 persistent_data->ai_personality_mil_upper_limit =
2151 persistent_data->target_military_score;
2152 }
1565 }2153 }
1566 } else {2154 } else {
2155
2156 uint16_t divider = 1; // this is to slow down decrementing the least military score
2157 switch (expansion_type.get_expansion_type()) {
2158 case ExpansionMode::kEconomy:
2159 divider = 3;
2160 break;
2161 case ExpansionMode::kBoth:
2162 divider = 2;
2163 break;
2164 default:
2165 divider = 1;
2166 }
2167
1567 // least_military_score is decreased, but depending on the size of territory2168 // least_military_score is decreased, but depending on the size of territory
1568 switch (static_cast<uint32_t>(log10(buildable_fields.size()))) {2169 switch (static_cast<uint32_t>(log10(buildable_fields.size()))) {
1569 case 0:2170 case 0:
1570 persistent_data->least_military_score -= 10;2171 persistent_data->least_military_score -= 10 / divider;
1571 break;2172 break;
1572 case 1:2173 case 1:
1573 persistent_data->least_military_score -= 8;2174 persistent_data->least_military_score -= 8 / divider;
1574 break;2175 break;
1575 case 2:2176 case 2:
1576 persistent_data->least_military_score -= 5;2177 persistent_data->least_military_score -= 5 / divider;
1577 break;2178 break;
1578 case 3:2179 case 3:
1579 persistent_data->least_military_score -= 3;2180 persistent_data->least_military_score -= 3 / divider;
1580 break;2181 break;
1581 default:2182 default:
1582 persistent_data->least_military_score -= 2;2183 persistent_data->least_military_score -= 2 / divider;
1583 }
1584 // do not get bellow kBottomLimit if there is at least one ms in construction
1585 if ((msites_in_constr() > 0 || too_many_vacant_mil) &&
1586 persistent_data->least_military_score < kBottomLimit) {
1587 persistent_data->least_military_score = kBottomLimit;
1588 }2184 }
1589 if (persistent_data->least_military_score < 0) {2185 if (persistent_data->least_military_score < 0) {
1590 persistent_data->least_military_score = 0;2186 persistent_data->least_military_score = 0;
1591 }2187 }
1592 }2188 }
15932189
1594 // This is effective score, falling down very quickly2190 assert(persistent_data->least_military_score <= persistent_data->target_military_score);
1595 if (persistent_data->target_military_score > kUpperLimit + 150) {2191 assert(persistent_data->target_military_score <=
1596 persistent_data->target_military_score = 8 * persistent_data->target_military_score / 10;2192 persistent_data->ai_personality_mil_upper_limit);
1597 } else {2193 persistent_data->target_military_score = 9 * persistent_data->target_military_score / 10;
1598 persistent_data->target_military_score = 9 * persistent_data->target_military_score / 10;
1599 }
1600 if (persistent_data->target_military_score < persistent_data->least_military_score) {2194 if (persistent_data->target_military_score < persistent_data->least_military_score) {
1601 persistent_data->target_military_score = persistent_data->least_military_score;2195 persistent_data->target_military_score = persistent_data->least_military_score;
1602 }2196 }
16032197 assert(persistent_data->target_military_score >= persistent_data->least_military_score);
1604 // there are many reasons why to stop building production buildings
1605 // (note there are numerous exceptions)
1606 // 1. to not have too many constructionsites
1607 if ((num_prod_constructionsites + mines_in_constr()) >
1608 (productionsites.size() + mines_built()) / persistent_data->ai_productionsites_ratio + 2) {
1609 new_buildings_stop_ = true;
1610 }
1611 // 2. to not exhaust all free spots
1612 if (!has_enough_space) {
1613 new_buildings_stop_ = true;
1614 }
1615 // 3. too keep some proportions production sites vs military sites
1616 if ((num_prod_constructionsites + productionsites.size()) >
1617 (msites_in_constr() + militarysites.size()) * 5) {
1618 new_buildings_stop_ = true;
1619 }
1620 // 4. if we do not have 2 mines at least
1621 if (mines_.size() < 2) {
1622 new_buildings_stop_ = true;
1623 }
16242198
1625 // we must calculate wood policy2199 // we must calculate wood policy
1626 const DescriptionIndex wood_index = tribe_->safe_ware_index("log");2200 const DescriptionIndex wood_index = tribe_->safe_ware_index("log");
1627 // stocked wood is to be in some propotion to productionsites and2201 // stocked wood is to be in some propotion to productionsites and
1628 // constructionsites (this proportion is bit artifical, or we can say2202 // constructionsites (this proportion is bit artifical, or we can say
1629 // it is proportion to the size of economy). Plus some positive 'margin'2203 // it is proportion to the size of economy). Plus some positive 'margin'
1630 const int32_t stocked_wood_margin = get_warehoused_stock(wood_index) -2204 const int32_t stocked_wood_margin = calculate_stocklevel(wood_index) -
1631 productionsites.size() * 2 - num_prod_constructionsites +2205 productionsites.size() * 2 - numof_psites_in_constr +
1632 persistent_data->ai_personality_wood_difference;2206 management_data.get_military_number_at(87) / 5;
1633 if (gametime < 15 * 60 * 1000) {2207 if (gametime < 15 * 60 * 1000) {
1634 wood_policy_ = WoodPolicy::kAllowRangers;2208 wood_policy_ = WoodPolicy::kAllowRangers;
1635 } else if (stocked_wood_margin > 80) {2209 } else if (stocked_wood_margin > 80) {
@@ -1640,34 +2214,6 @@
1640 wood_policy_ = WoodPolicy::kAllowRangers;2214 wood_policy_ = WoodPolicy::kAllowRangers;
1641 }2215 }
16422216
1643 // we must consider need for mines
1644 // set necessity for mines
1645 // we use 'virtual mines', because also mine spots can be changed
1646 // to mines when AI decides so
1647
1648 resource_necessity_mines_ = 100 * (15 - virtual_mines) / 15;
1649 resource_necessity_mines_ = (resource_necessity_mines_ > 100) ? 100 : resource_necessity_mines_;
1650 resource_necessity_mines_ = (resource_necessity_mines_ < 20) ? 10 : resource_necessity_mines_;
1651
1652 // here we calculate how badly we need to expand, result is number (0-100)
1653 // like a percent
1654 if (spots_ == 0) {
1655 resource_necessity_territory_ = 100;
1656 } else {
1657 resource_necessity_territory_ = 100 * 3 * (productionsites.size() + 5) / spots_;
1658 resource_necessity_territory_ =
1659 (resource_necessity_territory_ > 100) ? 100 : resource_necessity_territory_;
1660 resource_necessity_territory_ =
1661 (resource_necessity_territory_ < 10) ? 10 : resource_necessity_territory_;
1662 // alse we need at lest 4 big spots
1663 if (spots_avail.at(BUILDCAPS_BIG) < 2) {
1664 resource_necessity_territory_ = 100;
1665 }
1666 if (spots_avail.at(BUILDCAPS_MEDIUM) < 4) {
1667 resource_necessity_territory_ = 100;
1668 }
1669 }
1670
1671 BuildingObserver* best_building = nullptr;2217 BuildingObserver* best_building = nullptr;
1672 int32_t proposed_priority = 0;2218 int32_t proposed_priority = 0;
1673 Coords proposed_coords;2219 Coords proposed_coords;
@@ -1685,7 +2231,8 @@
16852231
1686 // not doing this for non-military buildins2232 // not doing this for non-military buildins
1687 if (!(bo.type == BuildingObserver::Type::kMilitarysite ||2233 if (!(bo.type == BuildingObserver::Type::kMilitarysite ||
1688 bo.type == BuildingObserver::Type::kTrainingsite))2234 bo.type == BuildingObserver::Type::kTrainingsite ||
2235 bo.type == BuildingObserver::Type::kProductionsite))
1689 continue;2236 continue;
16902237
1691 // and neither for small military buildings2238 // and neither for small military buildings
@@ -1698,13 +2245,17 @@
1698 // checking we have enough critical material on stock2245 // checking we have enough critical material on stock
1699 for (uint32_t m = 0; m < bo.critical_building_material.size(); ++m) {2246 for (uint32_t m = 0; m < bo.critical_building_material.size(); ++m) {
1700 DescriptionIndex wt(static_cast<size_t>(bo.critical_building_material.at(m)));2247 DescriptionIndex wt(static_cast<size_t>(bo.critical_building_material.at(m)));
1701 uint32_t treshold = 3;2248 uint32_t treshold = 7;
1702 // generally trainingsites are more important2249 // generally trainingsites are more important
1703 if (bo.type == BuildingObserver::Type::kTrainingsite) {2250 if (bo.type == BuildingObserver::Type::kTrainingsite) {
2251 treshold = 4;
2252 }
2253
2254 if (bo.type == BuildingObserver::Type::kProductionsite) {
1704 treshold = 2;2255 treshold = 2;
1705 }2256 }
17062257
1707 if (get_warehoused_stock(wt) < treshold) {2258 if (calculate_stocklevel(wt) <= treshold) {
1708 bo.build_material_shortage = true;2259 bo.build_material_shortage = true;
1709 break;2260 break;
1710 }2261 }
@@ -1722,6 +2273,11 @@
17222273
1723 bo.new_building = check_building_necessity(bo, PerfEvaluation::kForConstruction, gametime);2274 bo.new_building = check_building_necessity(bo, PerfEvaluation::kForConstruction, gametime);
17242275
2276 if (bo.is(BuildingAttribute::kShipyard)) {
2277 assert(bo.new_building == BuildingNecessity::kAllowed ||
2278 bo.new_building == BuildingNecessity::kForbidden);
2279 }
2280
1725 if (bo.new_building == BuildingNecessity::kAllowed) {2281 if (bo.new_building == BuildingNecessity::kAllowed) {
1726 bo.new_building_overdue = 0;2282 bo.new_building_overdue = 0;
1727 }2283 }
@@ -1732,7 +2288,7 @@
1732 bo.new_building == BuildingNecessity::kForced ||2288 bo.new_building == BuildingNecessity::kForced ||
1733 bo.new_building == BuildingNecessity::kAllowed ||2289 bo.new_building == BuildingNecessity::kAllowed ||
1734 bo.new_building == BuildingNecessity::kNeededPending) &&2290 bo.new_building == BuildingNecessity::kNeededPending) &&
1735 !bo.outputs.empty()) {2291 (!bo.outputs.empty() || bo.is(BuildingAttribute::kBarracks))) {
1736 if (bo.max_needed_preciousness <= 0) {2292 if (bo.max_needed_preciousness <= 0) {
1737 throw wexception("AI: Max presciousness must not be <= 0 for building: %s",2293 throw wexception("AI: Max presciousness must not be <= 0 for building: %s",
1738 bo.desc->name().c_str());2294 bo.desc->name().c_str());
@@ -1741,6 +2297,7 @@
1741 bo.max_needed_preciousness = 0;2297 bo.max_needed_preciousness = 0;
1742 } else {2298 } else {
1743 // For other situations we make sure max_needed_preciousness is zero2299 // For other situations we make sure max_needed_preciousness is zero
2300
1744 assert(bo.max_needed_preciousness == 0);2301 assert(bo.max_needed_preciousness == 0);
1745 }2302 }
17462303
@@ -1763,42 +2320,31 @@
1763 // c) all other cases: primary_priority = 0;2320 // c) all other cases: primary_priority = 0;
1764 if (bo.max_needed_preciousness > 0) {2321 if (bo.max_needed_preciousness > 0) {
1765 if (bo.new_building == BuildingNecessity::kAllowed) {2322 if (bo.new_building == BuildingNecessity::kAllowed) {
1766 bo.primary_priority = bo.max_needed_preciousness;2323 bo.primary_priority += bo.max_needed_preciousness;
1767 } else {2324 } else {
1768 bo.primary_priority = bo.max_needed_preciousness +2325 bo.primary_priority += bo.primary_priority * bo.new_building_overdue *
1769 bo.max_needed_preciousness * bo.new_building_overdue / 100 +2326 std::abs(management_data.get_military_number_at(120)) / 500;
1770 bo.new_building_overdue / 20;2327 bo.primary_priority += bo.max_needed_preciousness +
2328 bo.max_needed_preciousness * bo.new_building_overdue *
2329 std::abs(management_data.get_military_number_at(70)) /
2330 1000 +
2331 bo.new_building_overdue *
2332 std::abs(management_data.get_military_number_at(71)) / 50;
2333 if (bo.new_building == BuildingNecessity::kForced) {
2334 bo.primary_priority += bo.new_building_overdue *
2335 std::abs(management_data.get_military_number_at(119)) / 50;
2336 }
1771 }2337 }
1772 } else {2338 } else {
1773 bo.primary_priority = 0;2339 bo.primary_priority = 0;
1774 }2340 }
17752341
1776 // Generally we don't start another building if there is some of the same type in
1777 // construction
1778 // Some types of building allow two buildings in construction though, but not more
1779 // Below checks are to guarantee that there is no logical error in previous steps, or
1780 // inconsistency in AI data
1781 if (bo.new_building == BuildingNecessity::kNeeded ||
1782 bo.new_building == BuildingNecessity::kForced ||
1783 bo.new_building == BuildingNecessity::kAllowed ||
1784 bo.new_building == BuildingNecessity::kNeededPending) {
1785 if (bo.plants_trees || bo.need_trees || bo.max_needed_preciousness >= 10) {
1786 if (bo.cnt_under_construction + bo.unoccupied_count > 1) {
1787 throw wexception("AI inconsistency: %s: total_count %d > 1, unoccupied: %d",
1788 bo.name, bo.total_count(), bo.unoccupied_count);
1789 }
1790 } else {
1791 if (bo.cnt_under_construction + bo.unoccupied_count > 0) {
1792 throw wexception("AI inconsistency: %s: total_count %d > 0, unoccupied: %d",
1793 bo.name, bo.total_count(), bo.unoccupied_count);
1794 }
1795 }
1796 }
1797
1798 } else if (bo.type == BuildingObserver::Type::kMilitarysite) {2342 } else if (bo.type == BuildingObserver::Type::kMilitarysite) {
1799 bo.new_building = check_building_necessity(bo.desc->get_size(), gametime);2343 bo.new_building = check_building_necessity(bo, gametime);
1800 } else if (bo.type == BuildingObserver::Type::kTrainingsite) {2344 } else if (bo.type == BuildingObserver::Type::kTrainingsite) {
1801 bo.new_building = check_building_necessity(bo, PerfEvaluation::kForConstruction, gametime);2345 bo.new_building = check_building_necessity(bo, PerfEvaluation::kForConstruction, gametime);
2346 } else if (bo.type == BuildingObserver::Type::kWarehouse) {
2347 bo.new_building = check_warehouse_necessity(bo, gametime);
1802 } else if (bo.aimode_limit_status() != AiModeBuildings::kAnotherAllowed) {2348 } else if (bo.aimode_limit_status() != AiModeBuildings::kAnotherAllowed) {
1803 bo.new_building = BuildingNecessity::kNotNeeded;2349 bo.new_building = BuildingNecessity::kNotNeeded;
1804 } else {2350 } else {
@@ -1848,13 +2394,13 @@
1848 }2394 }
18492395
1850 // testing for reserved ports2396 // testing for reserved ports
1851 if (!bo.is_port) {2397 if (!bo.is(BuildingAttribute::kPort)) {
1852 if (port_reserved_coords.count(bf->coords.hash()) > 0) {2398 if (port_reserved_coords.count(bf->coords.hash()) > 0) {
1853 continue;2399 continue;
1854 }2400 }
1855 }2401 }
18562402
1857 if (time(nullptr) % 3 == 0 && bo.total_count() > 0) {2403 if (std::rand() % 3 == 0 && bo.total_count() > 0) {
1858 continue;2404 continue;
1859 } // add randomnes and ease AI2405 } // add randomnes and ease AI
18602406
@@ -1864,7 +2410,8 @@
18642410
1865 // here we do an exemption for lumberjacks, mainly in early stages of game2411 // here we do an exemption for lumberjacks, mainly in early stages of game
1866 // sometimes the first one is not built and AI waits too long for second attempt2412 // sometimes the first one is not built and AI waits too long for second attempt
1867 if (gametime - bo.construction_decision_time < kBuildingMinInterval && !bo.need_trees) {2413 if (gametime - bo.construction_decision_time < kBuildingMinInterval &&
2414 !bo.is(BuildingAttribute::kLumberjack)) {
1868 continue;2415 continue;
1869 }2416 }
18702417
@@ -1877,8 +2424,11 @@
18772424
1878 if (bo.type == BuildingObserver::Type::kProductionsite) {2425 if (bo.type == BuildingObserver::Type::kProductionsite) {
18792426
2427 prio = management_data.neuron_pool[44].get_result_safe(bf->military_score_ / 20) / 5;
2428 assert(prio >= -20 && prio <= 20);
2429
1880 // this can be only a well (as by now)2430 // this can be only a well (as by now)
1881 if (bo.mines_water) {2431 if (bo.is(BuildingAttribute::kWell)) {
18822432
1883 if (bo.new_building == BuildingNecessity::kForced) {2433 if (bo.new_building == BuildingNecessity::kForced) {
1884 assert(bo.total_count() - bo.unconnected_count == 0);2434 assert(bo.total_count() - bo.unconnected_count == 0);
@@ -1900,33 +2450,41 @@
1900 prio += 200;2450 prio += 200;
1901 }2451 }
19022452
1903 prio += bf->ground_water - 2;2453 prio += -10 + 2 * bf->ground_water;
19042454
1905 } else if (bo.need_trees) { // LUMBERJACS2455 } else if (bo.is(BuildingAttribute::kLumberjack)) {
19062456
1907 prio = bo.primary_priority;2457 prio = bo.primary_priority;
19082458
1909 prio += -20 + 200 / (bo.total_count() + 1);
1910
1911 if (bo.new_building == BuildingNecessity::kForced) {2459 if (bo.new_building == BuildingNecessity::kForced) {
1912 prio *= 2;2460 prio += 5 * std::abs(management_data.get_military_number_at(17));
1913 } else if (bf->trees_nearby < 2 && bf->supporters_nearby.at(bo.outputs.at(0) == 0)) {2461 }
2462
2463 if (bf->trees_nearby < trees_nearby_treshold_ &&
2464 bo.new_building == BuildingNecessity::kAllowed) {
1914 continue;2465 continue;
1915 }2466 }
19162467
2468 prio += std::abs(management_data.get_military_number_at(26)) *
2469 (bf->trees_nearby - trees_nearby_treshold_) / 10;
2470
1917 // consider cutters and rangers nearby2471 // consider cutters and rangers nearby
1918 prio -= bf->producers_nearby.at(bo.outputs.at(0)) * 20;2472 prio += 2 * bf->supporters_nearby.at(bo.outputs.at(0)) *
1919 prio += bf->supporters_nearby.at(bo.outputs.at(0)) * 5;2473 std::abs(management_data.get_military_number_at(25));
19202474 prio -= bf->producers_nearby.at(bo.outputs.at(0)) *
1921 prio += 2 * bf->trees_nearby;2475 std::abs(management_data.get_military_number_at(36)) * 3;
19222476
1923 } else if (bo.need_rocks) {2477 } else if (bo.is(BuildingAttribute::kNeedsRocks)) {
19242478
1925 // Quarries are generally to be built everywhere where rocks are2479 // Quarries are generally to be built everywhere where rocks are
1926 // no matter the need for granite, as rocks are considered an obstacle2480 // no matter the need for granite, as rocks are considered an obstacle
1927 // to expansion2481 // to expansion
1928 prio = 2 * bf->rocks_nearby;2482 prio = 2 * bf->rocks_nearby;
19292483
2484 if (bf->rocks_nearby > 0 && bf->near_border) {
2485 prio += management_data.get_military_number_at(27) / 2;
2486 }
2487
1930 // value is initialized with 1 but minimal value that can be2488 // value is initialized with 1 but minimal value that can be
1931 // calculated is 112489 // calculated is 11
1932 if (prio <= 1) {2490 if (prio <= 1) {
@@ -1937,19 +2495,14 @@
1937 prio += 150;2495 prio += 150;
1938 }2496 }
19392497
1940 if (bo.stocklevel_time < game().get_gametime() - 5 * 1000) {2498 if (get_stocklevel(bo, gametime) == 0) {
1941 bo.stocklevel = get_stocklevel(static_cast<size_t>(bo.production_hint));
1942 bo.stocklevel_time = game().get_gametime();
1943 }
1944
1945 if (bo.stocklevel == 0) {
1946 prio *= 2;2499 prio *= 2;
1947 }2500 }
19482501
1949 // to prevent to many quaries on one spot2502 // to prevent to many quaries on one spot
1950 prio = prio - 50 * bf->producers_nearby.at(bo.outputs.at(0));2503 prio = prio - 50 * bf->producers_nearby.at(bo.outputs.at(0));
19512504
1952 } else if (bo.is_hunter) {2505 } else if (bo.is(BuildingAttribute::kHunter)) {
19532506
1954 if (bf->critters_nearby < 5) {2507 if (bf->critters_nearby < 5) {
1955 continue;2508 continue;
@@ -1967,26 +2520,31 @@
1967 prio +=2520 prio +=
1968 (bf->critters_nearby * 3) - 8 - 5 * bf->producers_nearby.at(bo.outputs.at(0));2521 (bf->critters_nearby * 3) - 8 - 5 * bf->producers_nearby.at(bo.outputs.at(0));
19692522
1970 } else if (bo.is_fisher) { // fisher2523 } else if (bo.is(BuildingAttribute::kFisher)) { // fisher
19712524
1972 if (bf->water_nearby < 2 || bf->fish_nearby < 2) {2525 if (bf->water_nearby < 2 || bf->fish_nearby < 2) {
1973 continue;2526 continue;
1974 }2527 }
19752528
1976 if (bo.new_building == BuildingNecessity::kForced) {2529 if (bo.new_building == BuildingNecessity::kForced) {
1977 prio += 20;2530 prio += 200;
1978 }2531 }
19792532
1980 // Overdue priority here2533 // Overdue priority here
1981 prio += bo.primary_priority;2534 prio += bo.primary_priority;
19822535
1983 prio -= bf->producers_nearby.at(bo.outputs.at(0)) * 20;2536 prio -= bf->producers_nearby.at(bo.outputs.at(0)) * 20;
1984 prio += bf->supporters_nearby.at(bo.outputs.at(0)) * 10;2537 prio += bf->supporters_nearby.at(bo.outputs.at(0)) * 20;
19852538
1986 prio += -5 + bf->fish_nearby;2539 prio +=
2540 -5 +
2541 bf->fish_nearby * (1 + std::abs(management_data.get_military_number_at(63) / 15));
2542 if (resource_necessity_water_needed_) {
2543 prio *= 3;
2544 }
19872545
1988 } else if (bo.production_hint >= 0) {2546 } else if (bo.production_hint >= 0) {
1989 if (bo.plants_trees) {2547 if (bo.is(BuildingAttribute::kRanger)) {
1990 assert(bo.cnt_target > 0);2548 assert(bo.cnt_target > 0);
1991 } else {2549 } else {
1992 bo.cnt_target =2550 bo.cnt_target =
@@ -1996,39 +2554,41 @@
1996 // They have no own primary priority2554 // They have no own primary priority
1997 assert(bo.primary_priority == 0);2555 assert(bo.primary_priority == 0);
19982556
1999 if (bo.plants_trees) { // RANGERS2557 if (bo.is(BuildingAttribute::kRanger)) {
20002558
2001 assert(bo.new_building == BuildingNecessity::kNeeded);2559 assert(bo.new_building == BuildingNecessity::kNeeded);
20022560
2003 // if there are too many trees nearby2561 prio = 0;
2004 if (bf->trees_nearby > 25 && bo.total_count() >= 1) {
2005 continue;
2006 }
2007
2008 // for small starting spots - to prevent crowding by rangers and trees
2009 if (spots_ < (4 * bo.total_count()) && bo.total_count() > 0) {
2010 continue;
2011 }
20122562
2013 if (bo.total_count() == 0) {2563 if (bo.total_count() == 0) {
2014 prio = 200;2564 prio += 200;
2015 } else {2565 } else {
2016 prio = 50 / bo.total_count();2566 prio += std::abs(management_data.get_military_number_at(66)) *
2567 (bo.cnt_target - bo.total_count());
2017 }2568 }
20182569 prio -= bf->water_nearby / 5;
2019 // considering producers2570
2020 prio += std::min<uint8_t>(bf->producers_nearby.at(bo.production_hint), 4) * 5 -2571 prio += management_data.neuron_pool[67].get_result_safe(
2021 new_buildings_stop_ * 15 - bf->space_consumers_nearby * 5 -2572 bf->producers_nearby.at(bo.production_hint) * 5, kAbsValue) /
2022 bf->rocks_nearby / 3 + bf->trees_nearby / 2 +2573 2;
2023 std::min<uint8_t>(bf->supporters_nearby.at(bo.production_hint), 4) * 3;2574
2575 prio +=
2576 management_data.neuron_pool[49].get_result_safe(bf->trees_nearby, kAbsValue) /
2577 5;
2578
2579 prio += bf->producers_nearby.at(bo.production_hint) * 5 -
2580 (expansion_type.get_expansion_type() != ExpansionMode::kEconomy) * 15 -
2581 bf->space_consumers_nearby * 5 - bf->rocks_nearby / 3 +
2582 bf->supporters_nearby.at(bo.production_hint) * 3;
20242583
2025 } else { // FISH BREEDERS and GAME KEEPERS2584 } else { // FISH BREEDERS and GAME KEEPERS
20262585
2027 // especially for fish breeders2586 // especially for fish breeders
2028 if (bo.need_water && (bf->water_nearby < 6 || bf->fish_nearby < 6)) {2587 if (bo.is(BuildingAttribute::kNeedsCoast) &&
2588 (bf->water_nearby < 6 || bf->fish_nearby < 6)) {
2029 continue;2589 continue;
2030 }2590 }
2031 if (bo.need_water) {2591 if (bo.is(BuildingAttribute::kNeedsCoast)) {
2032 prio += (-6 + bf->water_nearby) / 3;2592 prio += (-6 + bf->water_nearby) / 3;
2033 prio += (-6 + bf->fish_nearby) / 3;2593 prio += (-6 + bf->fish_nearby) / 3;
2034 }2594 }
@@ -2037,18 +2597,13 @@
2037 continue;2597 continue;
2038 }2598 }
20392599
2040 if (bo.stocklevel_time < game().get_gametime() - 5 * 1000) {2600 if (get_stocklevel(bo, gametime) > 50) {
2041 bo.stocklevel =
2042 get_stocklevel_by_hint(static_cast<size_t>(bo.production_hint));
2043 bo.stocklevel_time = game().get_gametime();
2044 }
2045 if (bo.stocklevel > 50) {
2046 continue;2601 continue;
2047 }2602 }
20482603
2049 if (bo.total_count() == 0) {2604 if (bo.total_count() == 0) {
2050 prio += 100;2605 prio += 100;
2051 } else if (!bo.need_water) {2606 } else if (!bo.is(BuildingAttribute::kNeedsCoast)) {
2052 prio += 10 / bo.total_count();2607 prio += 10 / bo.total_count();
2053 }2608 }
20542609
@@ -2060,21 +2615,18 @@
2060 }2615 }
2061 }2616 }
20622617
2063 } else if (bo.recruitment && !new_buildings_stop_) {2618 } else if (bo.is(BuildingAttribute::kRecruitment)) {
2064 // this will depend on number of mines_ and productionsites2619 prio = bo.primary_priority;
2065 if (static_cast<int32_t>((productionsites.size() + mines_.size()) / 30) >2620 prio -= bf->unowned_land_nearby * 2;
2066 bo.total_count() &&2621 prio -= (bf->enemy_nearby) * 100;
2067 (bo.cnt_under_construction + bo.unoccupied_count) == 0 &&2622 prio -= (expansion_type.get_expansion_type() != ExpansionMode::kEconomy) * 100;
2068 // but only if current buildings are utilized enough
2069 (bo.total_count() == 0 || bo.current_stats > 60)) {
2070 prio = 10;
2071 }
2072 } else { // finally normal productionsites2623 } else { // finally normal productionsites
2073 assert(bo.production_hint < 0);2624 assert(bo.production_hint < 0);
20742625
2075 if (bo.new_building == BuildingNecessity::kForced) {2626 if (bo.new_building == BuildingNecessity::kForced) {
2076 prio += 150;2627 prio += 150;
2077 } else if (bo.is_shipyard) {2628 assert(!bo.is(BuildingAttribute::kShipyard));
2629 } else if (bo.is(BuildingAttribute::kShipyard)) {
2078 assert(bo.new_building == BuildingNecessity::kAllowed);2630 assert(bo.new_building == BuildingNecessity::kAllowed);
2079 if (!seafaring_economy) {2631 if (!seafaring_economy) {
2080 continue;2632 continue;
@@ -2089,33 +2641,43 @@
2089 // we check separatelly buildings with no inputs and some inputs2641 // we check separatelly buildings with no inputs and some inputs
2090 if (bo.inputs.empty()) {2642 if (bo.inputs.empty()) {
20912643
2092 if (bo.space_consumer) {2644 assert(!bo.is(BuildingAttribute::kShipyard));
2645
2646 if (bo.is(BuildingAttribute::kSpaceConsumer)) {
2093 // we dont like trees nearby2647 // we dont like trees nearby
2094 prio += 1 - bf->trees_nearby / 15;2648 prio += 1 - bf->trees_nearby / 15;
2095 // we attempt to cluster space consumers together2649 // we attempt to cluster space consumers together
2096 prio += bf->space_consumers_nearby * 2;2650 prio += bf->space_consumers_nearby * 2;
2097 // and be far from rangers2651 // and be far from rangers
2098 prio += 1 - bf->rangers_nearby * 3;2652 prio += 1 -
2653 bf->rangers_nearby *
2654 std::abs(management_data.get_military_number_at(102)) / 5;
2099 } else {2655 } else {
2100 // leave some free space between them2656 // leave some free space between them
2101 prio -= bf->producers_nearby.at(bo.outputs.at(0)) * 5;2657 prio -= bf->producers_nearby.at(bo.outputs.at(0)) *
2102 }2658 std::abs(management_data.get_military_number_at(108)) / 5;
21032659 }
2104 if (bo.space_consumer && !bf->water_nearby) { // not close to water2660
2105 prio += 1;2661 if (bo.is(BuildingAttribute::kSpaceConsumer) &&
2106 }2662 bf->water_nearby) { // not close to water
21072663 prio -= std::abs(management_data.get_military_number_at(103)) / 5;
2108 if (bo.space_consumer &&2664 }
2109 !bf->unowned_mines_spots_nearby) { // not close to mountains2665
2110 prio += 1;2666 if (bo.is(BuildingAttribute::kSpaceConsumer) &&
2667 bf->unowned_mines_spots_nearby) { // not close to mountains
2668 prio -= std::abs(management_data.get_military_number_at(104)) / 5;
2111 }2669 }
2112 }2670 }
21132671
2114 else if (bo.is_shipyard) {2672 else if (bo.is(BuildingAttribute::kShipyard)) {
2115 // for now AI builds only one shipyard2673 // for now AI builds only one shipyard
2116 if (bf->open_water_nearby > 1 && (bo.total_count() - bo.unconnected_count) == 0 &&2674 assert(bo.total_count() == 0);
2117 seafaring_economy) {2675 if (bf->open_water_nearby > 3 && seafaring_economy) {
2118 prio += productionsites.size() * 5 + bf->open_water_nearby;2676 prio += productionsites.size() * 5 +
2677 bf->open_water_nearby *
2678 std::abs(management_data.get_military_number_at(109)) / 10;
2679 } else {
2680 continue;
2119 }2681 }
2120 }2682 }
21212683
@@ -2125,11 +2687,11 @@
21252687
2126 // bonus for big buildings if shortage of big fields2688 // bonus for big buildings if shortage of big fields
2127 if (spots_avail.at(BUILDCAPS_BIG) <= 5 && bo.desc->get_size() == 3) {2689 if (spots_avail.at(BUILDCAPS_BIG) <= 5 && bo.desc->get_size() == 3) {
2128 prio += 10;2690 prio += std::abs(management_data.get_military_number_at(105)) / 5;
2129 }2691 }
21302692
2131 if (spots_avail.at(BUILDCAPS_MEDIUM) <= 5 && bo.desc->get_size() == 2) {2693 if (spots_avail.at(BUILDCAPS_MEDIUM) <= 5 && bo.desc->get_size() == 2) {
2132 prio += 5;2694 prio += std::abs(management_data.get_military_number_at(106)) / 5;
2133 }2695 }
21342696
2135 // +1 if any consumers_ are nearby2697 // +1 if any consumers_ are nearby
@@ -2139,152 +2701,69 @@
2139 consumers_nearby_count += bf->consumers_nearby.at(bo.outputs.at(k));2701 consumers_nearby_count += bf->consumers_nearby.at(bo.outputs.at(k));
21402702
2141 if (consumers_nearby_count > 0) {2703 if (consumers_nearby_count > 0) {
2142 prio += 1;2704 prio += std::abs(management_data.get_military_number_at(107)) / 3;
2143 }2705 }
2144 }2706 }
21452707
2146 // Consider border with exemption of some huts2708 // Consider border with exemption of some huts
2147 if (!(bo.need_trees || bo.need_water || bo.is_fisher)) {2709 if (!(bo.is(BuildingAttribute::kLumberjack) || bo.is(BuildingAttribute::kNeedsCoast) ||
2710 bo.is(BuildingAttribute::kFisher))) {
2148 prio = recalc_with_border_range(*bf, prio);2711 prio = recalc_with_border_range(*bf, prio);
2149 } else if (bf->near_border && (bo.need_trees || bo.need_water)) {2712 } else if (bf->near_border && (bo.is(BuildingAttribute::kLumberjack) ||
2713 bo.is(BuildingAttribute::kNeedsCoast))) {
2150 prio /= 2;2714 prio /= 2;
2151 }2715 }
21522716
2153 } // production sites done2717 } // production sites done
2154 else if (bo.type == BuildingObserver::Type::kMilitarysite) {2718 else if (bo.type == BuildingObserver::Type::kMilitarysite) {
21552719
2156 if (!(bf->unowned_land_nearby || bf->enemy_nearby)) {2720 assert(prio == 0);
2157 continue;2721 prio = bo.primary_priority;
2158 }2722
21592723 // Two possibilities why to construct militarysite here
2160 if (military_last_build_ > gametime - 15 * 1000) {2724 if (!bf->defense_msite_allowed &&
2161 continue;2725 bf->nearest_buildable_spot_nearby < bo.desc->get_conquers() &&
2162 }2726 (bf->military_in_constr_nearby + bf->military_unstationed) <
21632727 concurent_ms_in_constr_no_enemy) {
2164 // This is another restriction of military building - but general2728 // it will conquer new buildable spots for buildings or mines
2165 if (bf->enemy_nearby && bo.fighting_type) {2729 ;
2166 ;2730 } else if (bf->defense_msite_allowed &&
2167 } // it is ok, go on2731 (bf->military_in_constr_nearby + bf->military_unstationed) <
2168 else if (bf->unowned_mines_spots_nearby > 2 &&2732 concurent_ms_in_constr_enemy_nearby) {
2169 (bo.mountain_conqueror || bo.expansion_type)) {2733 // we need it to increase capacity on the field
2170 ;2734 if (bo.fighting_type) {
2171 } // it is ok, go on2735 prio += 5;
2172 else if (bo.expansion_type) {2736 }
2173 if (bo.desc->get_size() == 2 && gametime % 2 >= 1) {2737 } else {
2174 continue;2738 continue;
2175 }2739 }
2176 if (bo.desc->get_size() == 3 && gametime % 4 >= 1) {2740 if (bf->unowned_mines_spots_nearby > 2 && bo.mountain_conqueror) {
2177 continue;2741 prio += 5;
2178 };2742 }
2179 } else {2743 prio += std::abs(management_data.get_military_number_at(35)) / 5 *
2180 continue;2744 (static_cast<int16_t>(bo.desc->get_conquers()) -
2181 } // the building is not suitable for situation2745 static_cast<int16_t>(bf->nearest_buildable_spot_nearby));
21822746
2183 // score here is a compound of various input values
2184 // usually resources in vicinity, but when enemy is nearby
2185 // additional bonus is added
2186 if (bf->enemy_nearby) {
2187 prio += bf->military_loneliness / 3;
2188 prio += (20 - bf->area_military_capacity) * 10;
2189 prio -= bo.build_material_shortage * 50;
2190 prio -= (bf->military_in_constr_nearby + bf->military_unstationed) * 50;
2191 } else {
2192 if (bf->near_border) {
2193 prio += 50;
2194 prio -= bo.build_material_shortage * 150;
2195 } else {
2196 prio -= bo.build_material_shortage * 500; // prohibitive
2197 }
2198 prio -= (bf->military_in_constr_nearby + bf->military_unstationed) * 150;
2199 prio += (5 - bf->own_military_sites_nearby_()) * 15;
2200 }
2201 prio += bf->unconnected_nearby * 50;
2202 prio += bf->unowned_land_nearby * resource_necessity_territory_ / 100;
2203 prio += bf->unowned_mines_spots_nearby * resource_necessity_mines_ / 100;
2204 prio +=
2205 ((bf->unowned_mines_spots_nearby > 0) ? 35 : 0) * resource_necessity_mines_ / 100;
2206 prio += bf->rocks_nearby / 2;
2207 prio += bf->water_nearby;
2208 prio += bf->distant_water * resource_necessity_water_needed_ / 100;
2209 prio += bf->military_loneliness / 10;
2210 prio += bf->trees_nearby / 3;
2211 if (bf->portspace_nearby == ExtendedBool::kTrue) {
2212 if (num_ports == 0) {
2213 prio += 100;
2214 } else {
2215 prio += 25;
2216 }
2217 }
2218 // sometimes expansion is stalled and this is to help boost it
2219 if (msites_in_constr() == 0 && vacant_mil_positions_ <= 2) {
2220 prio += 10;
2221 if (bf->enemy_nearby) {
2222 prio += 20;
2223 }
2224 }
2225
2226 // additional score for bigger buildings
2227 int32_t prio_for_size = bo.desc->get_size() - 1;
2228 if (bf->enemy_nearby) {
2229 prio_for_size *= 30;
2230 } else {
2231 prio_for_size *= 5;
2232 }
2233 prio += prio_for_size;
The diff has been truncated for viewing.

Subscribers

People subscribed via source and target branches

to status/vote changes: