Merge lp:~widelands-dev/widelands/ai-post-b19-2 into lp:widelands
- ai-post-b19-2
- Merge into trunk
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 |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
GunChleoc | Approve | ||
Review via email: mp+325796@code.launchpad.net |
Commit message
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...
GunChleoc (gunchleoc) wrote : | # |
bunnybot (widelandsofficial) wrote : | # |
Continuous integration builds have changed state:
Travis build 2308. State: errored. Details: https:/
Appveyor build 2142. State: failed. Details: https:/
bunnybot (widelandsofficial) wrote : | # |
Continuous integration builds have changed state:
Travis build 2330. State: failed. Details: https:/
Appveyor build 2158. State: failed. Details: https:/
bunnybot (widelandsofficial) wrote : | # |
Continuous integration builds have changed state:
Travis build 2332. State: errored. Details: https:/
Appveyor build 2160. State: failed. Details: https:/
bunnybot (widelandsofficial) wrote : | # |
Continuous integration builds have changed state:
Travis build 2335. State: errored. Details: https:/
Appveyor build 2163. State: success. Details: https:/
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.
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:
woodcutter:
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....
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:
> woodcutter:
You mean like we have for the port & barracks? I could implement that
pretty easily.
TiborB (tiborb95) wrote : | # |
>> I can introduce bunch of new ai_hints like "is_bakery", though opposite would be better (per each tribe):
>> bakery:
>> woodcutter:
?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
GunChleoc (gunchleoc) wrote : | # |
>>> I can introduce bunch of new ai_hints like "is_bakery", though opposite would be better (per each tribe):
>>> bakery:
>>> woodcutter:
>
> ?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:
and this:
AI hints will certainly work though.
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.
GunChleoc (gunchleoc) wrote : | # |
Sounds good to me. Holler if you need help.
bunnybot (widelandsofficial) wrote : | # |
Continuous integration builds have changed state:
Travis build 2339. State: failed. Details: https:/
Appveyor build 2167. State: success. Details: https:/
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.
TiborB (tiborb95) wrote : | # |
@Gun,
I found that the game crashes on line:
if (field.
(gdb) bt
#0 0x0000000000ce6f5a in Widelands:
at /var/widelands2
#1 0x000000000111c015 in DefaultAI:
at /var/widelands2
#2 0x000000000111bc9e in DefaultAI:
at /var/widelands2
Do you know what had you changed? It worked for sure before...
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..
TiborB (tiborb95) wrote : | # |
re:
if (field.
crash
it crashes also with brand new game, so it is not related to save/load
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.
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.
SirVer (sirver) wrote : | # |
drive by: I like this stack overflow for information about dynamic_cast<> cost: https:/
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.
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://
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.
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
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(
If somebody mods a tribe with even more mine upgrades, or many different types of iron ore producers, the assertion won't hold.
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..
GunChleoc (gunchleoc) wrote : | # |
Sounds good to me.
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.
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....
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...
GunChleoc (gunchleoc) wrote : | # |
I did a few small cleanups, this is ready to go now. Thanks for taking on this huge job!
@bunnybot merge
TiborB (tiborb95) wrote : | # |
I am bit afraid of reaction of players, the change of behavior is really significant
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 ;)
GunChleoc (gunchleoc) wrote : | # |
We still have codecheck warnings. Travis is having problems today, so best wait until tomorrow and fix them then.
bunnybot (widelandsofficial) wrote : | # |
Continuous integration builds have changed state:
Travis build 2392. State: errored. Details: https:/
Appveyor build 2220. State: success. Details: https:/
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:/
bunnybot (widelandsofficial) wrote : | # |
Continuous integration builds have changed state:
Travis build 2403. State: failed. Details: https:/
Appveyor build 2231. State: success. Details: https:/
bunnybot (widelandsofficial) wrote : | # |
Continuous integration builds have changed state:
Travis build 2406. State: passed. Details: https:/
Appveyor build 2234. State: success. Details: https:/
TiborB (tiborb95) wrote : | # |
CI seems to be OK now. Can it be merged?
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.
TiborB (tiborb95) wrote : | # |
Oh, I did not know such feature exists. My editor (geany) has it so I will enable it...
Preview Diff
1 | === modified file 'data/tribes/atlanteans.lua' | |||
2 | --- data/tribes/atlanteans.lua 2017-04-30 10:30:02 +0000 | |||
3 | +++ data/tribes/atlanteans.lua 2017-07-03 17:39:38 +0000 | |||
4 | @@ -352,4 +352,9 @@ | |||
5 | 352 | headquarters = "atlanteans_headquarters", | 352 | headquarters = "atlanteans_headquarters", |
6 | 353 | port = "atlanteans_port", | 353 | port = "atlanteans_port", |
7 | 354 | barracks = "atlanteans_barracks", | 354 | barracks = "atlanteans_barracks", |
8 | 355 | bakery = "atlanteans_bakery", | ||
9 | 356 | ironore = "iron_ore", | ||
10 | 357 | rawlog = "log", | ||
11 | 358 | refinedlog = "planks", | ||
12 | 359 | granite = "granite", | ||
13 | 355 | } | 360 | } |
14 | 356 | 361 | ||
15 | === modified file 'data/tribes/barbarians.lua' | |||
16 | --- data/tribes/barbarians.lua 2017-04-30 10:30:02 +0000 | |||
17 | +++ data/tribes/barbarians.lua 2017-07-03 17:39:38 +0000 | |||
18 | @@ -285,4 +285,9 @@ | |||
19 | 285 | headquarters = "barbarians_headquarters", | 285 | headquarters = "barbarians_headquarters", |
20 | 286 | port = "barbarians_port", | 286 | port = "barbarians_port", |
21 | 287 | barracks = "barbarians_barracks", | 287 | barracks = "barbarians_barracks", |
22 | 288 | bakery = "barbarians_bakery", | ||
23 | 289 | ironore = "iron_ore", | ||
24 | 290 | rawlog = "log", | ||
25 | 291 | refinedlog = "blackwood", | ||
26 | 292 | granite = "granite", | ||
27 | 288 | } | 293 | } |
28 | 289 | 294 | ||
29 | === modified file 'data/tribes/buildings/productionsites/atlanteans/bakery/init.lua' | |||
30 | --- data/tribes/buildings/productionsites/atlanteans/bakery/init.lua 2017-02-10 09:40:17 +0000 | |||
31 | +++ data/tribes/buildings/productionsites/atlanteans/bakery/init.lua 2017-07-03 17:39:38 +0000 | |||
32 | @@ -32,7 +32,7 @@ | |||
33 | 32 | }, | 32 | }, |
34 | 33 | 33 | ||
35 | 34 | aihints = { | 34 | aihints = { |
37 | 35 | forced_after = 1200, | 35 | basic_amount = 1, |
38 | 36 | prohibited_till = 900 | 36 | prohibited_till = 900 |
39 | 37 | }, | 37 | }, |
40 | 38 | 38 | ||
41 | 39 | 39 | ||
42 | === modified file 'data/tribes/buildings/productionsites/atlanteans/barracks/init.lua' | |||
43 | --- data/tribes/buildings/productionsites/atlanteans/barracks/init.lua 2017-02-10 09:40:17 +0000 | |||
44 | +++ data/tribes/buildings/productionsites/atlanteans/barracks/init.lua 2017-07-03 17:39:38 +0000 | |||
45 | @@ -34,7 +34,6 @@ | |||
46 | 34 | }, | 34 | }, |
47 | 35 | 35 | ||
48 | 36 | aihints = { | 36 | aihints = { |
49 | 37 | forced_after = 1000, | ||
50 | 38 | very_weak_ai_limit = 1, | 37 | very_weak_ai_limit = 1, |
51 | 39 | weak_ai_limit = 3 | 38 | weak_ai_limit = 3 |
52 | 40 | }, | 39 | }, |
53 | 41 | 40 | ||
54 | === modified file 'data/tribes/buildings/productionsites/atlanteans/blackroot_farm/init.lua' | |||
55 | --- data/tribes/buildings/productionsites/atlanteans/blackroot_farm/init.lua 2015-12-11 16:54:00 +0000 | |||
56 | +++ data/tribes/buildings/productionsites/atlanteans/blackroot_farm/init.lua 2017-07-03 17:39:38 +0000 | |||
57 | @@ -29,7 +29,6 @@ | |||
58 | 29 | 29 | ||
59 | 30 | aihints = { | 30 | aihints = { |
60 | 31 | prohibited_till = 600, | 31 | prohibited_till = 600, |
61 | 32 | forced_after = 800, | ||
62 | 33 | space_consumer = true | 32 | space_consumer = true |
63 | 34 | }, | 33 | }, |
64 | 35 | 34 | ||
65 | 36 | 35 | ||
66 | === modified file 'data/tribes/buildings/productionsites/atlanteans/crystalmine/init.lua' | |||
67 | --- data/tribes/buildings/productionsites/atlanteans/crystalmine/init.lua 2017-02-18 23:07:56 +0000 | |||
68 | +++ data/tribes/buildings/productionsites/atlanteans/crystalmine/init.lua 2017-07-03 17:39:38 +0000 | |||
69 | @@ -36,6 +36,7 @@ | |||
70 | 36 | 36 | ||
71 | 37 | aihints = { | 37 | aihints = { |
72 | 38 | mines = "stones", | 38 | mines = "stones", |
73 | 39 | basic_amount = 1, | ||
74 | 39 | prohibited_till = 600 | 40 | prohibited_till = 600 |
75 | 40 | }, | 41 | }, |
76 | 41 | 42 | ||
77 | 42 | 43 | ||
78 | === modified file 'data/tribes/buildings/productionsites/atlanteans/farm/init.lua' | |||
79 | --- data/tribes/buildings/productionsites/atlanteans/farm/init.lua 2016-01-28 05:24:34 +0000 | |||
80 | +++ data/tribes/buildings/productionsites/atlanteans/farm/init.lua 2017-07-03 17:39:38 +0000 | |||
81 | @@ -30,9 +30,9 @@ | |||
82 | 30 | 30 | ||
83 | 31 | aihints = { | 31 | aihints = { |
84 | 32 | space_consumer = true, | 32 | space_consumer = true, |
85 | 33 | basic_amount = 1, | ||
86 | 33 | -- Farm needs spidercloth to be built and spidercloth needs corn for production | 34 | -- Farm needs spidercloth to be built and spidercloth needs corn for production |
87 | 34 | -- -> farm should be built ASAP! | 35 | -- -> farm should be built ASAP! |
88 | 35 | forced_after = 400, | ||
89 | 36 | prohibited_till = 200 | 36 | prohibited_till = 200 |
90 | 37 | }, | 37 | }, |
91 | 38 | 38 | ||
92 | 39 | 39 | ||
93 | === modified file 'data/tribes/buildings/productionsites/atlanteans/fishers_house/init.lua' | |||
94 | --- data/tribes/buildings/productionsites/atlanteans/fishers_house/init.lua 2015-12-11 16:54:00 +0000 | |||
95 | +++ data/tribes/buildings/productionsites/atlanteans/fishers_house/init.lua 2017-07-03 17:39:38 +0000 | |||
96 | @@ -26,6 +26,7 @@ | |||
97 | 26 | 26 | ||
98 | 27 | aihints = { | 27 | aihints = { |
99 | 28 | needs_water = true, | 28 | needs_water = true, |
100 | 29 | basic_amount = 1, | ||
101 | 29 | prohibited_till = 600 | 30 | prohibited_till = 600 |
102 | 30 | }, | 31 | }, |
103 | 31 | 32 | ||
104 | 32 | 33 | ||
105 | === modified file 'data/tribes/buildings/productionsites/atlanteans/mill/init.lua' | |||
106 | --- data/tribes/buildings/productionsites/atlanteans/mill/init.lua 2016-10-30 19:15:45 +0000 | |||
107 | +++ data/tribes/buildings/productionsites/atlanteans/mill/init.lua 2017-07-03 17:39:38 +0000 | |||
108 | @@ -33,6 +33,7 @@ | |||
109 | 33 | }, | 33 | }, |
110 | 34 | 34 | ||
111 | 35 | aihints = { | 35 | aihints = { |
112 | 36 | basic_amount = 1, | ||
113 | 36 | prohibited_till = 600 | 37 | prohibited_till = 600 |
114 | 37 | }, | 38 | }, |
115 | 38 | 39 | ||
116 | 39 | 40 | ||
117 | === modified file 'data/tribes/buildings/productionsites/atlanteans/sawmill/init.lua' | |||
118 | --- data/tribes/buildings/productionsites/atlanteans/sawmill/init.lua 2016-12-11 09:29:28 +0000 | |||
119 | +++ data/tribes/buildings/productionsites/atlanteans/sawmill/init.lua 2017-07-03 17:39:38 +0000 | |||
120 | @@ -31,7 +31,7 @@ | |||
121 | 31 | }, | 31 | }, |
122 | 32 | 32 | ||
123 | 33 | aihints = { | 33 | aihints = { |
125 | 34 | forced_after = 250, | 34 | basic_amount = 2, |
126 | 35 | prohibited_till = 250, | 35 | prohibited_till = 250, |
127 | 36 | very_weak_ai_limit = 1, | 36 | very_weak_ai_limit = 1, |
128 | 37 | weak_ai_limit = 2 | 37 | weak_ai_limit = 2 |
129 | 38 | 38 | ||
130 | === modified file 'data/tribes/buildings/productionsites/atlanteans/smokery/init.lua' | |||
131 | --- data/tribes/buildings/productionsites/atlanteans/smokery/init.lua 2016-10-26 19:21:32 +0000 | |||
132 | +++ data/tribes/buildings/productionsites/atlanteans/smokery/init.lua 2017-07-03 17:39:38 +0000 | |||
133 | @@ -32,7 +32,7 @@ | |||
134 | 32 | }, | 32 | }, |
135 | 33 | 33 | ||
136 | 34 | aihints = { | 34 | aihints = { |
138 | 35 | forced_after = 800, | 35 | basic_amount = 1, |
139 | 36 | prohibited_till = 180, | 36 | prohibited_till = 180, |
140 | 37 | very_weak_ai_limit = 1, | 37 | very_weak_ai_limit = 1, |
141 | 38 | weak_ai_limit = 2 | 38 | weak_ai_limit = 2 |
142 | 39 | 39 | ||
143 | === modified file 'data/tribes/buildings/productionsites/atlanteans/spiderfarm/init.lua' | |||
144 | --- data/tribes/buildings/productionsites/atlanteans/spiderfarm/init.lua 2016-09-03 14:59:10 +0000 | |||
145 | +++ data/tribes/buildings/productionsites/atlanteans/spiderfarm/init.lua 2017-07-03 17:39:38 +0000 | |||
146 | @@ -31,7 +31,7 @@ | |||
147 | 31 | }, | 31 | }, |
148 | 32 | 32 | ||
149 | 33 | aihints = { | 33 | aihints = { |
151 | 34 | forced_after = 450, | 34 | basic_amount = 1, |
152 | 35 | prohibited_till = 350 | 35 | prohibited_till = 350 |
153 | 36 | }, | 36 | }, |
154 | 37 | 37 | ||
155 | 38 | 38 | ||
156 | === modified file 'data/tribes/buildings/productionsites/atlanteans/toolsmithy/init.lua' | |||
157 | --- data/tribes/buildings/productionsites/atlanteans/toolsmithy/init.lua 2016-10-30 19:15:45 +0000 | |||
158 | +++ data/tribes/buildings/productionsites/atlanteans/toolsmithy/init.lua 2017-07-03 17:39:38 +0000 | |||
159 | @@ -32,7 +32,6 @@ | |||
160 | 32 | }, | 32 | }, |
161 | 33 | 33 | ||
162 | 34 | aihints = { | 34 | aihints = { |
163 | 35 | forced_after = 500, | ||
164 | 36 | prohibited_till = 450 | 35 | prohibited_till = 450 |
165 | 37 | }, | 36 | }, |
166 | 38 | 37 | ||
167 | 39 | 38 | ||
168 | === modified file 'data/tribes/buildings/productionsites/atlanteans/weaving_mill/init.lua' | |||
169 | --- data/tribes/buildings/productionsites/atlanteans/weaving_mill/init.lua 2016-12-14 09:09:34 +0000 | |||
170 | +++ data/tribes/buildings/productionsites/atlanteans/weaving_mill/init.lua 2017-07-03 17:39:38 +0000 | |||
171 | @@ -32,8 +32,8 @@ | |||
172 | 32 | }, | 32 | }, |
173 | 33 | 33 | ||
174 | 34 | aihints = { | 34 | aihints = { |
177 | 35 | forced_after = 600, | 35 | prohibited_till = 400, |
178 | 36 | prohibited_till = 450, | 36 | basic_amount = 1, |
179 | 37 | very_weak_ai_limit = 1, | 37 | very_weak_ai_limit = 1, |
180 | 38 | weak_ai_limit = 2 | 38 | weak_ai_limit = 2 |
181 | 39 | }, | 39 | }, |
182 | 40 | 40 | ||
183 | === modified file 'data/tribes/buildings/productionsites/barbarians/barracks/init.lua' | |||
184 | --- data/tribes/buildings/productionsites/barbarians/barracks/init.lua 2017-02-10 09:40:17 +0000 | |||
185 | +++ data/tribes/buildings/productionsites/barbarians/barracks/init.lua 2017-07-03 17:39:38 +0000 | |||
186 | @@ -33,7 +33,7 @@ | |||
187 | 33 | }, | 33 | }, |
188 | 34 | 34 | ||
189 | 35 | aihints = { | 35 | aihints = { |
191 | 36 | forced_after = 1000, | 36 | basic_amount = 1, |
192 | 37 | very_weak_ai_limit = 1, | 37 | very_weak_ai_limit = 1, |
193 | 38 | weak_ai_limit = 3 | 38 | weak_ai_limit = 3 |
194 | 39 | }, | 39 | }, |
195 | 40 | 40 | ||
196 | === modified file 'data/tribes/buildings/productionsites/barbarians/farm/init.lua' | |||
197 | --- data/tribes/buildings/productionsites/barbarians/farm/init.lua 2016-01-28 05:24:34 +0000 | |||
198 | +++ data/tribes/buildings/productionsites/barbarians/farm/init.lua 2017-07-03 17:39:38 +0000 | |||
199 | @@ -40,8 +40,7 @@ | |||
200 | 40 | }, | 40 | }, |
201 | 41 | 41 | ||
202 | 42 | aihints = { | 42 | aihints = { |
205 | 43 | space_consumer = true, | 43 | space_consumer = true |
204 | 44 | forced_after = 600 | ||
206 | 45 | }, | 44 | }, |
207 | 46 | 45 | ||
208 | 47 | working_positions = { | 46 | working_positions = { |
209 | 48 | 47 | ||
210 | === modified file 'data/tribes/buildings/productionsites/barbarians/gamekeepers_hut/init.lua' | |||
211 | --- data/tribes/buildings/productionsites/barbarians/gamekeepers_hut/init.lua 2015-12-11 16:54:00 +0000 | |||
212 | +++ data/tribes/buildings/productionsites/barbarians/gamekeepers_hut/init.lua 2017-07-03 17:39:38 +0000 | |||
213 | @@ -35,7 +35,8 @@ | |||
214 | 35 | 35 | ||
215 | 36 | aihints = { | 36 | aihints = { |
216 | 37 | renews_map_resource = "meat", | 37 | renews_map_resource = "meat", |
218 | 38 | prohibited_till = 900 | 38 | prohibited_till = 900, |
219 | 39 | basic_amount = 1 | ||
220 | 39 | }, | 40 | }, |
221 | 40 | 41 | ||
222 | 41 | working_positions = { | 42 | working_positions = { |
223 | 42 | 43 | ||
224 | === modified file 'data/tribes/buildings/productionsites/barbarians/hunters_hut/init.lua' | |||
225 | --- data/tribes/buildings/productionsites/barbarians/hunters_hut/init.lua 2015-12-11 16:54:00 +0000 | |||
226 | +++ data/tribes/buildings/productionsites/barbarians/hunters_hut/init.lua 2017-07-03 17:39:38 +0000 | |||
227 | @@ -34,7 +34,8 @@ | |||
228 | 34 | }, | 34 | }, |
229 | 35 | 35 | ||
230 | 36 | aihints = { | 36 | aihints = { |
232 | 37 | prohibited_till = 500 | 37 | prohibited_till = 500, |
233 | 38 | basic_amount = 1 | ||
234 | 38 | }, | 39 | }, |
235 | 39 | 40 | ||
236 | 40 | working_positions = { | 41 | working_positions = { |
237 | 41 | 42 | ||
238 | === modified file 'data/tribes/buildings/productionsites/barbarians/lime_kiln/init.lua' | |||
239 | --- data/tribes/buildings/productionsites/barbarians/lime_kiln/init.lua 2016-09-03 14:59:10 +0000 | |||
240 | +++ data/tribes/buildings/productionsites/barbarians/lime_kiln/init.lua 2017-07-03 17:39:38 +0000 | |||
241 | @@ -31,9 +31,9 @@ | |||
242 | 31 | }, | 31 | }, |
243 | 32 | 32 | ||
244 | 33 | aihints = { | 33 | aihints = { |
245 | 34 | forced_after = 600, | ||
246 | 35 | very_weak_ai_limit = 1, | 34 | very_weak_ai_limit = 1, |
248 | 36 | weak_ai_limit = 2 | 35 | weak_ai_limit = 2, |
249 | 36 | basic_amount = 1 | ||
250 | 37 | }, | 37 | }, |
251 | 38 | 38 | ||
252 | 39 | working_positions = { | 39 | working_positions = { |
253 | 40 | 40 | ||
254 | === modified file 'data/tribes/buildings/productionsites/barbarians/lumberjacks_hut/init.lua' | |||
255 | --- data/tribes/buildings/productionsites/barbarians/lumberjacks_hut/init.lua 2015-12-11 16:54:00 +0000 | |||
256 | +++ data/tribes/buildings/productionsites/barbarians/lumberjacks_hut/init.lua 2017-07-03 17:39:38 +0000 | |||
257 | @@ -32,8 +32,7 @@ | |||
258 | 32 | }, | 32 | }, |
259 | 33 | 33 | ||
260 | 34 | aihints = { | 34 | aihints = { |
263 | 35 | forced_after = 180, | 35 | basic_amount = 1, |
262 | 36 | prohibited_till = 180, | ||
264 | 37 | logproducer = true | 36 | logproducer = true |
265 | 38 | }, | 37 | }, |
266 | 39 | 38 | ||
267 | 40 | 39 | ||
268 | === modified file 'data/tribes/buildings/productionsites/barbarians/metal_workshop/init.lua' | |||
269 | --- data/tribes/buildings/productionsites/barbarians/metal_workshop/init.lua 2016-09-03 14:59:10 +0000 | |||
270 | +++ data/tribes/buildings/productionsites/barbarians/metal_workshop/init.lua 2017-07-03 17:39:38 +0000 | |||
271 | @@ -44,7 +44,7 @@ | |||
272 | 44 | }, | 44 | }, |
273 | 45 | 45 | ||
274 | 46 | aihints = { | 46 | aihints = { |
276 | 47 | forced_after = 400, | 47 | basic_amount = 2, |
277 | 48 | prohibited_till = 400 | 48 | prohibited_till = 400 |
278 | 49 | }, | 49 | }, |
279 | 50 | 50 | ||
280 | 51 | 51 | ||
281 | === modified file 'data/tribes/buildings/productionsites/barbarians/micro_brewery/init.lua' | |||
282 | --- data/tribes/buildings/productionsites/barbarians/micro_brewery/init.lua 2016-09-03 14:59:10 +0000 | |||
283 | +++ data/tribes/buildings/productionsites/barbarians/micro_brewery/init.lua 2017-07-03 17:39:38 +0000 | |||
284 | @@ -34,7 +34,6 @@ | |||
285 | 34 | }, | 34 | }, |
286 | 35 | 35 | ||
287 | 36 | aihints = { | 36 | aihints = { |
288 | 37 | forced_after = 500 | ||
289 | 38 | }, | 37 | }, |
290 | 39 | 38 | ||
291 | 40 | working_positions = { | 39 | working_positions = { |
292 | 41 | 40 | ||
293 | === modified file 'data/tribes/buildings/productionsites/barbarians/rangers_hut/init.lua' | |||
294 | --- data/tribes/buildings/productionsites/barbarians/rangers_hut/init.lua 2015-12-11 16:54:00 +0000 | |||
295 | +++ data/tribes/buildings/productionsites/barbarians/rangers_hut/init.lua 2017-07-03 17:39:38 +0000 | |||
296 | @@ -34,7 +34,7 @@ | |||
297 | 34 | aihints = { | 34 | aihints = { |
298 | 35 | renews_map_resource = "log", | 35 | renews_map_resource = "log", |
299 | 36 | space_consumer = true, | 36 | space_consumer = true, |
301 | 37 | prohibited_till = 200 | 37 | basic_amount = 1 |
302 | 38 | }, | 38 | }, |
303 | 39 | 39 | ||
304 | 40 | working_positions = { | 40 | working_positions = { |
305 | 41 | 41 | ||
306 | === modified file 'data/tribes/buildings/productionsites/barbarians/reed_yard/init.lua' | |||
307 | --- data/tribes/buildings/productionsites/barbarians/reed_yard/init.lua 2015-12-11 16:54:00 +0000 | |||
308 | +++ data/tribes/buildings/productionsites/barbarians/reed_yard/init.lua 2017-07-03 17:39:38 +0000 | |||
309 | @@ -27,7 +27,7 @@ | |||
310 | 27 | 27 | ||
311 | 28 | aihints = { | 28 | aihints = { |
312 | 29 | space_consumer = true, | 29 | space_consumer = true, |
314 | 30 | forced_after = 250, | 30 | basic_amount = 1, |
315 | 31 | prohibited_till = 250 | 31 | prohibited_till = 250 |
316 | 32 | }, | 32 | }, |
317 | 33 | 33 | ||
318 | 34 | 34 | ||
319 | === modified file 'data/tribes/buildings/productionsites/barbarians/smelting_works/init.lua' | |||
320 | --- data/tribes/buildings/productionsites/barbarians/smelting_works/init.lua 2016-10-24 10:07:57 +0000 | |||
321 | +++ data/tribes/buildings/productionsites/barbarians/smelting_works/init.lua 2017-07-03 17:39:38 +0000 | |||
322 | @@ -35,6 +35,7 @@ | |||
323 | 35 | 35 | ||
324 | 36 | aihints = { | 36 | aihints = { |
325 | 37 | prohibited_till = 400, | 37 | prohibited_till = 400, |
326 | 38 | basic_amount = 1, | ||
327 | 38 | very_weak_ai_limit = 1, | 39 | very_weak_ai_limit = 1, |
328 | 39 | weak_ai_limit = 2 | 40 | weak_ai_limit = 2 |
329 | 40 | }, | 41 | }, |
330 | 41 | 42 | ||
331 | === modified file 'data/tribes/buildings/productionsites/barbarians/tavern/init.lua' | |||
332 | --- data/tribes/buildings/productionsites/barbarians/tavern/init.lua 2016-10-24 10:10:06 +0000 | |||
333 | +++ data/tribes/buildings/productionsites/barbarians/tavern/init.lua 2017-07-03 17:39:38 +0000 | |||
334 | @@ -38,7 +38,7 @@ | |||
335 | 38 | }, | 38 | }, |
336 | 39 | 39 | ||
337 | 40 | aihints = { | 40 | aihints = { |
339 | 41 | forced_after = 900 | 41 | basic_amount = 1 |
340 | 42 | }, | 42 | }, |
341 | 43 | 43 | ||
342 | 44 | working_positions = { | 44 | working_positions = { |
343 | 45 | 45 | ||
344 | === modified file 'data/tribes/buildings/productionsites/barbarians/well/init.lua' | |||
345 | --- data/tribes/buildings/productionsites/barbarians/well/init.lua 2016-10-05 05:29:11 +0000 | |||
346 | +++ data/tribes/buildings/productionsites/barbarians/well/init.lua 2017-07-03 17:39:38 +0000 | |||
347 | @@ -33,8 +33,7 @@ | |||
348 | 33 | 33 | ||
349 | 34 | aihints = { | 34 | aihints = { |
350 | 35 | mines_water = true, | 35 | mines_water = true, |
353 | 36 | prohibited_till = 800, | 36 | basic_amount = 1 |
352 | 37 | forced_after = 800 | ||
354 | 38 | }, | 37 | }, |
355 | 39 | 38 | ||
356 | 40 | working_positions = { | 39 | working_positions = { |
357 | 41 | 40 | ||
358 | === modified file 'data/tribes/buildings/productionsites/barbarians/wood_hardener/init.lua' | |||
359 | --- data/tribes/buildings/productionsites/barbarians/wood_hardener/init.lua 2016-09-03 14:59:10 +0000 | |||
360 | +++ data/tribes/buildings/productionsites/barbarians/wood_hardener/init.lua 2017-07-03 17:39:38 +0000 | |||
361 | @@ -38,7 +38,7 @@ | |||
362 | 38 | }, | 38 | }, |
363 | 39 | 39 | ||
364 | 40 | aihints = { | 40 | aihints = { |
366 | 41 | forced_after = 250, | 41 | basic_amount = 1, |
367 | 42 | prohibited_till = 250, | 42 | prohibited_till = 250, |
368 | 43 | very_weak_ai_limit = 1, | 43 | very_weak_ai_limit = 1, |
369 | 44 | weak_ai_limit = 2 | 44 | weak_ai_limit = 2 |
370 | 45 | 45 | ||
371 | === modified file 'data/tribes/buildings/productionsites/empire/armorsmithy/init.lua' | |||
372 | --- data/tribes/buildings/productionsites/empire/armorsmithy/init.lua 2016-10-30 19:06:01 +0000 | |||
373 | +++ data/tribes/buildings/productionsites/empire/armorsmithy/init.lua 2017-07-03 17:39:38 +0000 | |||
374 | @@ -43,7 +43,6 @@ | |||
375 | 43 | 43 | ||
376 | 44 | aihints = { | 44 | aihints = { |
377 | 45 | prohibited_till = 700, | 45 | prohibited_till = 700, |
378 | 46 | forced_after = 900 | ||
379 | 47 | }, | 46 | }, |
380 | 48 | 47 | ||
381 | 49 | working_positions = { | 48 | working_positions = { |
382 | 50 | 49 | ||
383 | === modified file 'data/tribes/buildings/productionsites/empire/bakery/init.lua' | |||
384 | --- data/tribes/buildings/productionsites/empire/bakery/init.lua 2017-02-10 09:40:17 +0000 | |||
385 | +++ data/tribes/buildings/productionsites/empire/bakery/init.lua 2017-07-03 17:39:38 +0000 | |||
386 | @@ -37,7 +37,7 @@ | |||
387 | 37 | 37 | ||
388 | 38 | aihints = { | 38 | aihints = { |
389 | 39 | prohibited_till = 600, | 39 | prohibited_till = 600, |
391 | 40 | forced_after = 700 | 40 | basic_amount = 1 |
392 | 41 | }, | 41 | }, |
393 | 42 | 42 | ||
394 | 43 | working_positions = { | 43 | working_positions = { |
395 | 44 | 44 | ||
396 | === modified file 'data/tribes/buildings/productionsites/empire/barracks/init.lua' | |||
397 | --- data/tribes/buildings/productionsites/empire/barracks/init.lua 2017-02-10 09:40:17 +0000 | |||
398 | +++ data/tribes/buildings/productionsites/empire/barracks/init.lua 2017-07-03 17:39:38 +0000 | |||
399 | @@ -35,7 +35,6 @@ | |||
400 | 35 | }, | 35 | }, |
401 | 36 | 36 | ||
402 | 37 | aihints = { | 37 | aihints = { |
403 | 38 | forced_after = 1000, | ||
404 | 39 | very_weak_ai_limit = 1, | 38 | very_weak_ai_limit = 1, |
405 | 40 | weak_ai_limit = 3 | 39 | weak_ai_limit = 3 |
406 | 41 | }, | 40 | }, |
407 | 42 | 41 | ||
408 | === modified file 'data/tribes/buildings/productionsites/empire/brewery/init.lua' | |||
409 | --- data/tribes/buildings/productionsites/empire/brewery/init.lua 2016-09-03 14:59:10 +0000 | |||
410 | +++ data/tribes/buildings/productionsites/empire/brewery/init.lua 2017-07-03 17:39:38 +0000 | |||
411 | @@ -31,7 +31,6 @@ | |||
412 | 31 | }, | 31 | }, |
413 | 32 | 32 | ||
414 | 33 | aihints = { | 33 | aihints = { |
415 | 34 | forced_after = 900, | ||
416 | 35 | prohibited_till = 600, | 34 | prohibited_till = 600, |
417 | 36 | very_weak_ai_limit = 1, | 35 | very_weak_ai_limit = 1, |
418 | 37 | weak_ai_limit = 2 | 36 | weak_ai_limit = 2 |
419 | 38 | 37 | ||
420 | === modified file 'data/tribes/buildings/productionsites/empire/farm/init.lua' | |||
421 | --- data/tribes/buildings/productionsites/empire/farm/init.lua 2016-01-28 05:24:34 +0000 | |||
422 | +++ data/tribes/buildings/productionsites/empire/farm/init.lua 2017-07-03 17:39:38 +0000 | |||
423 | @@ -30,8 +30,8 @@ | |||
424 | 30 | }, | 30 | }, |
425 | 31 | 31 | ||
426 | 32 | aihints = { | 32 | aihints = { |
429 | 33 | space_consumer = true, | 33 | basic_amount = 1, |
430 | 34 | forced_after = 900 | 34 | space_consumer = true |
431 | 35 | }, | 35 | }, |
432 | 36 | 36 | ||
433 | 37 | working_positions = { | 37 | working_positions = { |
434 | 38 | 38 | ||
435 | === modified file 'data/tribes/buildings/productionsites/empire/inn/init.lua' | |||
436 | --- data/tribes/buildings/productionsites/empire/inn/init.lua 2016-10-26 19:21:32 +0000 | |||
437 | +++ data/tribes/buildings/productionsites/empire/inn/init.lua 2017-07-03 17:39:38 +0000 | |||
438 | @@ -31,7 +31,6 @@ | |||
439 | 31 | }, | 31 | }, |
440 | 32 | 32 | ||
441 | 33 | aihints = { | 33 | aihints = { |
442 | 34 | forced_after = 900, | ||
443 | 35 | prohibited_till = 600 | 34 | prohibited_till = 600 |
444 | 36 | }, | 35 | }, |
445 | 37 | 36 | ||
446 | 38 | 37 | ||
447 | === modified file 'data/tribes/buildings/productionsites/empire/marblemine/init.lua' | |||
448 | --- data/tribes/buildings/productionsites/empire/marblemine/init.lua 2016-09-03 14:59:10 +0000 | |||
449 | +++ data/tribes/buildings/productionsites/empire/marblemine/init.lua 2017-07-03 17:39:38 +0000 | |||
450 | @@ -38,7 +38,8 @@ | |||
451 | 38 | aihints = { | 38 | aihints = { |
452 | 39 | mines = "stones", | 39 | mines = "stones", |
453 | 40 | mines_percent = 50, | 40 | mines_percent = 50, |
455 | 41 | prohibited_till = 450 | 41 | prohibited_till = 450, |
456 | 42 | basic_amount = 1 | ||
457 | 42 | }, | 43 | }, |
458 | 43 | 44 | ||
459 | 44 | working_positions = { | 45 | working_positions = { |
460 | 45 | 46 | ||
461 | === modified file 'data/tribes/buildings/productionsites/empire/piggery/init.lua' | |||
462 | --- data/tribes/buildings/productionsites/empire/piggery/init.lua 2016-09-03 14:59:10 +0000 | |||
463 | +++ data/tribes/buildings/productionsites/empire/piggery/init.lua 2017-07-03 17:39:38 +0000 | |||
464 | @@ -33,7 +33,6 @@ | |||
465 | 33 | }, | 33 | }, |
466 | 34 | 34 | ||
467 | 35 | aihints = { | 35 | aihints = { |
468 | 36 | forced_after = 1800 | ||
469 | 37 | }, | 36 | }, |
470 | 38 | 37 | ||
471 | 39 | working_positions = { | 38 | working_positions = { |
472 | 40 | 39 | ||
473 | === modified file 'data/tribes/buildings/productionsites/empire/sawmill/init.lua' | |||
474 | --- data/tribes/buildings/productionsites/empire/sawmill/init.lua 2016-09-03 14:59:10 +0000 | |||
475 | +++ data/tribes/buildings/productionsites/empire/sawmill/init.lua 2017-07-03 17:39:38 +0000 | |||
476 | @@ -31,7 +31,7 @@ | |||
477 | 31 | }, | 31 | }, |
478 | 32 | 32 | ||
479 | 33 | aihints = { | 33 | aihints = { |
481 | 34 | forced_after = 250, | 34 | basic_amount = 2, |
482 | 35 | prohibited_till = 250, | 35 | prohibited_till = 250, |
483 | 36 | very_weak_ai_limit = 1, | 36 | very_weak_ai_limit = 1, |
484 | 37 | weak_ai_limit = 2 | 37 | weak_ai_limit = 2 |
485 | 38 | 38 | ||
486 | === modified file 'data/tribes/buildings/productionsites/empire/sheepfarm/init.lua' | |||
487 | --- data/tribes/buildings/productionsites/empire/sheepfarm/init.lua 2016-09-03 14:59:10 +0000 | |||
488 | +++ data/tribes/buildings/productionsites/empire/sheepfarm/init.lua 2017-07-03 17:39:38 +0000 | |||
489 | @@ -31,7 +31,7 @@ | |||
490 | 31 | }, | 31 | }, |
491 | 32 | 32 | ||
492 | 33 | aihints = { | 33 | aihints = { |
494 | 34 | prohibited_till = 600 | 34 | prohibited_till = 300 |
495 | 35 | }, | 35 | }, |
496 | 36 | 36 | ||
497 | 37 | working_positions = { | 37 | working_positions = { |
498 | 38 | 38 | ||
499 | === modified file 'data/tribes/buildings/productionsites/empire/stonemasons_house/init.lua' | |||
500 | --- data/tribes/buildings/productionsites/empire/stonemasons_house/init.lua 2016-09-03 14:59:10 +0000 | |||
501 | +++ data/tribes/buildings/productionsites/empire/stonemasons_house/init.lua 2017-07-03 17:39:38 +0000 | |||
502 | @@ -32,7 +32,7 @@ | |||
503 | 32 | }, | 32 | }, |
504 | 33 | 33 | ||
505 | 34 | aihints = { | 34 | aihints = { |
507 | 35 | forced_after = 400, | 35 | basic_amount = 1, |
508 | 36 | prohibited_till = 400, | 36 | prohibited_till = 400, |
509 | 37 | very_weak_ai_limit = 1, | 37 | very_weak_ai_limit = 1, |
510 | 38 | weak_ai_limit = 2 | 38 | weak_ai_limit = 2 |
511 | 39 | 39 | ||
512 | === modified file 'data/tribes/buildings/productionsites/empire/tavern/init.lua' | |||
513 | --- data/tribes/buildings/productionsites/empire/tavern/init.lua 2016-10-26 19:21:32 +0000 | |||
514 | +++ data/tribes/buildings/productionsites/empire/tavern/init.lua 2017-07-03 17:39:38 +0000 | |||
515 | @@ -33,7 +33,7 @@ | |||
516 | 33 | }, | 33 | }, |
517 | 34 | 34 | ||
518 | 35 | aihints = { | 35 | aihints = { |
520 | 36 | forced_after = 900, | 36 | basic_amount = 1, |
521 | 37 | prohibited_till = 300 | 37 | prohibited_till = 300 |
522 | 38 | }, | 38 | }, |
523 | 39 | 39 | ||
524 | 40 | 40 | ||
525 | === modified file 'data/tribes/buildings/productionsites/empire/toolsmithy/init.lua' | |||
526 | --- data/tribes/buildings/productionsites/empire/toolsmithy/init.lua 2016-09-03 14:59:10 +0000 | |||
527 | +++ data/tribes/buildings/productionsites/empire/toolsmithy/init.lua 2017-07-03 17:39:38 +0000 | |||
528 | @@ -32,7 +32,6 @@ | |||
529 | 32 | }, | 32 | }, |
530 | 33 | 33 | ||
531 | 34 | aihints = { | 34 | aihints = { |
532 | 35 | forced_after = 400, | ||
533 | 36 | prohibited_till = 400 | 35 | prohibited_till = 400 |
534 | 37 | }, | 36 | }, |
535 | 38 | 37 | ||
536 | 39 | 38 | ||
537 | === modified file 'data/tribes/buildings/productionsites/empire/vineyard/init.lua' | |||
538 | --- data/tribes/buildings/productionsites/empire/vineyard/init.lua 2015-12-11 16:54:00 +0000 | |||
539 | +++ data/tribes/buildings/productionsites/empire/vineyard/init.lua 2017-07-03 17:39:38 +0000 | |||
540 | @@ -29,7 +29,7 @@ | |||
541 | 29 | 29 | ||
542 | 30 | aihints = { | 30 | aihints = { |
543 | 31 | space_consumer = true, | 31 | space_consumer = true, |
545 | 32 | forced_after = 300 | 32 | basic_amount = 1 |
546 | 33 | }, | 33 | }, |
547 | 34 | 34 | ||
548 | 35 | working_positions = { | 35 | working_positions = { |
549 | 36 | 36 | ||
550 | === modified file 'data/tribes/buildings/productionsites/empire/weaponsmithy/init.lua' | |||
551 | --- data/tribes/buildings/productionsites/empire/weaponsmithy/init.lua 2016-10-30 19:06:01 +0000 | |||
552 | +++ data/tribes/buildings/productionsites/empire/weaponsmithy/init.lua 2017-07-03 17:39:38 +0000 | |||
553 | @@ -39,7 +39,8 @@ | |||
554 | 39 | }, | 39 | }, |
555 | 40 | 40 | ||
556 | 41 | aihints = { | 41 | aihints = { |
558 | 42 | prohibited_till = 900 | 42 | prohibited_till = 900, |
559 | 43 | forced_after = 3600 | ||
560 | 43 | }, | 44 | }, |
561 | 44 | 45 | ||
562 | 45 | working_positions = { | 46 | working_positions = { |
563 | 46 | 47 | ||
564 | === modified file 'data/tribes/buildings/productionsites/empire/winery/init.lua' | |||
565 | --- data/tribes/buildings/productionsites/empire/winery/init.lua 2016-09-03 14:59:10 +0000 | |||
566 | +++ data/tribes/buildings/productionsites/empire/winery/init.lua 2017-07-03 17:39:38 +0000 | |||
567 | @@ -33,10 +33,10 @@ | |||
568 | 33 | }, | 33 | }, |
569 | 34 | 34 | ||
570 | 35 | aihints = { | 35 | aihints = { |
571 | 36 | forced_after = 600, | ||
572 | 37 | prohibited_till = 600, | 36 | prohibited_till = 600, |
573 | 38 | very_weak_ai_limit = 1, | 37 | very_weak_ai_limit = 1, |
575 | 39 | weak_ai_limit = 2 | 38 | weak_ai_limit = 2, |
576 | 39 | basic_amount = 1 | ||
577 | 40 | }, | 40 | }, |
578 | 41 | 41 | ||
579 | 42 | working_positions = { | 42 | working_positions = { |
580 | 43 | 43 | ||
581 | === modified file 'data/tribes/buildings/trainingsites/atlanteans/dungeon/init.lua' | |||
582 | --- data/tribes/buildings/trainingsites/atlanteans/dungeon/init.lua 2017-02-10 09:40:17 +0000 | |||
583 | +++ data/tribes/buildings/trainingsites/atlanteans/dungeon/init.lua 2017-07-03 17:39:38 +0000 | |||
584 | @@ -112,7 +112,6 @@ | |||
585 | 112 | }, | 112 | }, |
586 | 113 | 113 | ||
587 | 114 | aihints = { | 114 | aihints = { |
588 | 115 | trainingsite_type = "advanced", | ||
589 | 116 | prohibited_till = 1500, | 115 | prohibited_till = 1500, |
590 | 117 | very_weak_ai_limit = 0, | 116 | very_weak_ai_limit = 0, |
591 | 118 | weak_ai_limit = 1 | 117 | weak_ai_limit = 1 |
592 | 119 | 118 | ||
593 | === modified file 'data/tribes/buildings/trainingsites/atlanteans/labyrinth/init.lua' | |||
594 | --- data/tribes/buildings/trainingsites/atlanteans/labyrinth/init.lua 2017-02-10 09:40:17 +0000 | |||
595 | +++ data/tribes/buildings/trainingsites/atlanteans/labyrinth/init.lua 2017-07-03 17:39:38 +0000 | |||
596 | @@ -36,7 +36,6 @@ | |||
597 | 36 | aihints = { | 36 | aihints = { |
598 | 37 | prohibited_till = 900, | 37 | prohibited_till = 900, |
599 | 38 | forced_after = 1500, | 38 | forced_after = 1500, |
600 | 39 | trainingsite_type = "basic", | ||
601 | 40 | very_weak_ai_limit = 1, | 39 | very_weak_ai_limit = 1, |
602 | 41 | weak_ai_limit = 2 | 40 | weak_ai_limit = 2 |
603 | 42 | }, | 41 | }, |
604 | 43 | 42 | ||
605 | === modified file 'data/tribes/buildings/trainingsites/barbarians/battlearena/init.lua' | |||
606 | --- data/tribes/buildings/trainingsites/barbarians/battlearena/init.lua 2017-02-10 09:40:17 +0000 | |||
607 | +++ data/tribes/buildings/trainingsites/barbarians/battlearena/init.lua 2017-07-03 17:39:38 +0000 | |||
608 | @@ -48,7 +48,6 @@ | |||
609 | 48 | aihints = { | 48 | aihints = { |
610 | 49 | prohibited_till = 900, | 49 | prohibited_till = 900, |
611 | 50 | forced_after = 1500, | 50 | forced_after = 1500, |
612 | 51 | trainingsite_type = "basic", | ||
613 | 52 | very_weak_ai_limit = 1, | 51 | very_weak_ai_limit = 1, |
614 | 53 | weak_ai_limit = 3 | 52 | weak_ai_limit = 3 |
615 | 54 | }, | 53 | }, |
616 | 55 | 54 | ||
617 | === modified file 'data/tribes/buildings/trainingsites/barbarians/trainingcamp/init.lua' | |||
618 | --- data/tribes/buildings/trainingsites/barbarians/trainingcamp/init.lua 2017-02-10 09:40:17 +0000 | |||
619 | +++ data/tribes/buildings/trainingsites/barbarians/trainingcamp/init.lua 2017-07-03 17:39:38 +0000 | |||
620 | @@ -41,7 +41,6 @@ | |||
621 | 41 | 41 | ||
622 | 42 | aihints = { | 42 | aihints = { |
623 | 43 | prohibited_till = 1500, | 43 | prohibited_till = 1500, |
624 | 44 | trainingsite_type = "advanced", | ||
625 | 45 | very_weak_ai_limit = 0, | 44 | very_weak_ai_limit = 0, |
626 | 46 | weak_ai_limit = 1 | 45 | weak_ai_limit = 1 |
627 | 47 | }, | 46 | }, |
628 | 48 | 47 | ||
629 | === modified file 'data/tribes/buildings/trainingsites/empire/arena/init.lua' | |||
630 | --- data/tribes/buildings/trainingsites/empire/arena/init.lua 2017-03-23 07:36:36 +0000 | |||
631 | +++ data/tribes/buildings/trainingsites/empire/arena/init.lua 2017-07-03 17:39:38 +0000 | |||
632 | @@ -37,7 +37,6 @@ | |||
633 | 37 | }, | 37 | }, |
634 | 38 | 38 | ||
635 | 39 | aihints = { | 39 | aihints = { |
636 | 40 | trainingsite_type = "basic", | ||
637 | 41 | trainingsites_max_percent = 20, | 40 | trainingsites_max_percent = 20, |
638 | 42 | prohibited_till = 900, | 41 | prohibited_till = 900, |
639 | 43 | very_weak_ai_limit = 1, | 42 | very_weak_ai_limit = 1, |
640 | 44 | 43 | ||
641 | === modified file 'data/tribes/buildings/trainingsites/empire/colosseum/init.lua' | |||
642 | --- data/tribes/buildings/trainingsites/empire/colosseum/init.lua 2017-02-10 09:40:17 +0000 | |||
643 | +++ data/tribes/buildings/trainingsites/empire/colosseum/init.lua 2017-07-03 17:39:38 +0000 | |||
644 | @@ -34,7 +34,6 @@ | |||
645 | 34 | 34 | ||
646 | 35 | aihints = { | 35 | aihints = { |
647 | 36 | prohibited_till = 1200, | 36 | prohibited_till = 1200, |
648 | 37 | trainingsite_type = "basic", | ||
649 | 38 | forced_after = 1800, | 37 | forced_after = 1800, |
650 | 39 | very_weak_ai_limit = 1, | 38 | very_weak_ai_limit = 1, |
651 | 40 | weak_ai_limit = 2 | 39 | weak_ai_limit = 2 |
652 | 41 | 40 | ||
653 | === modified file 'data/tribes/buildings/trainingsites/empire/trainingcamp/init.lua' | |||
654 | --- data/tribes/buildings/trainingsites/empire/trainingcamp/init.lua 2017-02-10 09:40:17 +0000 | |||
655 | +++ data/tribes/buildings/trainingsites/empire/trainingcamp/init.lua 2017-07-03 17:39:38 +0000 | |||
656 | @@ -35,7 +35,6 @@ | |||
657 | 35 | 35 | ||
658 | 36 | aihints = { | 36 | aihints = { |
659 | 37 | prohibited_till = 1500, | 37 | prohibited_till = 1500, |
660 | 38 | trainingsite_type = "advanced", | ||
661 | 39 | very_weak_ai_limit = 0, | 38 | very_weak_ai_limit = 0, |
662 | 40 | weak_ai_limit = 1 | 39 | weak_ai_limit = 1 |
663 | 41 | }, | 40 | }, |
664 | 42 | 41 | ||
665 | === modified file 'data/tribes/empire.lua' | |||
666 | --- data/tribes/empire.lua 2017-04-30 10:30:02 +0000 | |||
667 | +++ data/tribes/empire.lua 2017-07-03 17:39:38 +0000 | |||
668 | @@ -326,4 +326,9 @@ | |||
669 | 326 | headquarters = "empire_headquarters", | 326 | headquarters = "empire_headquarters", |
670 | 327 | port = "empire_port", | 327 | port = "empire_port", |
671 | 328 | barracks = "empire_barracks", | 328 | barracks = "empire_barracks", |
672 | 329 | bakery = "empire_bakery", | ||
673 | 330 | ironore = "iron_ore", | ||
674 | 331 | rawlog = "log", | ||
675 | 332 | refinedlog = "planks", | ||
676 | 333 | granite = "granite", | ||
677 | 329 | } | 334 | } |
678 | 330 | 335 | ||
679 | === modified file 'src/ai/ai_help_structs.cc' | |||
680 | --- src/ai/ai_help_structs.cc 2017-01-25 18:55:59 +0000 | |||
681 | +++ src/ai/ai_help_structs.cc 2017-07-03 17:39:38 +0000 | |||
682 | @@ -20,6 +20,7 @@ | |||
683 | 20 | #include "ai/ai_help_structs.h" | 20 | #include "ai/ai_help_structs.h" |
684 | 21 | 21 | ||
685 | 22 | #include "base/macros.h" | 22 | #include "base/macros.h" |
686 | 23 | #include "base/time_string.h" | ||
687 | 23 | #include "logic/map.h" | 24 | #include "logic/map.h" |
688 | 24 | #include "logic/player.h" | 25 | #include "logic/player.h" |
689 | 25 | 26 | ||
690 | @@ -27,6 +28,8 @@ | |||
691 | 27 | constexpr int kRoadNotFound = -1000; | 28 | constexpr int kRoadNotFound = -1000; |
692 | 28 | constexpr int kShortcutWithinSameEconomy = 1000; | 29 | constexpr int kShortcutWithinSameEconomy = 1000; |
693 | 29 | constexpr int kRoadToDifferentEconomy = 10000; | 30 | constexpr int kRoadToDifferentEconomy = 10000; |
694 | 31 | constexpr int kUpperDefaultMutationLimit = 200; | ||
695 | 32 | constexpr int kLowerDefaultMutationLimit = 150; | ||
696 | 30 | 33 | ||
697 | 31 | namespace Widelands { | 34 | namespace Widelands { |
698 | 32 | 35 | ||
699 | @@ -102,15 +105,12 @@ | |||
700 | 102 | // When looking for unowned terrain to acquire, we are actually | 105 | // When looking for unowned terrain to acquire, we are actually |
701 | 103 | // only interested in fields we can walk on. | 106 | // only interested in fields we can walk on. |
702 | 104 | // Fields should either be completely unowned or owned by an opposing player | 107 | // Fields should either be completely unowned or owned by an opposing player |
705 | 105 | FindNodeUnowned::FindNodeUnowned(Player* p, Game& g, bool oe) | 108 | FindEnemyNodeWalkable::FindEnemyNodeWalkable(Player* p, Game& g) : player(p), game(g) { |
704 | 106 | : player(p), game(g), only_enemies(oe) { | ||
706 | 107 | } | 109 | } |
707 | 108 | 110 | ||
713 | 109 | bool FindNodeUnowned::accept(const Map&, const FCoords& fc) const { | 111 | bool FindEnemyNodeWalkable::accept(const Map&, const FCoords& fc) const { |
714 | 110 | return (fc.field->nodecaps() & MOVECAPS_WALK) && | 112 | return ((fc.field->nodecaps() & MOVECAPS_WALK) && (fc.field->get_owned_by() > 0) && |
715 | 111 | ((fc.field->get_owned_by() == 0) || | 113 | player->is_hostile(*game.get_player(fc.field->get_owned_by()))); |
711 | 112 | player->is_hostile(*game.get_player(fc.field->get_owned_by()))) && | ||
712 | 113 | (!only_enemies || (fc.field->get_owned_by() != 0)); | ||
716 | 114 | } | 114 | } |
717 | 115 | 115 | ||
718 | 116 | // Sometimes we need to know how many nodes our allies owns | 116 | // Sometimes we need to know how many nodes our allies owns |
719 | @@ -127,11 +127,23 @@ | |||
720 | 127 | // When looking for unowned terrain to acquire, we must | 127 | // When looking for unowned terrain to acquire, we must |
721 | 128 | // pay speciall attention to fields where mines can be built. | 128 | // pay speciall attention to fields where mines can be built. |
722 | 129 | // Fields should be completely unowned | 129 | // Fields should be completely unowned |
724 | 130 | FindNodeUnownedMineable::FindNodeUnownedMineable(Player* p, Game& g) : player(p), game(g) { | 130 | FindNodeUnownedMineable::FindNodeUnownedMineable(Player* p, Game& g, int32_t t) |
725 | 131 | : player(p), game(g), ore_type(t) { | ||
726 | 131 | } | 132 | } |
727 | 132 | 133 | ||
728 | 133 | bool FindNodeUnownedMineable::accept(const Map&, const FCoords& fc) const { | 134 | bool FindNodeUnownedMineable::accept(const Map&, const FCoords& fc) const { |
730 | 134 | return (fc.field->nodecaps() & BUILDCAPS_MINE) && (fc.field->get_owned_by() == 0); | 135 | if (ore_type == INVALID_INDEX) { |
731 | 136 | return (fc.field->nodecaps() & BUILDCAPS_MINE) && (fc.field->get_owned_by() == neutral()); | ||
732 | 137 | } | ||
733 | 138 | return (fc.field->nodecaps() & BUILDCAPS_MINE) && (fc.field->get_owned_by() == neutral()) && | ||
734 | 139 | fc.field->get_resources() == ore_type; | ||
735 | 140 | } | ||
736 | 141 | |||
737 | 142 | FindNodeUnownedBuildable::FindNodeUnownedBuildable(Player* p, Game& g) : player(p), game(g) { | ||
738 | 143 | } | ||
739 | 144 | |||
740 | 145 | bool FindNodeUnownedBuildable::accept(const Map&, const FCoords& fc) const { | ||
741 | 146 | return (fc.field->nodecaps() & BUILDCAPS_SIZEMASK) && (fc.field->get_owned_by() == neutral()); | ||
742 | 135 | } | 147 | } |
743 | 136 | 148 | ||
744 | 137 | // Unowned but walkable fields nearby | 149 | // Unowned but walkable fields nearby |
745 | @@ -139,7 +151,7 @@ | |||
746 | 139 | } | 151 | } |
747 | 140 | 152 | ||
748 | 141 | bool FindNodeUnownedWalkable::accept(const Map&, const FCoords& fc) const { | 153 | bool FindNodeUnownedWalkable::accept(const Map&, const FCoords& fc) const { |
750 | 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()); |
751 | 143 | } | 155 | } |
752 | 144 | 156 | ||
753 | 145 | // Looking only for mines-capable fields nearby | 157 | // Looking only for mines-capable fields nearby |
754 | @@ -181,14 +193,35 @@ | |||
755 | 181 | : flag(&f), cost(c), distance(d) { | 193 | : flag(&f), cost(c), distance(d) { |
756 | 182 | } | 194 | } |
757 | 183 | 195 | ||
758 | 196 | EventTimeQueue::EventTimeQueue() { | ||
759 | 197 | } | ||
760 | 198 | |||
761 | 199 | void EventTimeQueue::push(const uint32_t production_time) { | ||
762 | 200 | queue.push(production_time); | ||
763 | 201 | } | ||
764 | 202 | |||
765 | 203 | uint32_t EventTimeQueue::count(const uint32_t current_time) { | ||
766 | 204 | strip_old(current_time); | ||
767 | 205 | return queue.size(); | ||
768 | 206 | } | ||
769 | 207 | |||
770 | 208 | void EventTimeQueue::strip_old(const uint32_t current_time) { | ||
771 | 209 | while (!queue.empty() && queue.front() < current_time - duration_) { | ||
772 | 210 | queue.pop(); | ||
773 | 211 | } | ||
774 | 212 | } | ||
775 | 213 | |||
776 | 184 | BuildableField::BuildableField(const Widelands::FCoords& fc) | 214 | BuildableField::BuildableField(const Widelands::FCoords& fc) |
777 | 185 | : coords(fc), | 215 | : coords(fc), |
778 | 186 | field_info_expiration(20000), | 216 | field_info_expiration(20000), |
779 | 187 | preferred(false), | 217 | preferred(false), |
780 | 188 | enemy_nearby(0), | 218 | enemy_nearby(0), |
781 | 219 | enemy_accessible_(false), | ||
782 | 220 | enemy_wh_nearby(false), | ||
783 | 189 | unowned_land_nearby(0), | 221 | unowned_land_nearby(0), |
784 | 190 | near_border(false), | 222 | near_border(false), |
785 | 191 | unowned_mines_spots_nearby(0), | 223 | unowned_mines_spots_nearby(0), |
786 | 224 | unowned_iron_mines_nearby(false), | ||
787 | 192 | trees_nearby(0), | 225 | trees_nearby(0), |
788 | 193 | // explanation of starting values | 226 | // explanation of starting values |
789 | 194 | // this is done to save some work for AI (CPU utilization) | 227 | // this is done to save some work for AI (CPU utilization) |
790 | @@ -209,15 +242,22 @@ | |||
791 | 209 | area_military_capacity(0), | 242 | area_military_capacity(0), |
792 | 210 | military_loneliness(1000), | 243 | military_loneliness(1000), |
793 | 211 | military_in_constr_nearby(0), | 244 | military_in_constr_nearby(0), |
795 | 212 | area_military_presence(0), | 245 | own_military_presence(0), |
796 | 246 | enemy_military_presence(0), | ||
797 | 247 | ally_military_presence(0), | ||
798 | 213 | military_stationed(0), | 248 | military_stationed(0), |
799 | 214 | unconnected_nearby(false), | 249 | unconnected_nearby(false), |
800 | 215 | military_unstationed(0), | 250 | military_unstationed(0), |
802 | 216 | is_portspace(false), | 251 | own_non_military_nearby(0), |
803 | 252 | is_portspace(Widelands::ExtendedBool::kUnset), | ||
804 | 217 | port_nearby(false), | 253 | port_nearby(false), |
805 | 218 | portspace_nearby(Widelands::ExtendedBool::kUnset), | 254 | portspace_nearby(Widelands::ExtendedBool::kUnset), |
806 | 219 | max_buildcap_nearby(0), | 255 | max_buildcap_nearby(0), |
808 | 220 | last_resources_check_time(0) { | 256 | last_resources_check_time(0), |
809 | 257 | military_score_(0), | ||
810 | 258 | inland(false), | ||
811 | 259 | local_soldier_capacity(0), | ||
812 | 260 | is_militarysite(false) { | ||
813 | 221 | } | 261 | } |
814 | 222 | 262 | ||
815 | 223 | int32_t BuildableField::own_military_sites_nearby_() { | 263 | int32_t BuildableField::own_military_sites_nearby_() { |
816 | @@ -240,6 +280,19 @@ | |||
817 | 240 | return cnt_built + cnt_under_construction; | 280 | return cnt_built + cnt_under_construction; |
818 | 241 | } | 281 | } |
819 | 242 | 282 | ||
820 | 283 | bool BuildingObserver::is(BuildingAttribute attribute) const { | ||
821 | 284 | return is_what.count(attribute) == 1; | ||
822 | 285 | } | ||
823 | 286 | |||
824 | 287 | void BuildingObserver::set_is(const BuildingAttribute attribute) { | ||
825 | 288 | is_what.insert(attribute); | ||
826 | 289 | } | ||
827 | 290 | |||
828 | 291 | void BuildingObserver::unset_is(const BuildingAttribute attribute) { | ||
829 | 292 | is_what.erase(attribute); | ||
830 | 293 | assert(!is(attribute)); | ||
831 | 294 | } | ||
832 | 295 | |||
833 | 243 | Widelands::AiModeBuildings BuildingObserver::aimode_limit_status() { | 296 | Widelands::AiModeBuildings BuildingObserver::aimode_limit_status() { |
834 | 244 | if (total_count() > cnt_limit_by_aimode) { | 297 | if (total_count() > cnt_limit_by_aimode) { |
835 | 245 | return Widelands::AiModeBuildings::kLimitExceeded; | 298 | return Widelands::AiModeBuildings::kLimitExceeded; |
836 | @@ -250,7 +303,7 @@ | |||
837 | 250 | } | 303 | } |
838 | 251 | } | 304 | } |
839 | 252 | bool BuildingObserver::buildable(Widelands::Player& p) { | 305 | bool BuildingObserver::buildable(Widelands::Player& p) { |
841 | 253 | return is_buildable && p.is_building_type_allowed(id); | 306 | return is(BuildingAttribute::kBuildable) && p.is_building_type_allowed(id); |
842 | 254 | } | 307 | } |
843 | 255 | 308 | ||
844 | 256 | // Computer player does not get notification messages about enemy militarysites | 309 | // Computer player does not get notification messages about enemy militarysites |
845 | @@ -264,16 +317,769 @@ | |||
846 | 264 | attack_soldiers_strength(0), | 317 | attack_soldiers_strength(0), |
847 | 265 | defenders_strength(0), | 318 | defenders_strength(0), |
848 | 266 | stationed_soldiers(0), | 319 | stationed_soldiers(0), |
850 | 267 | last_time_attackable(std::numeric_limits<uint32_t>::max()), | 320 | last_time_seen(0), |
851 | 268 | last_tested(0), | 321 | last_tested(0), |
852 | 269 | score(0), | 322 | score(0), |
853 | 270 | mines_nearby(Widelands::ExtendedBool::kUnset), | 323 | mines_nearby(Widelands::ExtendedBool::kUnset), |
855 | 271 | no_attack_counter(0) { | 324 | last_time_attacked(0), |
856 | 325 | attack_counter(0) { | ||
857 | 272 | } | 326 | } |
858 | 273 | 327 | ||
859 | 274 | // as all mines have 3 levels, AI does not know total count of mines per mined material | 328 | // as all mines have 3 levels, AI does not know total count of mines per mined material |
860 | 275 | // so this observer will be used for this | 329 | // so this observer will be used for this |
862 | 276 | MineTypesObserver::MineTypesObserver() : in_construction(0), finished(0) { | 330 | MineTypesObserver::MineTypesObserver() |
863 | 331 | : in_construction(0), finished(0), is_critical(false), unoccupied(0) { | ||
864 | 332 | } | ||
865 | 333 | |||
866 | 334 | ExpansionType::ExpansionType() { | ||
867 | 335 | type = ExpansionMode::kResources; | ||
868 | 336 | } | ||
869 | 337 | |||
870 | 338 | void ExpansionType::set_expantion_type(const ExpansionMode etype) { | ||
871 | 339 | type = etype; | ||
872 | 340 | } | ||
873 | 341 | |||
874 | 342 | ManagementData::ManagementData() { | ||
875 | 343 | score = 1; | ||
876 | 344 | primary_parent = 255; | ||
877 | 345 | next_neuron_id = 0; | ||
878 | 346 | performance_change = 0; | ||
879 | 347 | } | ||
880 | 348 | |||
881 | 349 | // Initialization of neuron. Neuron is defined by curve (type) and weight [-kWeightRange, kWeightRange] | ||
882 | 350 | // third argument is just id | ||
883 | 351 | Neuron::Neuron(int8_t w, uint8_t f, uint16_t i) : weight(w), type(f), id(i) { | ||
884 | 352 | assert(type < neuron_curves.size()); | ||
885 | 353 | assert(weight >= -kNeuronWeightLimit && weight <= kNeuronWeightLimit); | ||
886 | 354 | recalculate(); | ||
887 | 355 | } | ||
888 | 356 | |||
889 | 357 | // Weight, or rather value in range [-kWeightRange, kWeightRange]. Automatically adjusts the weight to the range in case of | ||
890 | 358 | // overflow. | ||
891 | 359 | void Neuron::set_weight(int8_t w) { | ||
892 | 360 | weight = Neuron::clip_weight_to_range(w); | ||
893 | 361 | } | ||
894 | 362 | |||
895 | 363 | // Neuron stores calculated values in an array of size 21. | ||
896 | 364 | // This has to be recalculated when the weight or curve type change | ||
897 | 365 | void Neuron::recalculate() { | ||
898 | 366 | assert(neuron_curves.size() > type); | ||
899 | 367 | for (uint8_t i = 0; i <= kNeuronMaxPosition; i += 1) { | ||
900 | 368 | results[i] = weight * neuron_curves[type][i] / kNeuronWeightLimit; | ||
901 | 369 | } | ||
902 | 370 | } | ||
903 | 371 | |||
904 | 372 | // The Following two functions return Neuron values on position | ||
905 | 373 | int8_t Neuron::get_result(const size_t pos) { | ||
906 | 374 | assert(pos <= kNeuronMaxPosition); | ||
907 | 375 | return results[pos]; | ||
908 | 376 | } | ||
909 | 377 | |||
910 | 378 | // get value corresponding to input in range 0-20, if you are out of range | ||
911 | 379 | // the input will be cropped | ||
912 | 380 | int8_t Neuron::get_result_safe(int32_t pos, const bool absolute) { | ||
913 | 381 | // pos has to be normalized into range 0 - 20(kNeuronMaxPosition) | ||
914 | 382 | pos = std::max(0, std::min(static_cast<int>(kNeuronMaxPosition), pos)); | ||
915 | 383 | |||
916 | 384 | assert(pos <= static_cast<int32_t>(kNeuronMaxPosition)); | ||
917 | 385 | assert(pos >= 0); | ||
918 | 386 | assert(results[pos] >= -kNeuronWeightLimit && results[pos] <= kNeuronWeightLimit); | ||
919 | 387 | |||
920 | 388 | if (absolute) { | ||
921 | 389 | return std::abs(results[pos]); | ||
922 | 390 | } | ||
923 | 391 | return results[pos]; | ||
924 | 392 | } | ||
925 | 393 | |||
926 | 394 | // Setting the type of curve | ||
927 | 395 | void Neuron::set_type(uint8_t new_type) { | ||
928 | 396 | assert(new_type < neuron_curves.size()); | ||
929 | 397 | type = new_type; | ||
930 | 398 | } | ||
931 | 399 | |||
932 | 400 | // FNeuron is basically a single uint32_t integer, and the AI can query every bit of that uint32_t | ||
933 | 401 | FNeuron::FNeuron(uint32_t c, uint16_t i) { | ||
934 | 402 | core = c; | ||
935 | 403 | id = i; | ||
936 | 404 | } | ||
937 | 405 | |||
938 | 406 | // Returning a result depending on combinations of 5 bools | ||
939 | 407 | // Bools are completely anonymous, but can present any yes/no inputs, e.g. imagine the AI that is | ||
940 | 408 | // to figure out if it should attack from a militarysite. The inputs can be: | ||
941 | 409 | // bool1 - are we stronger than the enemy? | ||
942 | 410 | // bool2 - do we have a basic economy established? | ||
943 | 411 | // bool3 - do we have local predominance? | ||
944 | 412 | // bool4 - has our strength grown during the last 60 minutes? | ||
945 | 413 | // bool5 - are there mines in the vicinity? | ||
946 | 414 | // These five bools can create 32 combinations = yes/no answers. | ||
947 | 415 | // In fact this can be perceived as a complicated if..then structure, but one that can | ||
948 | 416 | // adjust automatically as a part of training. | ||
949 | 417 | // Or rather it is a 5-dimensional table with 2 columns in every dimension :) | ||
950 | 418 | // In fact this concept if very demanding for training so we don't use it much | ||
951 | 419 | bool FNeuron::get_result( | ||
952 | 420 | const bool bool1, const bool bool2, const bool bool3, const bool bool4, const bool bool5) { | ||
953 | 421 | return core.test(bool1 * 16 + bool2 * 8 + bool3 * 4 + bool4 * 2 + bool5); | ||
954 | 422 | } | ||
955 | 423 | |||
956 | 424 | // Returning bool on a position | ||
957 | 425 | bool FNeuron::get_position(const uint8_t pos) { | ||
958 | 426 | assert(pos < kFNeuronBitSize); | ||
959 | 427 | return core.test(pos); | ||
960 | 428 | } | ||
961 | 429 | |||
962 | 430 | // Returning numerical value of FNeuron. Used for saving and priting into log | ||
963 | 431 | uint32_t FNeuron::get_int() { | ||
964 | 432 | return core.to_ulong(); | ||
965 | 433 | } | ||
966 | 434 | |||
967 | 435 | // This is basically a mutation of FNeuron | ||
968 | 436 | void FNeuron::flip_bit(const uint8_t pos) { | ||
969 | 437 | assert(pos < kFNeuronBitSize); | ||
970 | 438 | core.flip(pos); | ||
971 | 439 | } | ||
972 | 440 | |||
973 | 441 | // Shifting the value in range -kWeightRange to kWeightRange, if zero_align is true, it is now allowed to shift | ||
974 | 442 | // from negative to positive and vice versa, 0 must be used. | ||
975 | 443 | int8_t ManagementData::shift_weight_value(const int8_t old_value, const bool aggressive) { | ||
976 | 444 | |||
977 | 445 | int16_t halfVArRange = 50; | ||
978 | 446 | if (aggressive) { | ||
979 | 447 | halfVArRange = 200; | ||
980 | 448 | } | ||
981 | 449 | |||
982 | 450 | const int16_t upper_limit = std::min<int16_t>(old_value + halfVArRange, kNeuronWeightLimit); | ||
983 | 451 | const int16_t bottom_limit = std::max<int16_t>(old_value - halfVArRange, -kNeuronWeightLimit); | ||
984 | 452 | int16_t new_value = bottom_limit + std::rand() % (upper_limit - bottom_limit + 1); | ||
985 | 453 | |||
986 | 454 | if (!aggressive && ((old_value > 0 && new_value < 0) || (old_value < 0 && new_value > 0))) { | ||
987 | 455 | new_value = 0; | ||
988 | 456 | } | ||
989 | 457 | |||
990 | 458 | new_value = Neuron::clip_weight_to_range(new_value); | ||
991 | 459 | return static_cast<int8_t>(new_value); | ||
992 | 460 | } | ||
993 | 461 | |||
994 | 462 | // Used to score performance of AI | ||
995 | 463 | // Should be disabled for "production" | ||
996 | 464 | void ManagementData::review(const uint32_t gametime, | ||
997 | 465 | PlayerNumber pn, | ||
998 | 466 | const uint32_t land, | ||
999 | 467 | const uint32_t max_e_land, | ||
1000 | 468 | const uint32_t old_land, | ||
1001 | 469 | const uint16_t attackers, | ||
1002 | 470 | const int16_t trained_soldiers, | ||
1003 | 471 | const int16_t latest_attackers, | ||
1004 | 472 | const uint16_t conq_ws) { | ||
1005 | 473 | |||
1006 | 474 | const int16_t main_bonus = | ||
1007 | 475 | ((static_cast<int32_t>(land - old_land) > 0 && land > max_e_land * 5 / 6 && attackers > 0 && | ||
1008 | 476 | trained_soldiers > 0 && latest_attackers > 0) ? | ||
1009 | 477 | kBonus : | ||
1010 | 478 | 0); | ||
1011 | 479 | |||
1012 | 480 | const int16_t land_delta_bonus = static_cast<int16_t>(land - old_land) * kLandDeltaMultiplier; | ||
1013 | 481 | |||
1014 | 482 | score = land / kCurrentLandDivider + land_delta_bonus + main_bonus + | ||
1015 | 483 | attackers * kAttackersMultiplier + ((attackers > 0) ? kAttackBonus : -kAttackBonus) + | ||
1016 | 484 | trained_soldiers * kTrainedSoldiersScore + +kConqueredWhBonus + conq_ws; | ||
1017 | 485 | |||
1018 | 486 | log(" %2d %s: reviewing AI mngm. data, sc: %5d Pr.p: %d (l: %4d / %4d / %4d, " | ||
1019 | 487 | "at:%4d(%3d), ts:%4d(%2d), ConqWH:%2d)\n", | ||
1020 | 488 | pn, gamestring_with_leading_zeros(gametime), score, primary_parent, | ||
1021 | 489 | land / kCurrentLandDivider, main_bonus, land_delta_bonus, | ||
1022 | 490 | attackers * kAttackersMultiplier, latest_attackers, | ||
1023 | 491 | trained_soldiers * kTrainedSoldiersScore, trained_soldiers, conq_ws); | ||
1024 | 492 | |||
1025 | 493 | if (score < -10000 || score > 30000) { | ||
1026 | 494 | log( | ||
1027 | 495 | "%2d %s: reviewing AI mngm. data, score too extreme: %4d\n", | ||
1028 | 496 | pn, gamestring_with_leading_zeros(gametime), score); | ||
1029 | 497 | } | ||
1030 | 498 | assert(score > -10000 && score < 100000); | ||
1031 | 499 | } | ||
1032 | 500 | |||
1033 | 501 | // Here we generate new AI DNA (no mutation yet) and push them into persistent data | ||
1034 | 502 | // this can cause inconsistency between local and persistent | ||
1035 | 503 | void ManagementData::new_dna_for_persistent(const uint8_t pn, const Widelands::AiType type) { | ||
1036 | 504 | |||
1037 | 505 | ai_type = type; | ||
1038 | 506 | |||
1039 | 507 | log ("%2d: DNA initialization... \n", pn); | ||
1040 | 508 | |||
1041 | 509 | // AutoSCore_AIDNA_1 | ||
1042 | 510 | const std::vector<int16_t> AI_initial_military_numbers_A = | ||
1043 | 511 | { 18, -42, 21, 59, -7, -78, -22, 81, 48, 0, // AutoContent_01_AIDNA_1 | ||
1044 | 512 | -82, 45, -96, 16, 70, -30, 33, 79, -78, -42, // AutoContent_02_AIDNA_1 | ||
1045 | 513 | 79, -16, 34, 46, -22, 0, 45, -29, 53, 51, // AutoContent_03_AIDNA_1 | ||
1046 | 514 | 24, 47, -27, 80, -86, 46, -63, -47, 20, -63, // AutoContent_04_AIDNA_1 | ||
1047 | 515 | 78, 51, -11, -77, 20, 38, 6, 37, -64, -41, // AutoContent_05_AIDNA_1 | ||
1048 | 516 | -3, -55, 62, 0, 64, -92, 4, -89, 71, -18, // AutoContent_06_AIDNA_1 | ||
1049 | 517 | -87, 56, 17, -34, -69, 24, -57, 84, 40, -51, // AutoContent_07_AIDNA_1 | ||
1050 | 518 | 0, 44, 0, -2, -11, -4, -96, -35, -29, -12, // AutoContent_08_AIDNA_1 | ||
1051 | 519 | 71, -98, -25, 50, 97, 74, 0, 65, -60, 23, // AutoContent_09_AIDNA_1 | ||
1052 | 520 | 38, 53, 74, 0, -43, 27, 32, 37, -24, -65, // AutoContent_10_AIDNA_1 | ||
1053 | 521 | 16, -42, 19, -94, -28, 83, -55, -63, 16, -41, // AutoContent_11_AIDNA_1 | ||
1054 | 522 | 28, -3, 0, -87, 32, 5, 4, 6, -20, 62, // AutoContent_12_AIDNA_1 | ||
1055 | 523 | 85, 0, 58, 48, -80, -20, -49, 71, 60, 8, // AutoContent_13_AIDNA_1 | ||
1056 | 524 | -52, 59, 100, -74, 0, -36, -9, 80, 41, -67, // AutoContent_14_AIDNA_1 | ||
1057 | 525 | 0, 15, -96, -51, -21, 11, -27, -30, 76, -47 // AutoContent_15_AIDNA_1 | ||
1058 | 526 | } | ||
1059 | 527 | ; | ||
1060 | 528 | |||
1061 | 529 | assert(kMagicNumbersSize == AI_initial_military_numbers_A.size()); | ||
1062 | 530 | |||
1063 | 531 | const std::vector<int8_t> input_weights_A = | ||
1064 | 532 | // 0 1 2 3 4 5 6 7 8 9 | ||
1065 | 533 | { 48, -85, -26, 47, -93, -22, -91, 84, 24, -12, // AutoContent_16_AIDNA_1 | ||
1066 | 534 | 98, -59, -89, 76, 81, 95, -91, -90, -56, -15, // AutoContent_17_AIDNA_1 | ||
1067 | 535 | -65, -18, 6, -65, 41, 38, 47, -31, 79, 23, // AutoContent_18_AIDNA_1 | ||
1068 | 536 | 16, 25, -59, 0, -38, -85, -60, -42, 0, -70, // AutoContent_19_AIDNA_1 | ||
1069 | 537 | -78, -86, -87, -55, 92, -63, -21, -76, 4, 87, // AutoContent_20_AIDNA_1 | ||
1070 | 538 | 58, -40, 71, -90, -72, 0, -47, -94, -15, 66, // AutoContent_21_AIDNA_1 | ||
1071 | 539 | -32, 9, 67, -47, -44, -76, -53, 57, -31, -47, // AutoContent_22_AIDNA_1 | ||
1072 | 540 | 0, -28, -16, 48, 41, -45, 36, -8, 51, -49 // AutoContent_23_AIDNA_1 | ||
1073 | 541 | } | ||
1074 | 542 | ; | ||
1075 | 543 | const std::vector<int8_t> input_func_A = | ||
1076 | 544 | { 1, 0, 1, 2, 2, 1, 0, 0, 0, 0, // AutoContent_24_AIDNA_1 | ||
1077 | 545 | 2, 1, 2, 2, 2, 1, 2, 2, 2, 1, // AutoContent_25_AIDNA_1 | ||
1078 | 546 | 2, 2, 0, 2, 2, 1, 0, 1, 0, 2, // AutoContent_26_AIDNA_1 | ||
1079 | 547 | 1, 2, 2, 1, 2, 1, 0, 1, 2, 1, // AutoContent_27_AIDNA_1 | ||
1080 | 548 | 2, 1, 2, 0, 0, 1, 2, 0, 0, 0, // AutoContent_28_AIDNA_1 | ||
1081 | 549 | 1, 0, 0, 1, 0, 1, 0, 0, 1, 1, // AutoContent_29_AIDNA_1 | ||
1082 | 550 | 2, 0, 1, 2, 0, 2, 2, 2, 1, 0, // AutoContent_30_AIDNA_1 | ||
1083 | 551 | 2, 1, 2, 2, 1, 1, 0, 2, 2, 1 // AutoContent_31_AIDNA_1 | ||
1084 | 552 | } | ||
1085 | 553 | ; | ||
1086 | 554 | assert(kNeuronPoolSize == input_func_A.size()); | ||
1087 | 555 | assert(kNeuronPoolSize == input_weights_A.size()); | ||
1088 | 556 | |||
1089 | 557 | const std::vector<uint32_t> f_neurons_A = | ||
1090 | 558 | { 471130763, 1322756799, 1148682382, 2713953719, 194460207, 18113635, 2947490886, 3275944172, 3438582086, 856208494, // AutoContent_32_AIDNA_1 | ||
1091 | 559 | 1326156684, 986431571, 3465514749, 1962749574, 1523585333, 1376482111, 1223335901, 2962231598, 657710612, 578259960, // AutoContent_33_AIDNA_1 | ||
1092 | 560 | 1271222963, 2915927856, 3396846486, 1743568169, 2679432920, 410834609, 134904175, 2968201710, 2132567223, 2248461478, // AutoContent_34_AIDNA_1 | ||
1093 | 561 | 161963959, 3295327519, 670058472, 2013696856, 3608400883, 496651103, 733137541, 2952748738, 3307293853, 3886490843, // AutoContent_35_AIDNA_1 | ||
1094 | 562 | 3233788172, 715230539, 2583635732, 4271028953, 1217674278, 4043323645, 1857109651, 2181897047, 2825979187, 3081298269, // AutoContent_36_AIDNA_1 | ||
1095 | 563 | 1277901018, 1255642150, 2384261818, 2866704864, 755617465, 835768208, 1394358417, 4012239945, 2601238115, 3933467106 // AutoContent_37_AIDNA_1 | ||
1096 | 564 | }; | ||
1097 | 565 | assert(kFNeuronPoolSize == f_neurons_A.size()); | ||
1098 | 566 | |||
1099 | 567 | |||
1100 | 568 | // AutoSCore_AIDNA_2 | ||
1101 | 569 | const std::vector<int16_t> AI_initial_military_numbers_B = | ||
1102 | 570 | { 18, -42, 21, 59, -7, -78, -22, 81, 48, 0, // AutoContent_01_AIDNA_2 | ||
1103 | 571 | -55, 45, -96, 16, 70, -30, 33, 79, -78, -42, // AutoContent_02_AIDNA_2 | ||
1104 | 572 | 79, -16, 34, 46, -22, 0, 45, -33, 53, 51, // AutoContent_03_AIDNA_2 | ||
1105 | 573 | 49, 47, -27, 80, -86, 46, -63, -47, 20, -63, // AutoContent_04_AIDNA_2 | ||
1106 | 574 | 78, 51, 23, -77, 20, 38, 6, 37, -64, -41, // AutoContent_05_AIDNA_2 | ||
1107 | 575 | -3, -55, 62, 0, 64, -92, 4, -89, 71, -18, // AutoContent_06_AIDNA_2 | ||
1108 | 576 | -87, 56, 17, -34, -69, 24, -57, 84, 40, -51, // AutoContent_07_AIDNA_2 | ||
1109 | 577 | 0, 44, 0, -2, -11, -4, -96, -35, -29, -12, // AutoContent_08_AIDNA_2 | ||
1110 | 578 | 71, -98, -25, 50, 97, 74, 0, 65, -60, 23, // AutoContent_09_AIDNA_2 | ||
1111 | 579 | 38, 53, 74, 0, -15, 27, 32, 37, -24, -65, // AutoContent_10_AIDNA_2 | ||
1112 | 580 | 16, -42, 19, -94, -28, 83, -55, -63, 16, -41, // AutoContent_11_AIDNA_2 | ||
1113 | 581 | 28, -3, 0, -87, 32, 5, 4, 6, -20, 62, // AutoContent_12_AIDNA_2 | ||
1114 | 582 | 85, 0, 58, 48, -80, -20, -49, 71, 60, 8, // AutoContent_13_AIDNA_2 | ||
1115 | 583 | -52, 59, 100, -74, 0, -36, -9, 80, 41, -67, // AutoContent_14_AIDNA_2 | ||
1116 | 584 | 0, 15, -96, -51, -21, 11, -27, -30, 76, -47 // AutoContent_15_AIDNA_2 | ||
1117 | 585 | } | ||
1118 | 586 | ; | ||
1119 | 587 | assert(kMagicNumbersSize == AI_initial_military_numbers_B.size()); | ||
1120 | 588 | |||
1121 | 589 | const std::vector<int8_t> input_weights_B = | ||
1122 | 590 | { 48, -85, -26, 47, -93, -22, -91, 84, 50, -12, // AutoContent_16_AIDNA_2 | ||
1123 | 591 | 98, -59, -89, 76, 81, 95, -91, -90, -56, -15, // AutoContent_17_AIDNA_2 | ||
1124 | 592 | -65, -18, 6, -65, 41, 38, 47, -31, 79, 23, // AutoContent_18_AIDNA_2 | ||
1125 | 593 | 16, 25, -59, 0, -38, -85, -60, -42, 0, -70, // AutoContent_19_AIDNA_2 | ||
1126 | 594 | -78, -86, -87, -55, 92, -63, -21, -76, 4, 87, // AutoContent_20_AIDNA_2 | ||
1127 | 595 | 58, -40, 71, -90, -72, 0, -47, -94, -15, 66, // AutoContent_21_AIDNA_2 | ||
1128 | 596 | -32, 9, 67, -47, -44, -76, -53, 57, -31, -47, // AutoContent_22_AIDNA_2 | ||
1129 | 597 | 0, -28, -16, 48, 41, -45, 36, -8, 51, -49 // AutoContent_23_AIDNA_2 | ||
1130 | 598 | } | ||
1131 | 599 | ; | ||
1132 | 600 | |||
1133 | 601 | const std::vector<int8_t> input_func_B = | ||
1134 | 602 | { 1, 0, 1, 2, 2, 1, 0, 0, 0, 0, // AutoContent_24_AIDNA_2 | ||
1135 | 603 | 2, 1, 2, 2, 2, 1, 2, 2, 2, 1, // AutoContent_25_AIDNA_2 | ||
1136 | 604 | 2, 2, 0, 2, 2, 1, 0, 1, 0, 2, // AutoContent_26_AIDNA_2 | ||
1137 | 605 | 1, 2, 2, 1, 2, 1, 0, 1, 2, 1, // AutoContent_27_AIDNA_2 | ||
1138 | 606 | 2, 1, 2, 0, 0, 1, 2, 0, 0, 0, // AutoContent_28_AIDNA_2 | ||
1139 | 607 | 1, 0, 0, 1, 0, 1, 0, 0, 1, 1, // AutoContent_29_AIDNA_2 | ||
1140 | 608 | 2, 0, 1, 2, 0, 2, 2, 2, 1, 0, // AutoContent_30_AIDNA_2 | ||
1141 | 609 | 2, 1, 2, 2, 1, 1, 0, 2, 2, 1 // AutoContent_31_AIDNA_2 | ||
1142 | 610 | } | ||
1143 | 611 | ; | ||
1144 | 612 | assert(kNeuronPoolSize == input_func_B.size()); | ||
1145 | 613 | assert(kNeuronPoolSize == input_weights_B.size()); | ||
1146 | 614 | |||
1147 | 615 | |||
1148 | 616 | const std::vector<uint32_t> f_neurons_B = | ||
1149 | 617 | { 471130763, 1322756799, 1148682382, 2713953719, 194460207, 18113635, 2947490886, 3275944172, 3438582022, 855676014, // AutoContent_32_AIDNA_2 | ||
1150 | 618 | 1326156684, 986431571, 3465514749, 1962749574, 1523650869, 1376482111, 2347409353, 2962227502, 657710612, 578259960, // AutoContent_33_AIDNA_2 | ||
1151 | 619 | 1271222963, 2915927856, 3396846486, 1743568169, 2679432920, 410834609, 134904175, 2968201710, 2132567223, 2248461478, // AutoContent_34_AIDNA_2 | ||
1152 | 620 | 161963959, 3295327519, 670058472, 2013696856, 4145271795, 496651103, 733211269, 2952748738, 1159810205, 3886490843, // AutoContent_35_AIDNA_2 | ||
1153 | 621 | 3225153820, 732007755, 2583635732, 4271028825, 1217674278, 4043323645, 1857109651, 2249005911, 2825979187, 3081298269, // AutoContent_36_AIDNA_2 | ||
1154 | 622 | 1277901018, 1255642150, 2384261818, 2866704864, 755617465, 835768208, 1394096273, 4012239945, 2609626723, 3932418530 // AutoContent_37_AIDNA_2 | ||
1155 | 623 | }; | ||
1156 | 624 | assert(kFNeuronPoolSize == f_neurons_B.size()); | ||
1157 | 625 | |||
1158 | 626 | |||
1159 | 627 | // AutoSCore_AIDNA_3 | ||
1160 | 628 | const std::vector<int16_t> AI_initial_military_numbers_C = | ||
1161 | 629 | { 18, -42, 63, 82, -7, -78, -22, 81, 48, 0, // AutoContent_01_AIDNA_3 | ||
1162 | 630 | -55, 55, -96, 16, 70, -30, 33, 79, -78, -42, // AutoContent_02_AIDNA_3 | ||
1163 | 631 | 79, -16, 34, 46, 0, 0, 0, -29, 53, 51, // AutoContent_03_AIDNA_3 | ||
1164 | 632 | 24, 47, -27, 42, -86, 46, -63, -47, 20, -63, // AutoContent_04_AIDNA_3 | ||
1165 | 633 | 78, 31, 98, -73, 20, 38, 44, 37, -64, -41, // AutoContent_05_AIDNA_3 | ||
1166 | 634 | -3, -55, 67, 0, 64, -92, 4, -89, 71, -60, // AutoContent_06_AIDNA_3 | ||
1167 | 635 | -87, 56, 17, -34, -69, 24, -57, 50, 40, -51, // AutoContent_07_AIDNA_3 | ||
1168 | 636 | -34, 44, 0, -2, -11, -4, -96, -35, -29, -12, // AutoContent_08_AIDNA_3 | ||
1169 | 637 | 68, -98, -25, 50, 97, 74, 0, 65, -60, 23, // AutoContent_09_AIDNA_3 | ||
1170 | 638 | 38, 53, 74, 0, -15, 27, 32, 61, -24, -65, // AutoContent_10_AIDNA_3 | ||
1171 | 639 | 16, -42, 19, -94, -65, 83, -55, -63, 16, -41, // AutoContent_11_AIDNA_3 | ||
1172 | 640 | 74, -3, 0, -87, 32, 5, 4, 6, -70, 62, // AutoContent_12_AIDNA_3 | ||
1173 | 641 | 85, 0, 58, 48, -80, -20, -49, 71, 60, 8, // AutoContent_13_AIDNA_3 | ||
1174 | 642 | -52, 30, 69, -74, 0, -36, -57, 80, 64, -67, // AutoContent_14_AIDNA_3 | ||
1175 | 643 | 0, 15, -96, -51, -21, 0, -33, -30, 76, -47 // AutoContent_15_AIDNA_3 | ||
1176 | 644 | } | ||
1177 | 645 | |||
1178 | 646 | ; | ||
1179 | 647 | |||
1180 | 648 | assert(kMagicNumbersSize == AI_initial_military_numbers_C.size()); | ||
1181 | 649 | |||
1182 | 650 | const std::vector<int8_t> input_weights_C = | ||
1183 | 651 | { 48, -85, -26, 47, -65, -19, -91, 84, 92, -12, // AutoContent_16_AIDNA_3 | ||
1184 | 652 | 78, -59, -89, 76, 81, 95, -91, -90, -56, -15, // AutoContent_17_AIDNA_3 | ||
1185 | 653 | -65, -18, 6, -65, 17, 38, 47, -45, 79, 23, // AutoContent_18_AIDNA_3 | ||
1186 | 654 | 16, 25, -59, 36, -38, -85, -60, -42, 0, -70, // AutoContent_19_AIDNA_3 | ||
1187 | 655 | -78, -86, -87, -55, 92, -63, -21, -76, 4, 87, // AutoContent_20_AIDNA_3 | ||
1188 | 656 | 58, -40, 71, -90, -72, 0, -47, -94, -15, 95, // AutoContent_21_AIDNA_3 | ||
1189 | 657 | -32, 9, 67, -47, -44, -76, -53, 57, -31, -47, // AutoContent_22_AIDNA_3 | ||
1190 | 658 | 0, -28, -16, 48, 41, -45, 36, -8, 63, -49 // AutoContent_23_AIDNA_3 | ||
1191 | 659 | } | ||
1192 | 660 | ; | ||
1193 | 661 | const std::vector<int8_t> input_func_C = | ||
1194 | 662 | { 1, 0, 1, 2, 2, 1, 0, 0, 0, 0, // AutoContent_24_AIDNA_3 | ||
1195 | 663 | 2, 1, 2, 2, 1, 1, 2, 2, 2, 1, // AutoContent_25_AIDNA_3 | ||
1196 | 664 | 2, 2, 0, 2, 2, 1, 0, 1, 0, 2, // AutoContent_26_AIDNA_3 | ||
1197 | 665 | 1, 2, 2, 1, 2, 1, 0, 1, 2, 1, // AutoContent_27_AIDNA_3 | ||
1198 | 666 | 2, 1, 2, 0, 0, 1, 2, 0, 0, 0, // AutoContent_28_AIDNA_3 | ||
1199 | 667 | 1, 0, 0, 1, 0, 2, 0, 0, 1, 1, // AutoContent_29_AIDNA_3 | ||
1200 | 668 | 2, 0, 1, 2, 0, 2, 2, 2, 1, 0, // AutoContent_30_AIDNA_3 | ||
1201 | 669 | 2, 1, 2, 2, 1, 1, 0, 2, 2, 1 // AutoContent_31_AIDNA_3 | ||
1202 | 670 | } | ||
1203 | 671 | ; | ||
1204 | 672 | assert(kNeuronPoolSize == input_func_C.size()); | ||
1205 | 673 | assert(kNeuronPoolSize == input_weights_C.size()); | ||
1206 | 674 | |||
1207 | 675 | const std::vector<uint32_t> f_neurons_C = | ||
1208 | 676 | { 202828425, 1322625717, 1148682382, 2244191679, 194456367, 26493027, 2947491014, 3410163948, 3438582086, 856208494, // AutoContent_32_AIDNA_3 | ||
1209 | 677 | 1259048860, 986431571, 3457662708, 1954360966, 1523650869, 1376351039, 1223335901, 2997887274, 657657361, 645368312, // AutoContent_33_AIDNA_3 | ||
1210 | 678 | 1271218867, 2915927856, 3933717470, 2011479337, 2645864080, 408737457, 2282387823, 2968205806, 1597793527, 2248461494, // AutoContent_34_AIDNA_3 | ||
1211 | 679 | 161963959, 1147843615, 670058474, 2013712728, 4145271795, 496651102, 724812677, 2952748738, 1629834973, 3819381979, // AutoContent_35_AIDNA_3 | ||
1212 | 680 | 3233788172, 732007755, 2583635734, 4271028825, 1217670182, 4043323645, 1857109659, 2249005911, 2834367795, 3072909661, // AutoContent_36_AIDNA_3 | ||
1213 | 681 | 1278949528, 1792513063, 2384261690, 2732487136, 755615385, 835767184, 1393834641, 4012239945, 2601238115, 2859725290 // AutoContent_37_AIDNA_3 | ||
1214 | 682 | }; | ||
1215 | 683 | assert(kFNeuronPoolSize == f_neurons_C.size()); | ||
1216 | 684 | |||
1217 | 685 | |||
1218 | 686 | // AutoSCore_AIDNA_4 | ||
1219 | 687 | const std::vector<int16_t> AI_initial_military_numbers_D = | ||
1220 | 688 | { 18, -42, 21, 59, -7, -78, -22, 81, 48, 0, // AutoContent_01_AIDNA_4 | ||
1221 | 689 | -55, 45, -96, 16, 70, -30, 33, 79, -78, -42, // AutoContent_02_AIDNA_4 | ||
1222 | 690 | 79, -16, 34, 46, -22, 0, 45, -29, 53, 51, // AutoContent_03_AIDNA_4 | ||
1223 | 691 | 24, 47, -27, 80, -86, 46, -63, -47, 20, -63, // AutoContent_04_AIDNA_4 | ||
1224 | 692 | 78, 51, -25, -77, 20, 38, 6, 37, -64, -41, // AutoContent_05_AIDNA_4 | ||
1225 | 693 | -3, -55, 62, 0, 64, -92, 4, -89, 71, -18, // AutoContent_06_AIDNA_4 | ||
1226 | 694 | -87, 56, 17, -34, -69, 24, -57, 84, 40, -51, // AutoContent_07_AIDNA_4 | ||
1227 | 695 | 0, 44, 0, -2, -11, -4, -96, -35, -29, -12, // AutoContent_08_AIDNA_4 | ||
1228 | 696 | 71, -98, -25, 50, 97, 74, 0, 65, -60, 23, // AutoContent_09_AIDNA_4 | ||
1229 | 697 | 38, 53, 74, 0, -15, 27, 32, 37, -24, -65, // AutoContent_10_AIDNA_4 | ||
1230 | 698 | 16, -61, 19, -94, -28, 83, -55, -63, 16, -41, // AutoContent_11_AIDNA_4 | ||
1231 | 699 | 28, -3, 0, -87, 32, 5, 4, 6, -20, 62, // AutoContent_12_AIDNA_4 | ||
1232 | 700 | 85, 0, 58, 48, -80, -20, -49, 71, 60, 8, // AutoContent_13_AIDNA_4 | ||
1233 | 701 | -52, 59, 100, -74, 0, -36, -9, 80, 41, -67, // AutoContent_14_AIDNA_4 | ||
1234 | 702 | 0, 15, -96, -51, -21, 11, -27, -30, 76, -47 // AutoContent_15_AIDNA_4 | ||
1235 | 703 | } | ||
1236 | 704 | ; | ||
1237 | 705 | assert(kMagicNumbersSize == AI_initial_military_numbers_D.size()); | ||
1238 | 706 | |||
1239 | 707 | const std::vector<int8_t> input_weights_D = | ||
1240 | 708 | { 48, -85, -26, 47, -93, -22, -91, 84, 50, -12, // AutoContent_16_AIDNA_4 | ||
1241 | 709 | 98, -59, -89, 76, 81, 95, -91, -90, -56, -15, // AutoContent_17_AIDNA_4 | ||
1242 | 710 | -65, -18, 6, -65, 41, 38, 47, -31, 79, 23, // AutoContent_18_AIDNA_4 | ||
1243 | 711 | 16, 25, -59, 0, -38, -85, -60, -42, 0, -70, // AutoContent_19_AIDNA_4 | ||
1244 | 712 | -78, -86, -87, -55, 92, -63, -21, -76, 4, 87, // AutoContent_20_AIDNA_4 | ||
1245 | 713 | 58, -40, 71, -90, -72, 0, -47, -94, -15, 66, // AutoContent_21_AIDNA_4 | ||
1246 | 714 | -32, 9, 67, -47, -44, -76, -53, 57, -31, -47, // AutoContent_22_AIDNA_4 | ||
1247 | 715 | 0, -28, -16, 48, 41, -45, 36, -8, 63, -49 // AutoContent_23_AIDNA_4 | ||
1248 | 716 | } | ||
1249 | 717 | ; | ||
1250 | 718 | |||
1251 | 719 | const std::vector<int8_t> input_func_D = | ||
1252 | 720 | { 1, 0, 1, 2, 2, 1, 0, 0, 0, 0, // AutoContent_24_AIDNA_4 | ||
1253 | 721 | 2, 1, 2, 2, 2, 1, 2, 2, 2, 1, // AutoContent_25_AIDNA_4 | ||
1254 | 722 | 2, 2, 0, 2, 2, 1, 0, 1, 0, 2, // AutoContent_26_AIDNA_4 | ||
1255 | 723 | 1, 2, 2, 1, 2, 1, 0, 1, 2, 1, // AutoContent_27_AIDNA_4 | ||
1256 | 724 | 2, 1, 2, 0, 0, 1, 2, 0, 0, 0, // AutoContent_28_AIDNA_4 | ||
1257 | 725 | 1, 0, 0, 1, 0, 1, 0, 0, 1, 1, // AutoContent_29_AIDNA_4 | ||
1258 | 726 | 2, 0, 1, 2, 0, 2, 2, 2, 1, 0, // AutoContent_30_AIDNA_4 | ||
1259 | 727 | 2, 1, 2, 2, 1, 1, 0, 2, 2, 1 // AutoContent_31_AIDNA_4 | ||
1260 | 728 | } | ||
1261 | 729 | ; | ||
1262 | 730 | assert(kNeuronPoolSize == input_func_D.size()); | ||
1263 | 731 | assert(kNeuronPoolSize == input_weights_D.size()); | ||
1264 | 732 | |||
1265 | 733 | const std::vector<uint32_t> f_neurons_D = | ||
1266 | 734 | { 471130763, 1322756799, 1148682382, 2713953719, 194460175, 18113635, 2947490886, 3275944172, 3438582214, 856208494, // AutoContent_32_AIDNA_4 | ||
1267 | 735 | 1326156684, 449560659, 3465512701, 1962749574, 1523650869, 1376482111, 2347409353, 2962227502, 657710614, 578259960, // AutoContent_33_AIDNA_4 | ||
1268 | 736 | 1271222963, 2915927856, 3396846486, 1743568169, 2679432920, 410834611, 134904175, 2968201710, 2132567223, 2248461478, // AutoContent_34_AIDNA_4 | ||
1269 | 737 | 161963959, 3295327519, 670058472, 2013696856, 3608400883, 496651103, 733137541, 2952748738, 1159810205, 3886490843, // AutoContent_35_AIDNA_4 | ||
1270 | 738 | 3225153820, 732007755, 2583635732, 4271028825, 1217674278, 4043323645, 1857109651, 2248481623, 3899721011, 3081298269, // AutoContent_36_AIDNA_4 | ||
1271 | 739 | 1277901016, 1255642150, 2384261818, 2866704864, 755617465, 835768208, 1394358417, 4012239945, 2601238115, 3933467106 // AutoContent_37_AIDNA_4 | ||
1272 | 740 | }; | ||
1273 | 741 | assert(kFNeuronPoolSize == f_neurons_D.size()); | ||
1274 | 742 | |||
1275 | 743 | primary_parent = std::rand() % 4; | ||
1276 | 744 | const uint8_t parent2 = std::rand() % 4; | ||
1277 | 745 | |||
1278 | 746 | log (" ... Primary parent: %d, secondary parent: %d\n", primary_parent, parent2); | ||
1279 | 747 | |||
1280 | 748 | // First setting of military numbers, they go directly to persistent data | ||
1281 | 749 | for (uint16_t i = 0; i < kMagicNumbersSize; i += 1) { | ||
1282 | 750 | // Child inherits DNA with probability 5:1 from main parent | ||
1283 | 751 | uint8_t dna_donor = (std::rand() % kSecondParentProbability > 0) ? primary_parent : parent2; | ||
1284 | 752 | if (i == kMutationRatePosition) { // Overwriting | ||
1285 | 753 | dna_donor = primary_parent; | ||
1286 | 754 | } | ||
1287 | 755 | |||
1288 | 756 | switch (dna_donor) { | ||
1289 | 757 | case 0 : | ||
1290 | 758 | set_military_number_at(i, AI_initial_military_numbers_A[i]); | ||
1291 | 759 | break; | ||
1292 | 760 | case 1 : | ||
1293 | 761 | set_military_number_at(i, AI_initial_military_numbers_B[i]); | ||
1294 | 762 | break; | ||
1295 | 763 | case 2 : | ||
1296 | 764 | set_military_number_at(i, AI_initial_military_numbers_C[i]); | ||
1297 | 765 | break; | ||
1298 | 766 | case 3 : | ||
1299 | 767 | set_military_number_at(i, AI_initial_military_numbers_D[i]); | ||
1300 | 768 | break; | ||
1301 | 769 | default: | ||
1302 | 770 | log ("parent %d?\n", dna_donor); | ||
1303 | 771 | NEVER_HERE(); | ||
1304 | 772 | } | ||
1305 | 773 | } | ||
1306 | 774 | |||
1307 | 775 | pd->neuron_weights.clear(); | ||
1308 | 776 | pd->neuron_functs.clear(); | ||
1309 | 777 | pd->f_neurons.clear(); | ||
1310 | 778 | |||
1311 | 779 | for (uint16_t i = 0; i < kNeuronPoolSize; i += 1) { | ||
1312 | 780 | const uint8_t dna_donor = (std::rand() % kSecondParentProbability > 0) ? primary_parent : parent2; | ||
1313 | 781 | |||
1314 | 782 | switch (dna_donor) { | ||
1315 | 783 | case 0 : | ||
1316 | 784 | pd->neuron_weights.push_back(input_weights_A[i]); | ||
1317 | 785 | pd->neuron_functs.push_back(input_func_A[i]); | ||
1318 | 786 | break; | ||
1319 | 787 | case 1 : | ||
1320 | 788 | pd->neuron_weights.push_back(input_weights_B[i]); | ||
1321 | 789 | pd->neuron_functs.push_back(input_func_B[i]); | ||
1322 | 790 | break; | ||
1323 | 791 | case 2 : | ||
1324 | 792 | pd->neuron_weights.push_back(input_weights_C[i]); | ||
1325 | 793 | pd->neuron_functs.push_back(input_func_C[i]); | ||
1326 | 794 | break; | ||
1327 | 795 | case 3 : | ||
1328 | 796 | pd->neuron_weights.push_back(input_weights_D[i]); | ||
1329 | 797 | pd->neuron_functs.push_back(input_func_D[i]); | ||
1330 | 798 | break; | ||
1331 | 799 | default: | ||
1332 | 800 | log ("parent %d?\n", dna_donor); | ||
1333 | 801 | NEVER_HERE(); | ||
1334 | 802 | } | ||
1335 | 803 | } | ||
1336 | 804 | |||
1337 | 805 | |||
1338 | 806 | for (uint16_t i = 0; i < kFNeuronPoolSize; i += 1) { | ||
1339 | 807 | const uint8_t dna_donor = (std::rand() % kSecondParentProbability > 0) ? primary_parent : parent2; | ||
1340 | 808 | switch (dna_donor) { | ||
1341 | 809 | case 0 : | ||
1342 | 810 | pd->f_neurons.push_back(f_neurons_A[i]); | ||
1343 | 811 | break; | ||
1344 | 812 | case 1 : | ||
1345 | 813 | pd->f_neurons.push_back(f_neurons_B[i]); | ||
1346 | 814 | break; | ||
1347 | 815 | case 2 : | ||
1348 | 816 | pd->f_neurons.push_back(f_neurons_C[i]); | ||
1349 | 817 | break; | ||
1350 | 818 | case 3 : | ||
1351 | 819 | pd->f_neurons.push_back(f_neurons_D[i]); | ||
1352 | 820 | break; | ||
1353 | 821 | default: | ||
1354 | 822 | log ("parent %d?\n", dna_donor); | ||
1355 | 823 | NEVER_HERE(); | ||
1356 | 824 | } | ||
1357 | 825 | } | ||
1358 | 826 | |||
1359 | 827 | pd->magic_numbers_size = kMagicNumbersSize; | ||
1360 | 828 | pd->neuron_pool_size = kNeuronPoolSize; | ||
1361 | 829 | pd->f_neuron_pool_size = kFNeuronPoolSize; | ||
1362 | 830 | |||
1363 | 831 | } | ||
1364 | 832 | // Decides if mutation takes place and how intensive it will be | ||
1365 | 833 | MutatingIntensity ManagementData::do_mutate(const uint8_t is_preferred, const int16_t mutation_probability) { | ||
1366 | 834 | if (is_preferred > 0) { | ||
1367 | 835 | return MutatingIntensity::kAgressive; | ||
1368 | 836 | } | ||
1369 | 837 | if (std::rand() % mutation_probability == 0) { | ||
1370 | 838 | return MutatingIntensity::kNormal; | ||
1371 | 839 | } | ||
1372 | 840 | return MutatingIntensity::kNo; | ||
1373 | 841 | } | ||
1374 | 842 | |||
1375 | 843 | // Mutating, but all done on persistent data | ||
1376 | 844 | void ManagementData::mutate(const uint8_t pn) { | ||
1377 | 845 | |||
1378 | 846 | int16_t probability = | ||
1379 | 847 | shift_weight_value(get_military_number_at(kMutationRatePosition), false) + 101; | ||
1380 | 848 | if (probability > kUpperDefaultMutationLimit) { | ||
1381 | 849 | probability = kUpperDefaultMutationLimit; | ||
1382 | 850 | } | ||
1383 | 851 | if (probability < kLowerDefaultMutationLimit) { | ||
1384 | 852 | probability = kLowerDefaultMutationLimit; | ||
1385 | 853 | } | ||
1386 | 854 | |||
1387 | 855 | set_military_number_at(kMutationRatePosition, probability - 101); | ||
1388 | 856 | |||
1389 | 857 | // decreasing probability (or rather increasing probability of mutation) if weaker player | ||
1390 | 858 | if (ai_type == Widelands::AiType::kWeak) { | ||
1391 | 859 | probability /= 2; | ||
1392 | 860 | log("%2d: Weak mode, increasing mutation probability to 1 / %d\n", pn, probability); | ||
1393 | 861 | } else if (ai_type == Widelands::AiType::kVeryWeak) { | ||
1394 | 862 | probability /= 4; | ||
1395 | 863 | log("%2d: Very weak mode, increasing mutation probability to 1 / %d\n", pn, probability); | ||
1396 | 864 | } | ||
1397 | 865 | |||
1398 | 866 | assert(probability > 0 && probability <= 201); | ||
1399 | 867 | |||
1400 | 868 | log("%2d: mutating DNA with probability 1 / %3d:\n", pn, probability); | ||
1401 | 869 | |||
1402 | 870 | if (probability < 201) { | ||
1403 | 871 | |||
1404 | 872 | // Modifying pool of Military numbers | ||
1405 | 873 | { | ||
1406 | 874 | // Preferred numbers are ones that will be mutated agressively in full range [-kWeightRange, kWeightRange] | ||
1407 | 875 | std::set<int32_t> preferred_numbers = {}; | ||
1408 | 876 | |||
1409 | 877 | for (uint16_t i = 0; i < kMagicNumbersSize; i += 1) { | ||
1410 | 878 | if (i == kMutationRatePosition) { // mutated above | ||
1411 | 879 | continue; | ||
1412 | 880 | } | ||
1413 | 881 | |||
1414 | 882 | const MutatingIntensity mutating_intensity = do_mutate(preferred_numbers.count(i) > 0, probability); | ||
1415 | 883 | |||
1416 | 884 | if (mutating_intensity != MutatingIntensity::kNo) { | ||
1417 | 885 | const int16_t old_value = get_military_number_at(i); | ||
1418 | 886 | const int16_t new_value = shift_weight_value(get_military_number_at(i), mutating_intensity == MutatingIntensity::kAgressive); | ||
1419 | 887 | set_military_number_at(i, new_value); | ||
1420 | 888 | log(" Magic number %3d: value changed: %4d -> %4d %s\n", i, old_value, | ||
1421 | 889 | new_value, (mutating_intensity == MutatingIntensity::kAgressive) ? "aggressive" : ""); | ||
1422 | 890 | } | ||
1423 | 891 | } | ||
1424 | 892 | } | ||
1425 | 893 | |||
1426 | 894 | // Modifying pool of neurons | ||
1427 | 895 | { | ||
1428 | 896 | // Neurons to be mutated more agressively | ||
1429 | 897 | std::set<int32_t> preferred_neurons = {}; | ||
1430 | 898 | for (auto& item : neuron_pool) { | ||
1431 | 899 | |||
1432 | 900 | const MutatingIntensity mutating_intensity = do_mutate(preferred_neurons.count(item.get_id()) > 0, probability); | ||
1433 | 901 | |||
1434 | 902 | if (mutating_intensity != MutatingIntensity::kNo) { | ||
1435 | 903 | const int16_t old_value = item.get_weight(); | ||
1436 | 904 | if (std::rand() % 4 == 0) { | ||
1437 | 905 | assert(!neuron_curves.empty()); | ||
1438 | 906 | item.set_type(std::rand() % neuron_curves.size()); | ||
1439 | 907 | pd->neuron_functs[item.get_id()] = item.get_type(); | ||
1440 | 908 | } else { | ||
1441 | 909 | int16_t new_value = shift_weight_value(item.get_weight(), mutating_intensity == MutatingIntensity::kAgressive); | ||
1442 | 910 | item.set_weight(new_value); | ||
1443 | 911 | pd->neuron_weights[item.get_id()] = item.get_weight(); | ||
1444 | 912 | } | ||
1445 | 913 | log(" Neuron %2d: weight: %4d -> %4d, new curve: %d %s\n", item.get_id(), | ||
1446 | 914 | old_value, item.get_weight(), item.get_type(), | ||
1447 | 915 | (mutating_intensity == MutatingIntensity::kAgressive) ? "aggressive" : ""); | ||
1448 | 916 | |||
1449 | 917 | item.recalculate(); | ||
1450 | 918 | } | ||
1451 | 919 | } | ||
1452 | 920 | } | ||
1453 | 921 | |||
1454 | 922 | // Modifying pool of f-neurons | ||
1455 | 923 | { | ||
1456 | 924 | // FNeurons to be mutated more agressively | ||
1457 | 925 | std::set<int32_t> preferred_f_neurons = {}; | ||
1458 | 926 | for (auto& item : f_neuron_pool) { | ||
1459 | 927 | uint8_t changed_bits = 0; | ||
1460 | 928 | // is this a preferred neuron | ||
1461 | 929 | if (preferred_f_neurons.count(item.get_id()) > 0) { | ||
1462 | 930 | for (uint8_t i = 0; i < kFNeuronBitSize; i += 1) { | ||
1463 | 931 | if (std::rand() % 5 == 0) { | ||
1464 | 932 | item.flip_bit(i); | ||
1465 | 933 | changed_bits += 1; | ||
1466 | 934 | } | ||
1467 | 935 | } | ||
1468 | 936 | } else { // normal mutation | ||
1469 | 937 | for (uint8_t i = 0; i < kFNeuronBitSize; i += 1) { | ||
1470 | 938 | if (std::rand() % (probability * 3) == 0) { | ||
1471 | 939 | item.flip_bit(i); | ||
1472 | 940 | changed_bits += 1; | ||
1473 | 941 | } | ||
1474 | 942 | } | ||
1475 | 943 | } | ||
1476 | 944 | |||
1477 | 945 | if (changed_bits) { | ||
1478 | 946 | pd->f_neurons[item.get_id()] = item.get_int(); | ||
1479 | 947 | log(" F-Neuron %2d: new value: %13ul, changed bits: %2d %s\n", | ||
1480 | 948 | item.get_id(), item.get_int(), changed_bits, | ||
1481 | 949 | (preferred_f_neurons.count(item.get_id()) > 0) ? "aggressive" : ""); | ||
1482 | 950 | } | ||
1483 | 951 | } | ||
1484 | 952 | } | ||
1485 | 953 | } | ||
1486 | 954 | |||
1487 | 955 | test_consistency(); | ||
1488 | 956 | } | ||
1489 | 957 | |||
1490 | 958 | // Now we copy persistent to local | ||
1491 | 959 | void ManagementData::copy_persistent_to_local() { | ||
1492 | 960 | |||
1493 | 961 | assert(pd->neuron_weights.size() == kNeuronPoolSize); | ||
1494 | 962 | assert(pd->neuron_functs.size() == kNeuronPoolSize); | ||
1495 | 963 | neuron_pool.clear(); | ||
1496 | 964 | for (uint32_t i = 0; i < kNeuronPoolSize; i = i + 1) { | ||
1497 | 965 | neuron_pool.push_back(Neuron(pd->neuron_weights[i], pd->neuron_functs[i], i)); | ||
1498 | 966 | } | ||
1499 | 967 | |||
1500 | 968 | assert(pd->f_neurons.size() == kFNeuronPoolSize); | ||
1501 | 969 | f_neuron_pool.clear(); | ||
1502 | 970 | for (uint32_t i = 0; i < kFNeuronPoolSize; i = i + 1) { | ||
1503 | 971 | f_neuron_pool.push_back(FNeuron(pd->f_neurons[i], i)); | ||
1504 | 972 | } | ||
1505 | 973 | |||
1506 | 974 | pd->magic_numbers_size = kMagicNumbersSize; | ||
1507 | 975 | pd->neuron_pool_size = kNeuronPoolSize; | ||
1508 | 976 | pd->f_neuron_pool_size = kFNeuronPoolSize; | ||
1509 | 977 | |||
1510 | 978 | test_consistency(); | ||
1511 | 979 | log(" ... DNA initialized\n"); | ||
1512 | 980 | } | ||
1513 | 981 | |||
1514 | 982 | void ManagementData::test_consistency(bool itemized) { | ||
1515 | 983 | |||
1516 | 984 | assert(pd->neuron_weights.size() == pd->neuron_pool_size); | ||
1517 | 985 | assert(pd->neuron_functs.size() == pd->neuron_pool_size); | ||
1518 | 986 | assert(neuron_pool.size() == pd->neuron_pool_size); | ||
1519 | 987 | assert(neuron_pool.size() == kNeuronPoolSize); | ||
1520 | 988 | |||
1521 | 989 | assert(pd->magic_numbers_size == kMagicNumbersSize); | ||
1522 | 990 | assert(pd->magic_numbers.size() == kMagicNumbersSize); | ||
1523 | 991 | |||
1524 | 992 | assert(pd->f_neurons.size() == pd->f_neuron_pool_size); | ||
1525 | 993 | assert(f_neuron_pool.size() == pd->f_neuron_pool_size); | ||
1526 | 994 | assert(f_neuron_pool.size() == kFNeuronPoolSize); | ||
1527 | 995 | |||
1528 | 996 | if (itemized) { | ||
1529 | 997 | // comparing contents of neuron and fneuron pools | ||
1530 | 998 | for (uint16_t i = 0; i < kNeuronPoolSize; i += 1) { | ||
1531 | 999 | assert(pd->neuron_weights[i] == neuron_pool[i].get_weight()); | ||
1532 | 1000 | assert(pd->neuron_functs[i] == neuron_pool[i].get_type()); | ||
1533 | 1001 | assert(neuron_pool[i].get_id() == i); | ||
1534 | 1002 | } | ||
1535 | 1003 | for (uint16_t i = 0; i < kFNeuronPoolSize; i += 1) { | ||
1536 | 1004 | assert(pd->f_neurons[i] == f_neuron_pool[i].get_int()); | ||
1537 | 1005 | assert(f_neuron_pool[i].get_id() == i); | ||
1538 | 1006 | } | ||
1539 | 1007 | } | ||
1540 | 1008 | |||
1541 | 1009 | return; | ||
1542 | 1010 | } | ||
1543 | 1011 | |||
1544 | 1012 | // Print DNA data to console, used for training | ||
1545 | 1013 | // TODO(tiborb): Once we will have AI dumped into files, this should be removed | ||
1546 | 1014 | // Also, used only for training | ||
1547 | 1015 | void ManagementData::dump_data() { | ||
1548 | 1016 | // dumping new numbers | ||
1549 | 1017 | log(" actual military_numbers (%lu):\n {", pd->magic_numbers.size()); | ||
1550 | 1018 | uint16_t itemcounter = 1; | ||
1551 | 1019 | uint16_t line_counter = 1; | ||
1552 | 1020 | for (const auto& item : pd->magic_numbers) { | ||
1553 | 1021 | log(" %3d%s", item, (&item != &pd->magic_numbers.back()) ? ", " : " "); | ||
1554 | 1022 | if (itemcounter % 10 == 0) { | ||
1555 | 1023 | log(" // AutoContent_%02d\n ", line_counter); | ||
1556 | 1024 | line_counter += 1; | ||
1557 | 1025 | } | ||
1558 | 1026 | ++itemcounter; | ||
1559 | 1027 | } | ||
1560 | 1028 | log("}\n"); | ||
1561 | 1029 | |||
1562 | 1030 | log(" actual neuron setup:\n "); | ||
1563 | 1031 | log("{ "); | ||
1564 | 1032 | itemcounter = 1; | ||
1565 | 1033 | for (auto& item : neuron_pool) { | ||
1566 | 1034 | log(" %3d%s", item.get_weight(), (&item != &neuron_pool.back()) ? ", " : " "); | ||
1567 | 1035 | if (itemcounter % 10 == 0) { | ||
1568 | 1036 | log(" // AutoContent_%02d\n ", line_counter); | ||
1569 | 1037 | line_counter += 1; | ||
1570 | 1038 | } | ||
1571 | 1039 | ++itemcounter; | ||
1572 | 1040 | } | ||
1573 | 1041 | log("}\n { "); | ||
1574 | 1042 | itemcounter = 1; | ||
1575 | 1043 | for (auto& item : neuron_pool) { | ||
1576 | 1044 | log(" %3d%s", item.get_type(), (&item != &neuron_pool.back()) ? ", " : " "); | ||
1577 | 1045 | if (itemcounter % 10 == 0) { | ||
1578 | 1046 | log(" // AutoContent_%02d\n ", line_counter); | ||
1579 | 1047 | line_counter += 1; | ||
1580 | 1048 | } | ||
1581 | 1049 | ++itemcounter; | ||
1582 | 1050 | } | ||
1583 | 1051 | log("}\n"); | ||
1584 | 1052 | |||
1585 | 1053 | log(" actual f-neuron setup:\n "); | ||
1586 | 1054 | log("{ "); | ||
1587 | 1055 | itemcounter = 1; | ||
1588 | 1056 | for (auto& item : f_neuron_pool) { | ||
1589 | 1057 | log(" %8u%s", item.get_int(), (&item != &f_neuron_pool.back()) ? ", " : " "); | ||
1590 | 1058 | if (itemcounter % 10 == 0) { | ||
1591 | 1059 | log(" // AutoContent_%02d\n ", line_counter); | ||
1592 | 1060 | line_counter += 1; | ||
1593 | 1061 | } | ||
1594 | 1062 | ++itemcounter; | ||
1595 | 1063 | } | ||
1596 | 1064 | log("}\n"); | ||
1597 | 1065 | } | ||
1598 | 1066 | |||
1599 | 1067 | // Querying military number at a possition | ||
1600 | 1068 | int16_t ManagementData::get_military_number_at(uint8_t pos) { | ||
1601 | 1069 | assert(pos < kMagicNumbersSize); | ||
1602 | 1070 | return pd->magic_numbers[pos]; | ||
1603 | 1071 | } | ||
1604 | 1072 | |||
1605 | 1073 | // Setting military number (persistent numbers are used also for local use) | ||
1606 | 1074 | void ManagementData::set_military_number_at(const uint8_t pos, int16_t value) { | ||
1607 | 1075 | assert(pos < kMagicNumbersSize); | ||
1608 | 1076 | |||
1609 | 1077 | while (pos >= pd->magic_numbers.size()) { | ||
1610 | 1078 | pd->magic_numbers.push_back(0); | ||
1611 | 1079 | } | ||
1612 | 1080 | |||
1613 | 1081 | value = Neuron::clip_weight_to_range(value); | ||
1614 | 1082 | pd->magic_numbers[pos] = value; | ||
1615 | 277 | } | 1083 | } |
1616 | 278 | 1084 | ||
1617 | 279 | uint16_t MineTypesObserver::total_count() const { | 1085 | uint16_t MineTypesObserver::total_count() const { |
1618 | @@ -292,7 +1098,7 @@ | |||
1619 | 292 | : due_time(time), id(t), priority(p), descr(d) { | 1098 | : due_time(time), id(t), priority(p), descr(d) { |
1620 | 293 | } | 1099 | } |
1621 | 294 | 1100 | ||
1623 | 295 | bool SchedulerTask::operator<(SchedulerTask other) const { | 1101 | bool SchedulerTask::operator<(const SchedulerTask& other) const { |
1624 | 296 | return priority > other.priority; | 1102 | return priority > other.priority; |
1625 | 297 | } | 1103 | } |
1626 | 298 | 1104 | ||
1627 | @@ -450,9 +1256,7 @@ | |||
1628 | 450 | } | 1256 | } |
1629 | 451 | } | 1257 | } |
1630 | 452 | 1258 | ||
1634 | 453 | bool FlagsForRoads::get_winner(uint32_t* winner_hash, uint32_t pos) { | 1259 | bool FlagsForRoads::get_winner(uint32_t* winner_hash) { |
1632 | 454 | assert(pos == 1 || pos == 2); | ||
1633 | 455 | uint32_t counter = 1; | ||
1635 | 456 | // If AI can ask for 2nd position, but there is only one viable candidate | 1260 | // If AI can ask for 2nd position, but there is only one viable candidate |
1636 | 457 | // we return the first one of course | 1261 | // we return the first one of course |
1637 | 458 | bool has_winner = false; | 1262 | bool has_winner = false; |
1638 | @@ -466,37 +1270,98 @@ | |||
1639 | 466 | *winner_hash = candidate_flag.coords_hash; | 1270 | *winner_hash = candidate_flag.coords_hash; |
1640 | 467 | has_winner = true; | 1271 | has_winner = true; |
1641 | 468 | 1272 | ||
1643 | 469 | if (counter == pos) { | 1273 | if (std::rand() % 3 > 0) { |
1644 | 1274 | // with probability of 2/3 we accept this flag | ||
1645 | 470 | return true; | 1275 | return true; |
1646 | 471 | } else if (counter < pos) { | ||
1647 | 472 | counter += 1; | ||
1648 | 473 | } else { | ||
1649 | 474 | break; | ||
1650 | 475 | } | 1276 | } |
1651 | 476 | } | 1277 | } |
1652 | 1278 | |||
1653 | 477 | if (has_winner) { | 1279 | if (has_winner) { |
1654 | 478 | return true; | 1280 | return true; |
1655 | 479 | } | 1281 | } |
1656 | 480 | return false; | 1282 | return false; |
1657 | 481 | } | 1283 | } |
1658 | 482 | 1284 | ||
1665 | 483 | // This is an struct that stores strength of players, info on teams and provides some outputs from | 1285 | PlayersStrengths::PlayersStrengths() : update_time(0) { |
1666 | 484 | // these data | 1286 | } |
1667 | 485 | PlayersStrengths::PlayerStat::PlayerStat() : team_number(0), players_power(0) { | 1287 | |
1668 | 486 | } | 1288 | // Default constructor |
1669 | 487 | PlayersStrengths::PlayerStat::PlayerStat(Widelands::TeamNumber tc, uint32_t pp) | 1289 | PlayersStrengths::PlayerStat::PlayerStat() |
1670 | 488 | : team_number(tc), players_power(pp) { | 1290 | : team_number(0), |
1671 | 1291 | is_enemy(false), | ||
1672 | 1292 | players_power(0), | ||
1673 | 1293 | old_players_power(0), | ||
1674 | 1294 | old60_players_power(0), | ||
1675 | 1295 | players_casualities(0) { | ||
1676 | 1296 | } | ||
1677 | 1297 | |||
1678 | 1298 | // Constructor to be used | ||
1679 | 1299 | PlayersStrengths::PlayerStat::PlayerStat(Widelands::TeamNumber tc, | ||
1680 | 1300 | bool e, | ||
1681 | 1301 | uint32_t pp, | ||
1682 | 1302 | uint32_t op, | ||
1683 | 1303 | uint32_t o60p, | ||
1684 | 1304 | uint32_t cs, | ||
1685 | 1305 | uint32_t land, | ||
1686 | 1306 | uint32_t oland, | ||
1687 | 1307 | uint32_t o60l) | ||
1688 | 1308 | : team_number(tc), | ||
1689 | 1309 | is_enemy(e), | ||
1690 | 1310 | players_power(pp), | ||
1691 | 1311 | old_players_power(op), | ||
1692 | 1312 | old60_players_power(o60p), | ||
1693 | 1313 | players_casualities(cs), | ||
1694 | 1314 | players_land(land), | ||
1695 | 1315 | old_players_land(oland), | ||
1696 | 1316 | old60_players_land(o60l) { | ||
1697 | 1317 | last_time_seen = kNever; | ||
1698 | 489 | } | 1318 | } |
1699 | 490 | 1319 | ||
1700 | 491 | // Inserting/updating data | 1320 | // Inserting/updating data |
1704 | 492 | void PlayersStrengths::add(Widelands::PlayerNumber pn, Widelands::TeamNumber tn, uint32_t pp) { | 1321 | // We keep information for |
1705 | 493 | if (all_stats.count(pn) == 0) { | 1322 | // - player strength / power |
1706 | 494 | all_stats.insert(std::pair<Widelands::PlayerNumber, PlayerStat>(pn, PlayerStat(tn, pp))); | 1323 | // - player casualties |
1707 | 1324 | // - player land | ||
1708 | 1325 | // We store actual values, but for some of them we store also | ||
1709 | 1326 | // - old = 15 mins ago | ||
1710 | 1327 | // - old60 = 60 mins ago | ||
1711 | 1328 | // e.g. players_power / old_players_power / old60_players_power | ||
1712 | 1329 | // we recieve also player and team numbers to figure out if we are enemies, or in the team | ||
1713 | 1330 | void PlayersStrengths::add(Widelands::PlayerNumber pn, | ||
1714 | 1331 | Widelands::PlayerNumber opn, | ||
1715 | 1332 | Widelands::TeamNumber mytn, | ||
1716 | 1333 | Widelands::TeamNumber pltn, | ||
1717 | 1334 | uint32_t pp, | ||
1718 | 1335 | uint32_t op, | ||
1719 | 1336 | uint32_t o60p, | ||
1720 | 1337 | uint32_t cs, | ||
1721 | 1338 | uint32_t land, | ||
1722 | 1339 | uint32_t oland, | ||
1723 | 1340 | uint32_t o60l) { | ||
1724 | 1341 | if (all_stats.count(opn) == 0) { | ||
1725 | 1342 | bool enemy = false; | ||
1726 | 1343 | if (pn == opn) { | ||
1727 | 1344 | ; | ||
1728 | 1345 | } else if (pltn == 0 || mytn == 0) { | ||
1729 | 1346 | enemy = true; | ||
1730 | 1347 | } else if (pltn != mytn) { | ||
1731 | 1348 | enemy = true; | ||
1732 | 1349 | } | ||
1733 | 1350 | this_player_number = pn; | ||
1734 | 1351 | all_stats.insert(std::make_pair( | ||
1735 | 1352 | opn, PlayerStat(pltn, enemy, pp, op, o60p, cs, land, oland, o60l))); | ||
1736 | 495 | } else { | 1353 | } else { |
1738 | 496 | all_stats[pn].players_power = pp; | 1354 | all_stats[opn].players_power = pp; |
1739 | 1355 | all_stats[opn].old_players_power = op; | ||
1740 | 1356 | all_stats[opn].old60_players_power = o60p; | ||
1741 | 1357 | all_stats[opn].players_casualities = cs; | ||
1742 | 1358 | all_stats[opn].players_land = land; | ||
1743 | 1359 | all_stats[opn].old_players_land = oland; | ||
1744 | 1360 | all_stats[opn].old60_players_land = oland; | ||
1745 | 497 | } | 1361 | } |
1746 | 498 | } | 1362 | } |
1747 | 499 | 1363 | ||
1748 | 1364 | // After statistics for team members are updated, this calculation is needed | ||
1749 | 500 | void PlayersStrengths::recalculate_team_power() { | 1365 | void PlayersStrengths::recalculate_team_power() { |
1750 | 501 | team_powers.clear(); | 1366 | team_powers.clear(); |
1751 | 502 | for (auto& item : all_stats) { | 1367 | for (auto& item : all_stats) { |
1752 | @@ -510,6 +1375,186 @@ | |||
1753 | 510 | } | 1375 | } |
1754 | 511 | } | 1376 | } |
1755 | 512 | 1377 | ||
1756 | 1378 | // This just goes over information about all enemies and where they were seen the last time | ||
1757 | 1379 | bool PlayersStrengths::any_enemy_seen_lately(const uint32_t gametime) { | ||
1758 | 1380 | for (auto& item : all_stats) { | ||
1759 | 1381 | if (item.second.is_enemy && player_seen_lately(item.first, gametime)) { | ||
1760 | 1382 | return true; | ||
1761 | 1383 | } | ||
1762 | 1384 | } | ||
1763 | 1385 | return false; | ||
1764 | 1386 | } | ||
1765 | 1387 | |||
1766 | 1388 | // Returns count of nearby enemies | ||
1767 | 1389 | uint8_t PlayersStrengths::enemies_seen_lately_count(const uint32_t gametime) { | ||
1768 | 1390 | uint8_t count = 0; | ||
1769 | 1391 | for (auto& item : all_stats) { | ||
1770 | 1392 | if (item.second.is_enemy && player_seen_lately(item.first, gametime)) { | ||
1771 | 1393 | count += 1; | ||
1772 | 1394 | } | ||
1773 | 1395 | } | ||
1774 | 1396 | return count; | ||
1775 | 1397 | } | ||
1776 | 1398 | |||
1777 | 1399 | // When we see enemy, we use this to store the time | ||
1778 | 1400 | void PlayersStrengths::set_last_time_seen(const uint32_t seentime, Widelands::PlayerNumber pn) { | ||
1779 | 1401 | if (all_stats.count(pn) == 0) { | ||
1780 | 1402 | return; | ||
1781 | 1403 | } | ||
1782 | 1404 | all_stats[pn].last_time_seen = seentime; | ||
1783 | 1405 | } | ||
1784 | 1406 | |||
1785 | 1407 | bool PlayersStrengths::get_is_enemy(Widelands::PlayerNumber pn) { | ||
1786 | 1408 | if (all_stats.count(pn) == 0) { | ||
1787 | 1409 | // Should happen only rarely so we print a warning here | ||
1788 | 1410 | log("%d: WARNING: player has no statistics yet\n", this_player_number); | ||
1789 | 1411 | return false; | ||
1790 | 1412 | } | ||
1791 | 1413 | return all_stats[pn].is_enemy; | ||
1792 | 1414 | } | ||
1793 | 1415 | |||
1794 | 1416 | // Was the player seen less then 2 minutes ago | ||
1795 | 1417 | bool PlayersStrengths::player_seen_lately(Widelands::PlayerNumber pn, const uint32_t gametime) { | ||
1796 | 1418 | if (all_stats.count(pn) == 0) { | ||
1797 | 1419 | // Should happen only rarely so we print a warning here | ||
1798 | 1420 | log("%d: WARNING: player has no statistics yet\n", this_player_number); | ||
1799 | 1421 | return false; | ||
1800 | 1422 | } | ||
1801 | 1423 | if (all_stats[pn].last_time_seen == kNever) { | ||
1802 | 1424 | return false; | ||
1803 | 1425 | } | ||
1804 | 1426 | if (all_stats[pn].last_time_seen + (2U * 60U * 1000U) > gametime) { | ||
1805 | 1427 | return true; | ||
1806 | 1428 | } | ||
1807 | 1429 | return false; | ||
1808 | 1430 | } | ||
1809 | 1431 | |||
1810 | 1432 | // This is the strength of a player | ||
1811 | 1433 | uint32_t PlayersStrengths::get_player_power(Widelands::PlayerNumber pn) { | ||
1812 | 1434 | if (all_stats.count(pn) > 0) { | ||
1813 | 1435 | return all_stats[pn].players_power; | ||
1814 | 1436 | }; | ||
1815 | 1437 | return 0; | ||
1816 | 1438 | } | ||
1817 | 1439 | |||
1818 | 1440 | // This is the land size owned by player | ||
1819 | 1441 | uint32_t PlayersStrengths::get_player_land(Widelands::PlayerNumber pn) { | ||
1820 | 1442 | if (all_stats.count(pn) > 0) { | ||
1821 | 1443 | return all_stats[pn].players_land; | ||
1822 | 1444 | }; | ||
1823 | 1445 | return 0; | ||
1824 | 1446 | } | ||
1825 | 1447 | |||
1826 | 1448 | // Calculates the strength of the enemies seen within the last 2 minutes | ||
1827 | 1449 | uint32_t PlayersStrengths::get_visible_enemies_power(const uint32_t gametime) { | ||
1828 | 1450 | uint32_t pw = 0; | ||
1829 | 1451 | for (auto& item : all_stats) { | ||
1830 | 1452 | if (get_is_enemy(item.first) && player_seen_lately(item.first, gametime)) { | ||
1831 | 1453 | pw += item.second.players_power; | ||
1832 | 1454 | } | ||
1833 | 1455 | } | ||
1834 | 1456 | return pw; | ||
1835 | 1457 | } | ||
1836 | 1458 | |||
1837 | 1459 | uint32_t PlayersStrengths::get_enemies_average_power() { | ||
1838 | 1460 | uint32_t sum = 0; | ||
1839 | 1461 | uint8_t count = 0; | ||
1840 | 1462 | for (auto& item : all_stats) { | ||
1841 | 1463 | if (get_is_enemy(item.first)) { | ||
1842 | 1464 | sum += item.second.players_power; | ||
1843 | 1465 | ++count; | ||
1844 | 1466 | } | ||
1845 | 1467 | } | ||
1846 | 1468 | if (count > 0) { | ||
1847 | 1469 | return sum / count; | ||
1848 | 1470 | } | ||
1849 | 1471 | return 0; | ||
1850 | 1472 | } | ||
1851 | 1473 | |||
1852 | 1474 | uint32_t PlayersStrengths::get_enemies_average_land() { | ||
1853 | 1475 | uint32_t sum = 0; | ||
1854 | 1476 | uint8_t count = 0; | ||
1855 | 1477 | for (auto& item : all_stats) { | ||
1856 | 1478 | if (get_is_enemy(item.first)) { | ||
1857 | 1479 | sum += item.second.players_land; | ||
1858 | 1480 | ++count; | ||
1859 | 1481 | } | ||
1860 | 1482 | } | ||
1861 | 1483 | if (count > 0) { | ||
1862 | 1484 | return sum / count; | ||
1863 | 1485 | } | ||
1864 | 1486 | return 0; | ||
1865 | 1487 | } | ||
1866 | 1488 | |||
1867 | 1489 | // Strength of stronger player | ||
1868 | 1490 | uint32_t PlayersStrengths::get_enemies_max_power() { | ||
1869 | 1491 | uint32_t power = 0; | ||
1870 | 1492 | for (auto& item : all_stats) { | ||
1871 | 1493 | if (get_is_enemy(item.first)) { | ||
1872 | 1494 | power = std::max<uint32_t>(power, item.second.players_power); | ||
1873 | 1495 | } | ||
1874 | 1496 | } | ||
1875 | 1497 | return power; | ||
1876 | 1498 | } | ||
1877 | 1499 | |||
1878 | 1500 | uint32_t PlayersStrengths::get_enemies_max_land() { | ||
1879 | 1501 | uint32_t land = 0; | ||
1880 | 1502 | for (auto& item : all_stats) { | ||
1881 | 1503 | if (get_is_enemy(item.first)) { | ||
1882 | 1504 | land = std::max<uint32_t>(land, item.second.players_land); | ||
1883 | 1505 | } | ||
1884 | 1506 | } | ||
1885 | 1507 | return land; | ||
1886 | 1508 | } | ||
1887 | 1509 | |||
1888 | 1510 | uint32_t PlayersStrengths::get_old_player_power(Widelands::PlayerNumber pn) { | ||
1889 | 1511 | if (all_stats.count(pn) > 0) { | ||
1890 | 1512 | return all_stats[pn].old_players_power; | ||
1891 | 1513 | } | ||
1892 | 1514 | return 0; | ||
1893 | 1515 | } | ||
1894 | 1516 | |||
1895 | 1517 | uint32_t PlayersStrengths::get_old60_player_power(Widelands::PlayerNumber pn) { | ||
1896 | 1518 | if (all_stats.count(pn) > 0) { | ||
1897 | 1519 | return all_stats[pn].old60_players_power; | ||
1898 | 1520 | } | ||
1899 | 1521 | return 0; | ||
1900 | 1522 | } | ||
1901 | 1523 | |||
1902 | 1524 | uint32_t PlayersStrengths::get_old_player_land(Widelands::PlayerNumber pn) { | ||
1903 | 1525 | if (all_stats.count(pn) == 0) { | ||
1904 | 1526 | log(" %d: Players statistics are still empty\n", pn); | ||
1905 | 1527 | return 0; | ||
1906 | 1528 | } | ||
1907 | 1529 | return all_stats[pn].old_players_land; | ||
1908 | 1530 | } | ||
1909 | 1531 | |||
1910 | 1532 | uint32_t PlayersStrengths::get_old60_player_land(Widelands::PlayerNumber pn) { | ||
1911 | 1533 | if (all_stats.count(pn) == 0) { | ||
1912 | 1534 | log(" %d: Players statistics are still empty\n", pn); | ||
1913 | 1535 | return 0; | ||
1914 | 1536 | } | ||
1915 | 1537 | return all_stats[pn].old60_players_land; | ||
1916 | 1538 | } | ||
1917 | 1539 | |||
1918 | 1540 | uint32_t PlayersStrengths::get_old_visible_enemies_power(const uint32_t gametime) { | ||
1919 | 1541 | uint32_t pw = 0; | ||
1920 | 1542 | for (auto& item : all_stats) { | ||
1921 | 1543 | if (get_is_enemy(item.first) && player_seen_lately(item.first, gametime)) { | ||
1922 | 1544 | pw += item.second.old_players_power; | ||
1923 | 1545 | } | ||
1924 | 1546 | } | ||
1925 | 1547 | return pw; | ||
1926 | 1548 | } | ||
1927 | 1549 | |||
1928 | 1550 | // This is casualities of player | ||
1929 | 1551 | uint32_t PlayersStrengths::get_player_casualities(Widelands::PlayerNumber pn) { | ||
1930 | 1552 | if (all_stats.count(pn) > 0) { | ||
1931 | 1553 | return all_stats[pn].players_casualities; | ||
1932 | 1554 | } | ||
1933 | 1555 | return 0; | ||
1934 | 1556 | } | ||
1935 | 1557 | |||
1936 | 513 | // This is strength of player plus third of strength of other members of his team | 1558 | // This is strength of player plus third of strength of other members of his team |
1937 | 514 | uint32_t PlayersStrengths::get_modified_player_power(Widelands::PlayerNumber pn) { | 1559 | uint32_t PlayersStrengths::get_modified_player_power(Widelands::PlayerNumber pn) { |
1938 | 515 | uint32_t result = 0; | 1560 | uint32_t result = 0; |
1939 | @@ -517,19 +1562,24 @@ | |||
1940 | 517 | if (all_stats.count(pn) > 0) { | 1562 | if (all_stats.count(pn) > 0) { |
1941 | 518 | result = all_stats[pn].players_power; | 1563 | result = all_stats[pn].players_power; |
1942 | 519 | team = all_stats[pn].team_number; | 1564 | team = all_stats[pn].team_number; |
1944 | 520 | }; | 1565 | } |
1945 | 521 | if (team > 0 && team_powers.count(team) > 0) { | 1566 | if (team > 0 && team_powers.count(team) > 0) { |
1946 | 522 | result = result + (team_powers[team] - result) / 3; | 1567 | result = result + (team_powers[team] - result) / 3; |
1948 | 523 | }; | 1568 | } |
1949 | 524 | return result; | 1569 | return result; |
1950 | 525 | } | 1570 | } |
1951 | 526 | 1571 | ||
1952 | 1572 | // Are the player in the same team | ||
1953 | 527 | bool PlayersStrengths::players_in_same_team(Widelands::PlayerNumber pl1, | 1573 | bool PlayersStrengths::players_in_same_team(Widelands::PlayerNumber pl1, |
1954 | 528 | Widelands::PlayerNumber pl2) { | 1574 | Widelands::PlayerNumber pl2) { |
1956 | 529 | if (all_stats.count(pl1) > 0 && all_stats.count(pl2) > 0 && pl1 != pl2) { | 1575 | assert(all_stats.count(pl1) > 0); |
1957 | 1576 | assert(all_stats.count(pl2) > 0); | ||
1958 | 1577 | if (pl1 == pl2) { | ||
1959 | 1578 | return false; | ||
1960 | 1579 | } else if (all_stats[pl1].team_number > 0 && | ||
1961 | 1580 | all_stats[pl1].team_number == all_stats[pl2].team_number) { | ||
1962 | 530 | // team number 0 = no team | 1581 | // team number 0 = no team |
1965 | 531 | return all_stats[pl1].team_number > 0 && | 1582 | return true; |
1964 | 532 | all_stats[pl1].team_number == all_stats[pl2].team_number; | ||
1966 | 533 | } else { | 1583 | } else { |
1967 | 534 | return false; | 1584 | return false; |
1968 | 535 | } | 1585 | } |
1969 | @@ -551,4 +1601,19 @@ | |||
1970 | 551 | return my_strength > strongest_opponent_strength + 50; | 1601 | return my_strength > strongest_opponent_strength + 50; |
1971 | 552 | } | 1602 | } |
1972 | 553 | 1603 | ||
1974 | 554 | } // namespace WIdelands | 1604 | // Update_time is used to prevent too frequent updates of statistics |
1975 | 1605 | void PlayersStrengths::set_update_time(const uint32_t gametime) { | ||
1976 | 1606 | update_time = gametime; | ||
1977 | 1607 | } | ||
1978 | 1608 | |||
1979 | 1609 | uint32_t PlayersStrengths::get_update_time() { | ||
1980 | 1610 | return update_time; | ||
1981 | 1611 | } | ||
1982 | 1612 | |||
1983 | 1613 | ProductionSiteObserver::ProductionSiteObserver() | ||
1984 | 1614 | : no_resources_since(kNever), | ||
1985 | 1615 | upgrade_pending(false), | ||
1986 | 1616 | dismantle_pending_since(kNever) { | ||
1987 | 1617 | } | ||
1988 | 1618 | |||
1989 | 1619 | } // namespace Widelands | ||
1990 | 555 | 1620 | ||
1991 | === modified file 'src/ai/ai_help_structs.h' | |||
1992 | --- src/ai/ai_help_structs.h 2017-06-24 08:47:46 +0000 | |||
1993 | +++ src/ai/ai_help_structs.h 2017-07-03 17:39:38 +0000 | |||
1994 | @@ -21,6 +21,7 @@ | |||
1995 | 21 | #define WL_AI_AI_HELP_STRUCTS_H | 21 | #define WL_AI_AI_HELP_STRUCTS_H |
1996 | 22 | 22 | ||
1997 | 23 | #include <list> | 23 | #include <list> |
1998 | 24 | #include <queue> | ||
1999 | 24 | #include <unordered_set> | 25 | #include <unordered_set> |
2000 | 25 | 26 | ||
2001 | 26 | #include "ai/ai_hints.h" | 27 | #include "ai/ai_hints.h" |
2002 | @@ -43,6 +44,8 @@ | |||
2003 | 43 | 44 | ||
2004 | 44 | enum class ExtendedBool : uint8_t { kUnset, kTrue, kFalse }; | 45 | enum class ExtendedBool : uint8_t { kUnset, kTrue, kFalse }; |
2005 | 45 | 46 | ||
2006 | 47 | enum class MutatingIntensity : uint8_t { kNo, kNormal, kAgressive }; | ||
2007 | 48 | |||
2008 | 46 | enum class BuildingNecessity : uint8_t { | 49 | enum class BuildingNecessity : uint8_t { |
2009 | 47 | kForced, | 50 | kForced, |
2010 | 48 | kNeeded, | 51 | kNeeded, |
2011 | @@ -54,6 +57,33 @@ | |||
2012 | 54 | kForbidden | 57 | kForbidden |
2013 | 55 | }; | 58 | }; |
2014 | 56 | 59 | ||
2015 | 60 | // A building type can have no, one or multiple of these attributes | ||
2016 | 61 | enum class BuildingAttribute : uint8_t { | ||
2017 | 62 | kBakery, | ||
2018 | 63 | kRanger, | ||
2019 | 64 | kBuildable, | ||
2020 | 65 | kLumberjack, | ||
2021 | 66 | kPort, | ||
2022 | 67 | kNeedsRocks, | ||
2023 | 68 | kWell, | ||
2024 | 69 | kNeedsCoast, | ||
2025 | 70 | kHunter, | ||
2026 | 71 | kFisher, | ||
2027 | 72 | kShipyard, | ||
2028 | 73 | kBarracks, | ||
2029 | 74 | kSpaceConsumer, | ||
2030 | 75 | kRecruitment, | ||
2031 | 76 | kBuildingMatProducer, | ||
2032 | 77 | kUpgradeSubstitutes, | ||
2033 | 78 | kUpgradeExtends, | ||
2034 | 79 | kLogRefiner, | ||
2035 | 80 | kIronMine | ||
2036 | 81 | }; | ||
2037 | 82 | |||
2038 | 83 | enum class AiType : uint8_t { kVeryWeak, kWeak, kNormal }; | ||
2039 | 84 | |||
2040 | 85 | enum class ExpansionMode : uint8_t { kResources = 0, kSpace = 1, kEconomy = 2, kBoth = 3 }; | ||
2041 | 86 | |||
2042 | 57 | enum class AiModeBuildings : uint8_t { kAnotherAllowed, kOnLimit, kLimitExceeded }; | 87 | enum class AiModeBuildings : uint8_t { kAnotherAllowed, kOnLimit, kLimitExceeded }; |
2043 | 58 | 88 | ||
2044 | 59 | enum class SchedulerTaskId : uint8_t { | 89 | enum class SchedulerTaskId : uint8_t { |
2045 | @@ -74,9 +104,28 @@ | |||
2046 | 74 | kCheckTrainingsites, | 104 | kCheckTrainingsites, |
2047 | 75 | kCountMilitaryVacant, | 105 | kCountMilitaryVacant, |
2048 | 76 | kCheckEnemySites, | 106 | kCheckEnemySites, |
2049 | 107 | kManagementUpdate, | ||
2050 | 108 | kUpdateStats, | ||
2051 | 77 | kUnset | 109 | kUnset |
2052 | 78 | }; | 110 | }; |
2053 | 79 | 111 | ||
2054 | 112 | // This is a simplification of a curve, to avoid repeated calculation | ||
2055 | 113 | const std::vector<std::vector<int8_t>> neuron_curves = { | ||
2056 | 114 | {0, 5, 10, 15, 20, 25, 30, 35, 40, 45, 50, 55, 60, 65, 70, 75, 80, 85, 90, 95, 100}, | ||
2057 | 115 | {0, 0, 1, 2, 4, 6, 9, 12, 16, 20, 25, 30, 36, 42, 49, 56, 64, 72, 81, 90, 100}, | ||
2058 | 116 | {0, 17, 25, 32, 38, 44, 49, 53, 58, 62, 66, 70, 74, 78, 81, 84, 88, 91, 94, 97, 100}, | ||
2059 | 117 | }; | ||
2060 | 118 | |||
2061 | 119 | constexpr int kMagicNumbersSize = 150; | ||
2062 | 120 | constexpr int kNeuronPoolSize = 80; | ||
2063 | 121 | constexpr int kFNeuronPoolSize = 60; | ||
2064 | 122 | constexpr int kFNeuronBitSize = 32; | ||
2065 | 123 | constexpr int kMutationRatePosition = 42; | ||
2066 | 124 | // TODO(tiborb): this should be replaced by command line switch | ||
2067 | 125 | constexpr bool kAITrainingMode = false; | ||
2068 | 126 | |||
2069 | 127 | constexpr uint32_t kNever = std::numeric_limits<uint32_t>::max(); | ||
2070 | 128 | |||
2071 | 80 | struct CheckStepRoadAI { | 129 | struct CheckStepRoadAI { |
2072 | 81 | CheckStepRoadAI(Player* const pl, uint8_t const mc, bool const oe); | 130 | CheckStepRoadAI(Player* const pl, uint8_t const mc, bool const oe); |
2073 | 82 | 131 | ||
2074 | @@ -112,17 +161,14 @@ | |||
2075 | 112 | Game& game; | 161 | Game& game; |
2076 | 113 | }; | 162 | }; |
2077 | 114 | 163 | ||
2083 | 115 | // When looking for unowned terrain to acquire, we are actually | 164 | // We need to count walkable fields owned by enemy |
2084 | 116 | // only interested in fields we can walk on. | 165 | struct FindEnemyNodeWalkable { |
2085 | 117 | // Fields should either be completely unowned or owned by an opposing player_ | 166 | FindEnemyNodeWalkable(Player* p, Game& g); |
2081 | 118 | struct FindNodeUnowned { | ||
2082 | 119 | FindNodeUnowned(Player* p, Game& g, bool oe = false); | ||
2086 | 120 | 167 | ||
2087 | 121 | bool accept(const Map&, const FCoords& fc) const; | 168 | bool accept(const Map&, const FCoords& fc) const; |
2088 | 122 | 169 | ||
2089 | 123 | Player* player; | 170 | Player* player; |
2090 | 124 | Game& game; | 171 | Game& game; |
2091 | 125 | bool only_enemies; | ||
2092 | 126 | }; | 172 | }; |
2093 | 127 | 173 | ||
2094 | 128 | // Sometimes we need to know how many nodes our allies owns | 174 | // Sometimes we need to know how many nodes our allies owns |
2095 | @@ -140,7 +186,19 @@ | |||
2096 | 140 | // pay speciall attention to fields where mines can be built. | 186 | // pay speciall attention to fields where mines can be built. |
2097 | 141 | // Fields should be completely unowned | 187 | // Fields should be completely unowned |
2098 | 142 | struct FindNodeUnownedMineable { | 188 | struct FindNodeUnownedMineable { |
2100 | 143 | FindNodeUnownedMineable(Player* p, Game& g); | 189 | FindNodeUnownedMineable(Player* p, Game& g, int32_t t = INVALID_INDEX); |
2101 | 190 | |||
2102 | 191 | bool accept(const Map&, const FCoords& fc) const; | ||
2103 | 192 | |||
2104 | 193 | Player* player; | ||
2105 | 194 | Game& game; | ||
2106 | 195 | int32_t ore_type; | ||
2107 | 196 | }; | ||
2108 | 197 | |||
2109 | 198 | // When looking for unowned terrain to acquire, we must | ||
2110 | 199 | // consider if any buildings can be built on unowned land. | ||
2111 | 200 | struct FindNodeUnownedBuildable { | ||
2112 | 201 | FindNodeUnownedBuildable(Player* p, Game& g); | ||
2113 | 144 | 202 | ||
2114 | 145 | bool accept(const Map&, const FCoords& fc) const; | 203 | bool accept(const Map&, const FCoords& fc) const; |
2115 | 146 | 204 | ||
2116 | @@ -216,6 +274,18 @@ | |||
2117 | 216 | int32_t distance; | 274 | int32_t distance; |
2118 | 217 | }; | 275 | }; |
2119 | 218 | 276 | ||
2120 | 277 | struct EventTimeQueue { | ||
2121 | 278 | EventTimeQueue(); | ||
2122 | 279 | |||
2123 | 280 | void push(uint32_t); | ||
2124 | 281 | uint32_t count(uint32_t); | ||
2125 | 282 | void strip_old(uint32_t); | ||
2126 | 283 | |||
2127 | 284 | private: | ||
2128 | 285 | uint32_t duration_ = 20 * 60 * 1000; | ||
2129 | 286 | std::queue<uint32_t> queue; | ||
2130 | 287 | }; | ||
2131 | 288 | |||
2132 | 219 | struct WalkableSpot { | 289 | struct WalkableSpot { |
2133 | 220 | Coords coords; | 290 | Coords coords; |
2134 | 221 | bool has_flag; | 291 | bool has_flag; |
2135 | @@ -238,11 +308,17 @@ | |||
2136 | 238 | 308 | ||
2137 | 239 | bool preferred; | 309 | bool preferred; |
2138 | 240 | bool enemy_nearby; | 310 | bool enemy_nearby; |
2139 | 311 | bool enemy_accessible_; | ||
2140 | 241 | 312 | ||
2142 | 242 | uint8_t unowned_land_nearby; | 313 | bool enemy_wh_nearby; |
2143 | 314 | uint16_t unowned_land_nearby; | ||
2144 | 315 | uint16_t enemy_owned_land_nearby; | ||
2145 | 316 | uint16_t unowned_buildable_spots_nearby; | ||
2146 | 317 | uint16_t nearest_buildable_spot_nearby; | ||
2147 | 243 | // to identify that field is too close to border and no production building should be built there | 318 | // to identify that field is too close to border and no production building should be built there |
2148 | 244 | bool near_border; | 319 | bool near_border; |
2150 | 245 | uint8_t unowned_mines_spots_nearby; | 320 | uint16_t unowned_mines_spots_nearby; |
2151 | 321 | uint16_t unowned_iron_mines_nearby; | ||
2152 | 246 | uint8_t trees_nearby; | 322 | uint8_t trees_nearby; |
2153 | 247 | uint8_t rocks_nearby; | 323 | uint8_t rocks_nearby; |
2154 | 248 | int16_t water_nearby; | 324 | int16_t water_nearby; |
2155 | @@ -264,22 +340,29 @@ | |||
2156 | 264 | // are construction sites that will change this once they are built | 340 | // are construction sites that will change this once they are built |
2157 | 265 | int16_t military_in_constr_nearby; | 341 | int16_t military_in_constr_nearby; |
2158 | 266 | // actual count of soldiers in nearby buldings | 342 | // actual count of soldiers in nearby buldings |
2160 | 267 | int16_t area_military_presence; | 343 | int16_t own_military_presence; |
2161 | 344 | int16_t enemy_military_presence; | ||
2162 | 345 | int16_t enemy_military_sites; // Including unfinished | ||
2163 | 346 | int16_t ally_military_presence; | ||
2164 | 268 | // stationed (manned) military buildings nearby | 347 | // stationed (manned) military buildings nearby |
2165 | 269 | int16_t military_stationed; | 348 | int16_t military_stationed; |
2166 | 270 | // stationed (manned) military buildings nearby | ||
2167 | 271 | // unconnected buildings nearby | 349 | // unconnected buildings nearby |
2168 | 272 | bool unconnected_nearby; | 350 | bool unconnected_nearby; |
2169 | 273 | int16_t military_unstationed; | 351 | int16_t military_unstationed; |
2171 | 274 | bool is_portspace; | 352 | int16_t own_non_military_nearby; |
2172 | 353 | bool defense_msite_allowed; | ||
2173 | 354 | Widelands::ExtendedBool is_portspace; | ||
2174 | 275 | bool port_nearby; // to increase priority if a port is nearby, | 355 | bool port_nearby; // to increase priority if a port is nearby, |
2175 | 276 | // especially for new colonies | 356 | // especially for new colonies |
2176 | 277 | Widelands::ExtendedBool portspace_nearby; // prefer military buildings closer to the portspace | 357 | Widelands::ExtendedBool portspace_nearby; // prefer military buildings closer to the portspace |
2177 | 278 | int32_t max_buildcap_nearby; | 358 | int32_t max_buildcap_nearby; |
2181 | 279 | // it is not necessary to check resources (stones, fish...) too frequently as they do not change | 359 | // It is not necessary to check resources (stones, fish...) too frequently as they do not change |
2182 | 280 | // fast | 360 | // fast. This stores the time of the last check. |
2180 | 281 | // this stores time of last check | ||
2183 | 282 | uint32_t last_resources_check_time; | 361 | uint32_t last_resources_check_time; |
2184 | 362 | int32_t military_score_; | ||
2185 | 363 | bool inland; | ||
2186 | 364 | uint16_t local_soldier_capacity; | ||
2187 | 365 | bool is_militarysite; | ||
2188 | 283 | 366 | ||
2189 | 284 | std::vector<uint8_t> consumers_nearby; | 367 | std::vector<uint8_t> consumers_nearby; |
2190 | 285 | std::vector<uint8_t> producers_nearby; | 368 | std::vector<uint8_t> producers_nearby; |
2191 | @@ -322,33 +405,27 @@ | |||
2192 | 322 | Widelands::AiModeBuildings aimode_limit_status(); | 405 | Widelands::AiModeBuildings aimode_limit_status(); |
2193 | 323 | bool buildable(Widelands::Player& p); | 406 | bool buildable(Widelands::Player& p); |
2194 | 324 | 407 | ||
2195 | 408 | // Convenience functions for is_what | ||
2196 | 409 | bool is(BuildingAttribute) const; | ||
2197 | 410 | void set_is(BuildingAttribute); | ||
2198 | 411 | void unset_is(BuildingAttribute); | ||
2199 | 412 | |||
2200 | 325 | char const* name; | 413 | char const* name; |
2201 | 326 | Widelands::DescriptionIndex id; | 414 | Widelands::DescriptionIndex id; |
2202 | 327 | Widelands::BuildingDescr const* desc; | 415 | Widelands::BuildingDescr const* desc; |
2203 | 328 | 416 | ||
2204 | 329 | Type type; | 417 | Type type; |
2205 | 330 | 418 | ||
2206 | 331 | bool plants_trees; | ||
2207 | 332 | bool recruitment; // is "producing" workers? | ||
2208 | 333 | Widelands::BuildingNecessity new_building; | 419 | Widelands::BuildingNecessity new_building; |
2209 | 334 | uint32_t new_building_overdue; | 420 | uint32_t new_building_overdue; |
2210 | 335 | int32_t primary_priority; | 421 | int32_t primary_priority; |
2221 | 336 | bool is_buildable; | 422 | |
2212 | 337 | bool need_trees; // lumberjack = true | ||
2213 | 338 | bool need_rocks; // quarry = true | ||
2214 | 339 | bool mines_water; // wells | ||
2215 | 340 | bool need_water; // fisher, fish_breeder = true | ||
2216 | 341 | bool is_hunter; // need to identify hunters | ||
2217 | 342 | bool is_fisher; // need to identify fishers | ||
2218 | 343 | bool is_port; | ||
2219 | 344 | bool is_shipyard; | ||
2220 | 345 | bool space_consumer; // farm, vineyard... = true | ||
2222 | 346 | bool expansion_type; // military building used that can be used to control area | 423 | bool expansion_type; // military building used that can be used to control area |
2223 | 347 | bool fighting_type; // military building built near enemies | 424 | bool fighting_type; // military building built near enemies |
2224 | 348 | bool mountain_conqueror; // military building built near mountains | 425 | bool mountain_conqueror; // military building built near mountains |
2225 | 349 | uint32_t prohibited_till; // do not build before (ms) | 426 | uint32_t prohibited_till; // do not build before (ms) |
2226 | 350 | uint32_t forced_after; // do not wait until ware is needed | 427 | uint32_t forced_after; // do not wait until ware is needed |
2228 | 351 | TrainingSiteType trainingsite_type; | 428 | uint8_t max_trainingsites_proportion; |
2229 | 352 | 429 | ||
2230 | 353 | uint16_t unconnected_count; // to any warehouse (count of such buildings) | 430 | uint16_t unconnected_count; // to any warehouse (count of such buildings) |
2231 | 354 | 431 | ||
2232 | @@ -358,16 +435,9 @@ | |||
2233 | 358 | 435 | ||
2234 | 359 | std::vector<Widelands::DescriptionIndex> inputs; | 436 | std::vector<Widelands::DescriptionIndex> inputs; |
2235 | 360 | std::vector<Widelands::DescriptionIndex> outputs; | 437 | std::vector<Widelands::DescriptionIndex> outputs; |
2236 | 438 | std::vector<Widelands::DescriptionIndex> positions; | ||
2237 | 361 | std::vector<Widelands::DescriptionIndex> critical_building_material; | 439 | std::vector<Widelands::DescriptionIndex> critical_building_material; |
2238 | 362 | 440 | ||
2239 | 363 | bool produces_building_material; | ||
2240 | 364 | |||
2241 | 365 | // an enhancement to this building: | ||
2242 | 366 | // produces all wares as current building, and perhaps more | ||
2243 | 367 | bool upgrade_substitutes; | ||
2244 | 368 | // produces some additional wares | ||
2245 | 369 | bool upgrade_extends; | ||
2246 | 370 | |||
2247 | 371 | // It seems that fish and meat are subsitutes (for trainingsites), so | 441 | // It seems that fish and meat are subsitutes (for trainingsites), so |
2248 | 372 | // when testing if a trainingsite is supplied enough | 442 | // when testing if a trainingsite is supplied enough |
2249 | 373 | // we count the wares together | 443 | // we count the wares together |
2250 | @@ -388,7 +458,7 @@ | |||
2251 | 388 | int32_t cnt_upgrade_pending; // number of buildings that are to be upgraded | 458 | int32_t cnt_upgrade_pending; // number of buildings that are to be upgraded |
2252 | 389 | 459 | ||
2253 | 390 | // used to track amount of wares produced by building | 460 | // used to track amount of wares produced by building |
2255 | 391 | uint32_t stocklevel; | 461 | uint32_t stocklevel_count; |
2256 | 392 | uint32_t stocklevel_time; // time when stocklevel_ was last time recalculated | 462 | uint32_t stocklevel_time; // time when stocklevel_ was last time recalculated |
2257 | 393 | uint32_t last_dismantle_time; | 463 | uint32_t last_dismantle_time; |
2258 | 394 | uint32_t construction_decision_time; | 464 | uint32_t construction_decision_time; |
2259 | @@ -397,25 +467,27 @@ | |||
2260 | 397 | uint32_t unoccupied_count; | 467 | uint32_t unoccupied_count; |
2261 | 398 | 468 | ||
2262 | 399 | bool build_material_shortage; | 469 | bool build_material_shortage; |
2263 | 470 | |||
2264 | 471 | private: | ||
2265 | 472 | std::set<BuildingAttribute> is_what; | ||
2266 | 400 | }; | 473 | }; |
2267 | 401 | 474 | ||
2268 | 402 | struct ProductionSiteObserver { | 475 | struct ProductionSiteObserver { |
2269 | 476 | ProductionSiteObserver(); | ||
2270 | 403 | Widelands::ProductionSite* site; | 477 | Widelands::ProductionSite* site; |
2271 | 404 | uint32_t built_time; | 478 | uint32_t built_time; |
2272 | 405 | uint32_t unoccupied_till; | 479 | uint32_t unoccupied_till; |
2273 | 406 | uint8_t stats_zero; | ||
2274 | 407 | uint32_t no_resources_since; | 480 | uint32_t no_resources_since; |
2275 | 408 | bool upgrade_pending; | 481 | bool upgrade_pending; |
2276 | 482 | uint32_t dismantle_pending_since; | ||
2277 | 409 | BuildingObserver* bo; | 483 | BuildingObserver* bo; |
2278 | 410 | }; | 484 | }; |
2279 | 411 | 485 | ||
2280 | 412 | struct MilitarySiteObserver { | 486 | struct MilitarySiteObserver { |
2281 | 413 | Widelands::MilitarySite* site; | 487 | Widelands::MilitarySite* site; |
2282 | 414 | BuildingObserver* bo; | 488 | BuildingObserver* bo; |
2287 | 415 | uint8_t checks; | 489 | uint16_t understaffed; |
2288 | 416 | // when considering attack most military sites are inside territory and should be skipped during | 490 | uint32_t last_change; // to prevent switching the occupancy policy too fast |
2285 | 417 | // evaluation | ||
2286 | 418 | bool enemies_nearby; | ||
2289 | 419 | uint32_t built_time; | 491 | uint32_t built_time; |
2290 | 420 | }; | 492 | }; |
2291 | 421 | 493 | ||
2292 | @@ -457,13 +529,15 @@ | |||
2293 | 457 | 529 | ||
2294 | 458 | bool is_warehouse; | 530 | bool is_warehouse; |
2295 | 459 | int32_t attack_soldiers_strength; | 531 | int32_t attack_soldiers_strength; |
2296 | 532 | int32_t attack_soldiers_competency; | ||
2297 | 460 | int32_t defenders_strength; | 533 | int32_t defenders_strength; |
2298 | 461 | uint8_t stationed_soldiers; | 534 | uint8_t stationed_soldiers; |
2300 | 462 | uint32_t last_time_attackable; | 535 | uint32_t last_time_seen; |
2301 | 463 | uint32_t last_tested; | 536 | uint32_t last_tested; |
2302 | 464 | int16_t score; | 537 | int16_t score; |
2303 | 465 | Widelands::ExtendedBool mines_nearby; | 538 | Widelands::ExtendedBool mines_nearby; |
2305 | 466 | int16_t no_attack_counter; | 539 | uint32_t last_time_attacked; |
2306 | 540 | uint32_t attack_counter; | ||
2307 | 467 | }; | 541 | }; |
2308 | 468 | 542 | ||
2309 | 469 | // as all mines have 3 levels, AI does not know total count of mines per mined material | 543 | // as all mines have 3 levels, AI does not know total count of mines per mined material |
2310 | @@ -475,6 +549,122 @@ | |||
2311 | 475 | 549 | ||
2312 | 476 | uint16_t in_construction; | 550 | uint16_t in_construction; |
2313 | 477 | uint16_t finished; | 551 | uint16_t finished; |
2314 | 552 | bool is_critical; | ||
2315 | 553 | uint16_t unoccupied; | ||
2316 | 554 | }; | ||
2317 | 555 | |||
2318 | 556 | constexpr int kNeuronWeightLimit = 100; | ||
2319 | 557 | constexpr size_t kNeuronMaxPosition = 20; | ||
2320 | 558 | constexpr size_t kSecondParentProbability = 50; | ||
2321 | 559 | |||
2322 | 560 | // A bunch of parameters used for trainig AI (for calculation of fitness function result) | ||
2323 | 561 | constexpr int16_t kCurrentLandDivider = 2; | ||
2324 | 562 | constexpr int16_t kLandDeltaMultiplier = 1; | ||
2325 | 563 | constexpr int16_t kBonus = 1000; | ||
2326 | 564 | constexpr int16_t kAttackersMultiplier = 1; | ||
2327 | 565 | constexpr int16_t kAttackBonus = 100; | ||
2328 | 566 | constexpr int16_t kTrainedSoldiersScore = 250; | ||
2329 | 567 | constexpr int16_t kConqueredWhBonus = 500; | ||
2330 | 568 | |||
2331 | 569 | struct Neuron { | ||
2332 | 570 | static int clip_weight_to_range(int w) { | ||
2333 | 571 | assert(w < 125); | ||
2334 | 572 | assert(w > -125); | ||
2335 | 573 | return std::max(-kNeuronWeightLimit, std::min(kNeuronWeightLimit, w)); | ||
2336 | 574 | } | ||
2337 | 575 | |||
2338 | 576 | Neuron(int8_t, uint8_t, uint16_t); | ||
2339 | 577 | void recalculate(); | ||
2340 | 578 | void set_weight(int8_t w); | ||
2341 | 579 | int8_t get_weight() { | ||
2342 | 580 | return weight; | ||
2343 | 581 | } | ||
2344 | 582 | int8_t get_result(size_t); | ||
2345 | 583 | int8_t get_result_safe(int32_t, bool = false); | ||
2346 | 584 | void set_type(uint8_t); | ||
2347 | 585 | uint8_t get_type() { | ||
2348 | 586 | return type; | ||
2349 | 587 | } | ||
2350 | 588 | uint16_t get_id() { | ||
2351 | 589 | return id; | ||
2352 | 590 | } | ||
2353 | 591 | |||
2354 | 592 | private: | ||
2355 | 593 | int8_t results[21]; // kPositions + 1 | ||
2356 | 594 | int8_t weight; | ||
2357 | 595 | uint8_t type; | ||
2358 | 596 | uint16_t id; | ||
2359 | 597 | }; | ||
2360 | 598 | |||
2361 | 599 | struct FNeuron { | ||
2362 | 600 | FNeuron(uint32_t, uint16_t); | ||
2363 | 601 | |||
2364 | 602 | void flip_bit(uint8_t); | ||
2365 | 603 | bool get_result(bool, bool, bool, bool bool4 = true, bool bool5 = true); | ||
2366 | 604 | bool get_position(uint8_t); | ||
2367 | 605 | uint32_t get_int(); | ||
2368 | 606 | uint16_t get_id() { | ||
2369 | 607 | return id; | ||
2370 | 608 | }; | ||
2371 | 609 | |||
2372 | 610 | private: | ||
2373 | 611 | std::bitset<kFNeuronBitSize> core; | ||
2374 | 612 | uint16_t id; | ||
2375 | 613 | }; | ||
2376 | 614 | |||
2377 | 615 | struct ExpansionType { | ||
2378 | 616 | ExpansionType(); | ||
2379 | 617 | |||
2380 | 618 | void set_expantion_type(ExpansionMode); | ||
2381 | 619 | ExpansionMode get_expansion_type() { | ||
2382 | 620 | return type; | ||
2383 | 621 | }; | ||
2384 | 622 | |||
2385 | 623 | private: | ||
2386 | 624 | ExpansionMode type; | ||
2387 | 625 | }; | ||
2388 | 626 | |||
2389 | 627 | // This is to keep all data related to AI magic numbers | ||
2390 | 628 | struct ManagementData { | ||
2391 | 629 | ManagementData(); | ||
2392 | 630 | |||
2393 | 631 | std::vector<Neuron> neuron_pool; | ||
2394 | 632 | std::vector<FNeuron> f_neuron_pool; | ||
2395 | 633 | Widelands::Player::AiPersistentState* pd; | ||
2396 | 634 | |||
2397 | 635 | void mutate(PlayerNumber = 0); | ||
2398 | 636 | void new_dna_for_persistent(uint8_t, Widelands::AiType); | ||
2399 | 637 | void copy_persistent_to_local(); | ||
2400 | 638 | void review( | ||
2401 | 639 | uint32_t, PlayerNumber, uint32_t, uint32_t, uint32_t, uint16_t, int16_t, int16_t, uint16_t); | ||
2402 | 640 | void dump_data(); | ||
2403 | 641 | uint16_t new_neuron_id() { | ||
2404 | 642 | ++next_neuron_id; | ||
2405 | 643 | return next_neuron_id - 1; | ||
2406 | 644 | }; | ||
2407 | 645 | void reset_neuron_id() { | ||
2408 | 646 | next_neuron_id = 0; | ||
2409 | 647 | } | ||
2410 | 648 | uint16_t new_bi_neuron_id() { | ||
2411 | 649 | ++next_bi_neuron_id; | ||
2412 | 650 | return next_bi_neuron_id - 1; | ||
2413 | 651 | }; | ||
2414 | 652 | void reset_bi_neuron_id() { | ||
2415 | 653 | next_bi_neuron_id = 0; | ||
2416 | 654 | } | ||
2417 | 655 | int16_t get_military_number_at(uint8_t); | ||
2418 | 656 | void set_military_number_at(uint8_t, int16_t); | ||
2419 | 657 | MutatingIntensity do_mutate(uint8_t, int16_t); | ||
2420 | 658 | int8_t shift_weight_value(int8_t, bool = true); | ||
2421 | 659 | void test_consistency(bool = false); | ||
2422 | 660 | |||
2423 | 661 | private: | ||
2424 | 662 | int32_t score; | ||
2425 | 663 | uint8_t primary_parent; | ||
2426 | 664 | uint16_t next_neuron_id; | ||
2427 | 665 | uint16_t next_bi_neuron_id; | ||
2428 | 666 | uint16_t performance_change; | ||
2429 | 667 | Widelands::AiType ai_type; | ||
2430 | 478 | }; | 668 | }; |
2431 | 479 | 669 | ||
2432 | 480 | // this is used to count militarysites by their size | 670 | // this is used to count militarysites by their size |
2433 | @@ -492,7 +682,7 @@ | |||
2434 | 492 | const uint8_t p, | 682 | const uint8_t p, |
2435 | 493 | const char* d); | 683 | const char* d); |
2436 | 494 | 684 | ||
2438 | 495 | bool operator<(SchedulerTask other) const; | 685 | bool operator<(const SchedulerTask& other) const; |
2439 | 496 | 686 | ||
2440 | 497 | uint32_t due_time; | 687 | uint32_t due_time; |
2441 | 498 | Widelands::SchedulerTaskId id; | 688 | Widelands::SchedulerTaskId id; |
2442 | @@ -560,34 +750,87 @@ | |||
2443 | 560 | // Updating walking distance over existing roads | 750 | // Updating walking distance over existing roads |
2444 | 561 | void set_road_distance(Widelands::Coords coords, int32_t distance); | 751 | void set_road_distance(Widelands::Coords coords, int32_t distance); |
2445 | 562 | // Finally we query the flag that we will build a road to | 752 | // Finally we query the flag that we will build a road to |
2447 | 563 | bool get_winner(uint32_t* winner_hash, uint32_t pos); | 753 | bool get_winner(uint32_t* winner_hash); |
2448 | 564 | }; | 754 | }; |
2449 | 565 | 755 | ||
2450 | 566 | // This is a struct that stores strength of players, info on teams and provides some outputs from | 756 | // This is a struct that stores strength of players, info on teams and provides some outputs from |
2451 | 567 | // these data | 757 | // these data |
2452 | 568 | struct PlayersStrengths { | 758 | struct PlayersStrengths { |
2453 | 759 | private: | ||
2454 | 569 | struct PlayerStat { | 760 | struct PlayerStat { |
2455 | 570 | PlayerStat(); | 761 | PlayerStat(); |
2457 | 571 | PlayerStat(Widelands::TeamNumber tc, uint32_t pp); | 762 | PlayerStat(Widelands::TeamNumber tc, |
2458 | 763 | bool en, | ||
2459 | 764 | uint32_t pp, | ||
2460 | 765 | uint32_t op, | ||
2461 | 766 | uint32_t o60p, | ||
2462 | 767 | uint32_t cs, | ||
2463 | 768 | uint32_t land, | ||
2464 | 769 | uint32_t oland, | ||
2465 | 770 | uint32_t o60l); | ||
2466 | 572 | 771 | ||
2467 | 573 | Widelands::TeamNumber team_number; | 772 | Widelands::TeamNumber team_number; |
2468 | 773 | bool is_enemy; | ||
2469 | 574 | uint32_t players_power; | 774 | uint32_t players_power; |
2470 | 775 | uint32_t old_players_power; | ||
2471 | 776 | uint32_t old60_players_power; | ||
2472 | 777 | uint32_t players_casualities; | ||
2473 | 778 | uint32_t last_time_seen; | ||
2474 | 779 | uint32_t players_land; | ||
2475 | 780 | uint32_t old_players_land; | ||
2476 | 781 | uint32_t old60_players_land; | ||
2477 | 575 | }; | 782 | }; |
2478 | 576 | 783 | ||
2479 | 784 | public: | ||
2480 | 785 | PlayersStrengths(); | ||
2481 | 577 | // Inserting/updating data | 786 | // Inserting/updating data |
2483 | 578 | void add(Widelands::PlayerNumber pn, Widelands::TeamNumber tn, uint32_t pp); | 787 | void add(Widelands::PlayerNumber pn, |
2484 | 788 | Widelands::PlayerNumber opn, | ||
2485 | 789 | Widelands::TeamNumber mytn, | ||
2486 | 790 | Widelands::TeamNumber pltn, | ||
2487 | 791 | uint32_t pp, | ||
2488 | 792 | uint32_t op, | ||
2489 | 793 | uint32_t o60p, | ||
2490 | 794 | uint32_t cs, | ||
2491 | 795 | uint32_t land, | ||
2492 | 796 | uint32_t oland, | ||
2493 | 797 | uint32_t o60l); | ||
2494 | 579 | void recalculate_team_power(); | 798 | void recalculate_team_power(); |
2495 | 580 | 799 | ||
2496 | 581 | // This is strength of player plus third of strength of other members of his team | 800 | // This is strength of player plus third of strength of other members of his team |
2497 | 582 | uint32_t get_modified_player_power(Widelands::PlayerNumber pn); | 801 | uint32_t get_modified_player_power(Widelands::PlayerNumber pn); |
2498 | 802 | uint32_t get_player_power(Widelands::PlayerNumber pn); | ||
2499 | 803 | uint32_t get_old_player_power(Widelands::PlayerNumber pn); | ||
2500 | 804 | uint32_t get_old60_player_power(Widelands::PlayerNumber pn); | ||
2501 | 805 | uint32_t get_player_land(Widelands::PlayerNumber pn); | ||
2502 | 806 | uint32_t get_old_player_land(Widelands::PlayerNumber pn); | ||
2503 | 807 | uint32_t get_old60_player_land(Widelands::PlayerNumber pn); | ||
2504 | 808 | uint32_t get_visible_enemies_power(uint32_t); | ||
2505 | 809 | uint32_t get_enemies_average_power(); | ||
2506 | 810 | uint32_t get_enemies_average_land(); | ||
2507 | 811 | uint32_t get_enemies_max_power(); | ||
2508 | 812 | uint32_t get_enemies_max_land(); | ||
2509 | 813 | uint32_t get_old_visible_enemies_power(uint32_t); | ||
2510 | 814 | uint32_t get_player_casualities(Widelands::PlayerNumber pn); | ||
2511 | 583 | bool players_in_same_team(Widelands::PlayerNumber pl1, Widelands::PlayerNumber pl2); | 815 | bool players_in_same_team(Widelands::PlayerNumber pl1, Widelands::PlayerNumber pl2); |
2512 | 584 | bool strong_enough(Widelands::PlayerNumber pl); | 816 | bool strong_enough(Widelands::PlayerNumber pl); |
2513 | 817 | void set_last_time_seen(uint32_t, Widelands::PlayerNumber); | ||
2514 | 818 | bool player_seen_lately(Widelands::PlayerNumber, uint32_t); | ||
2515 | 819 | bool get_is_enemy(Widelands::PlayerNumber); | ||
2516 | 820 | uint8_t enemies_seen_lately_count(uint32_t); | ||
2517 | 821 | bool any_enemy_seen_lately(uint32_t); | ||
2518 | 822 | PlayerNumber this_player_number; | ||
2519 | 823 | void set_update_time(uint32_t); | ||
2520 | 824 | uint32_t get_update_time(); | ||
2521 | 585 | 825 | ||
2522 | 826 | private: | ||
2523 | 586 | // This is the core part of this struct | 827 | // This is the core part of this struct |
2524 | 587 | std::map<Widelands::PlayerNumber, PlayerStat> all_stats; | 828 | std::map<Widelands::PlayerNumber, PlayerStat> all_stats; |
2525 | 588 | 829 | ||
2526 | 589 | // Number of team, sum of players' strength | 830 | // Number of team, sum of players' strength |
2527 | 590 | std::map<Widelands::TeamNumber, uint32_t> team_powers; | 831 | std::map<Widelands::TeamNumber, uint32_t> team_powers; |
2528 | 832 | |||
2529 | 833 | uint32_t update_time; | ||
2530 | 591 | }; | 834 | }; |
2531 | 592 | } // namespace Widelands | 835 | } // namespace Widelands |
2532 | 593 | 836 | ||
2533 | 594 | 837 | ||
2534 | === modified file 'src/ai/ai_hints.cc' | |||
2535 | --- src/ai/ai_hints.cc 2017-05-25 07:16:05 +0000 | |||
2536 | +++ src/ai/ai_hints.cc 2017-07-03 17:39:38 +0000 | |||
2537 | @@ -38,27 +38,19 @@ | |||
2538 | 38 | table->has_key("mountain_conqueror") ? table->get_bool("mountain_conqueror") : false), | 38 | table->has_key("mountain_conqueror") ? table->get_bool("mountain_conqueror") : false), |
2539 | 39 | shipyard_(table->has_key("shipyard") ? table->get_bool("shipyard") : false), | 39 | shipyard_(table->has_key("shipyard") ? table->get_bool("shipyard") : false), |
2540 | 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), |
2541 | 41 | basic_amount_(table->has_key("basic_amount") ? table->get_int("basic_amount") : 0), | ||
2542 | 41 | // 10 days default | 42 | // 10 days default |
2543 | 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), |
2544 | 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), |
2545 | 44 | very_weak_ai_limit_( | 45 | very_weak_ai_limit_( |
2546 | 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), |
2547 | 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), |
2548 | 47 | trainingsite_type_(TrainingSiteType::kNoTS), | ||
2549 | 48 | trainingsites_max_percent_(table->has_key("trainingsites_max_percent") ? | 48 | trainingsites_max_percent_(table->has_key("trainingsites_max_percent") ? |
2550 | 49 | table->get_int("trainingsites_max_percent") : | 49 | table->get_int("trainingsites_max_percent") : |
2551 | 50 | 0) { | 50 | 0) { |
2552 | 51 | |||
2553 | 52 | if (table->has_key("trainingsite_type")) { | ||
2554 | 53 | if (table->get_string("trainingsite_type") == "basic") { | ||
2555 | 54 | trainingsite_type_ = TrainingSiteType::kBasic; | ||
2556 | 55 | } else if (table->get_string("trainingsite_type") == "advanced") { | ||
2557 | 56 | trainingsite_type_ = TrainingSiteType::kAdvanced; | ||
2558 | 57 | } | ||
2559 | 58 | } | ||
2560 | 59 | } | 51 | } |
2561 | 60 | 52 | ||
2563 | 61 | void BuildingHints::set_trainingsites_max_percent(uint8_t percent) { | 53 | void BuildingHints::set_trainingsites_max_percent(int percent) { |
2564 | 62 | trainingsites_max_percent_ = percent; | 54 | trainingsites_max_percent_ = percent; |
2565 | 63 | } | 55 | } |
2566 | 64 | 56 | ||
2567 | 65 | 57 | ||
2568 | === modified file 'src/ai/ai_hints.h' | |||
2569 | --- src/ai/ai_hints.h 2017-06-24 08:47:46 +0000 | |||
2570 | +++ src/ai/ai_hints.h 2017-07-03 17:39:38 +0000 | |||
2571 | @@ -28,8 +28,6 @@ | |||
2572 | 28 | #include "base/macros.h" | 28 | #include "base/macros.h" |
2573 | 29 | #include "scripting/lua_table.h" | 29 | #include "scripting/lua_table.h" |
2574 | 30 | 30 | ||
2575 | 31 | enum class TrainingSiteType : uint8_t { kNoTS = 0, kBasic = 1, kAdvanced = 2 }; | ||
2576 | 32 | |||
2577 | 33 | /// This struct is used to read out the data given in [aihints] section of a | 31 | /// This struct is used to read out the data given in [aihints] section of a |
2578 | 34 | /// buildings conf file. It is used to tell the computer player about the | 32 | /// buildings conf file. It is used to tell the computer player about the |
2579 | 35 | /// special properties of a building. | 33 | /// special properties of a building. |
2580 | @@ -95,6 +93,10 @@ | |||
2581 | 95 | return prohibited_till_; | 93 | return prohibited_till_; |
2582 | 96 | } | 94 | } |
2583 | 97 | 95 | ||
2584 | 96 | uint32_t basic_amount() const { | ||
2585 | 97 | return basic_amount_; | ||
2586 | 98 | } | ||
2587 | 99 | |||
2588 | 98 | uint32_t get_forced_after() const { | 100 | uint32_t get_forced_after() const { |
2589 | 99 | return forced_after_; | 101 | return forced_after_; |
2590 | 100 | } | 102 | } |
2591 | @@ -111,11 +113,7 @@ | |||
2592 | 111 | return weak_ai_limit_; | 113 | return weak_ai_limit_; |
2593 | 112 | } | 114 | } |
2594 | 113 | 115 | ||
2600 | 114 | TrainingSiteType get_trainingsite_type() const { | 116 | void set_trainingsites_max_percent(int percent); |
2596 | 115 | return trainingsite_type_; | ||
2597 | 116 | } | ||
2598 | 117 | |||
2599 | 118 | void set_trainingsites_max_percent(uint8_t percent); | ||
2601 | 119 | 117 | ||
2602 | 120 | uint8_t trainingsites_max_percent() const; | 118 | uint8_t trainingsites_max_percent() const; |
2603 | 121 | 119 | ||
2604 | @@ -133,11 +131,11 @@ | |||
2605 | 133 | bool mountain_conqueror_; | 131 | bool mountain_conqueror_; |
2606 | 134 | bool shipyard_; | 132 | bool shipyard_; |
2607 | 135 | int32_t prohibited_till_; | 133 | int32_t prohibited_till_; |
2608 | 134 | uint32_t basic_amount_; | ||
2609 | 136 | int32_t forced_after_; | 135 | int32_t forced_after_; |
2610 | 137 | int8_t mines_percent_; | 136 | int8_t mines_percent_; |
2611 | 138 | int16_t very_weak_ai_limit_; | 137 | int16_t very_weak_ai_limit_; |
2612 | 139 | int16_t weak_ai_limit_; | 138 | int16_t weak_ai_limit_; |
2613 | 140 | TrainingSiteType trainingsite_type_; | ||
2614 | 141 | int trainingsites_max_percent_; | 139 | int trainingsites_max_percent_; |
2615 | 142 | 140 | ||
2616 | 143 | DISALLOW_COPY_AND_ASSIGN(BuildingHints); | 141 | DISALLOW_COPY_AND_ASSIGN(BuildingHints); |
2617 | 144 | 142 | ||
2618 | === modified file 'src/ai/defaultai.cc' | |||
2619 | --- src/ai/defaultai.cc 2017-06-24 20:22:19 +0000 | |||
2620 | +++ src/ai/defaultai.cc 2017-07-03 17:39:38 +0000 | |||
2621 | @@ -62,13 +62,16 @@ | |||
2622 | 62 | constexpr int kMinBFCheckInterval = 5 * 1000; | 62 | constexpr int kMinBFCheckInterval = 5 * 1000; |
2623 | 63 | constexpr int kMinMFCheckInterval = 19 * 1000; | 63 | constexpr int kMinMFCheckInterval = 19 * 1000; |
2624 | 64 | constexpr int kMarineDecisionInterval = 20 * 1000; | 64 | constexpr int kMarineDecisionInterval = 20 * 1000; |
2625 | 65 | constexpr int kRemainingBasicBuildingsResetTime = 1 * 60 * 1000; | ||
2626 | 65 | 66 | ||
2627 | 66 | // following two are used for roads management, for creating shortcuts and dismantling dispensable | 67 | // following two are used for roads management, for creating shortcuts and dismantling dispensable |
2628 | 67 | // roads | 68 | // roads |
2629 | 68 | constexpr int32_t kSpotsTooLittle = 15; | 69 | constexpr int32_t kSpotsTooLittle = 15; |
2630 | 69 | constexpr int32_t kSpotsEnough = 25; | 70 | constexpr int32_t kSpotsEnough = 25; |
2631 | 70 | 71 | ||
2633 | 71 | // this is intended for map developers, by default should be off | 72 | constexpr uint16_t kTargetQuantCap = 30; |
2634 | 73 | |||
2635 | 74 | // this is intended for map developers & testers, should be off by default | ||
2636 | 72 | constexpr bool kPrintStats = false; | 75 | constexpr bool kPrintStats = false; |
2637 | 73 | 76 | ||
2638 | 74 | // for scheduler | 77 | // for scheduler |
2639 | @@ -81,37 +84,29 @@ | |||
2640 | 81 | DefaultAI::VeryWeakImpl DefaultAI::very_weak_impl; | 84 | DefaultAI::VeryWeakImpl DefaultAI::very_weak_impl; |
2641 | 82 | 85 | ||
2642 | 83 | /// Constructor of DefaultAI | 86 | /// Constructor of DefaultAI |
2644 | 84 | DefaultAI::DefaultAI(Game& ggame, PlayerNumber const pid, DefaultAI::Type const t) | 87 | DefaultAI::DefaultAI(Game& ggame, PlayerNumber const pid, Widelands::AiType const t) |
2645 | 85 | : ComputerPlayer(ggame, pid), | 88 | : ComputerPlayer(ggame, pid), |
2646 | 86 | type_(t), | 89 | type_(t), |
2647 | 87 | player_(nullptr), | 90 | player_(nullptr), |
2648 | 88 | tribe_(nullptr), | 91 | tribe_(nullptr), |
2649 | 92 | attackers_count_(0), | ||
2650 | 89 | next_ai_think_(0), | 93 | next_ai_think_(0), |
2651 | 90 | scheduler_delay_counter_(0), | 94 | scheduler_delay_counter_(0), |
2652 | 91 | wood_policy_(WoodPolicy::kAllowRangers), | 95 | wood_policy_(WoodPolicy::kAllowRangers), |
2654 | 92 | num_prod_constructionsites(0), | 96 | numof_psites_in_constr(0), |
2655 | 93 | num_ports(0), | 97 | num_ports(0), |
2656 | 94 | numof_warehouses_(0), | 98 | numof_warehouses_(0), |
2657 | 99 | numof_warehouses_in_const_(0), | ||
2658 | 95 | military_last_dismantle_(0), | 100 | military_last_dismantle_(0), |
2659 | 96 | military_last_build_(0), | 101 | military_last_build_(0), |
2660 | 97 | time_of_last_construction_(0), | 102 | time_of_last_construction_(0), |
2661 | 98 | next_mine_construction_due_(0), | 103 | next_mine_construction_due_(0), |
2666 | 99 | ts_basic_count_(0), | 104 | fishers_count_(0), |
2667 | 100 | ts_basic_const_count_(0), | 105 | bakeries_count_(), |
2668 | 101 | ts_advanced_count_(0), | 106 | ts_finished_count_(0), |
2669 | 102 | ts_advanced_const_count_(0), | 107 | ts_in_const_count_(0), |
2670 | 103 | ts_without_trainers_(0), | 108 | ts_without_trainers_(0), |
2671 | 104 | inhibit_road_building_(0), | 109 | inhibit_road_building_(0), |
2672 | 105 | last_road_dismantled_(0), | ||
2673 | 106 | enemy_last_seen_(kNever), | ||
2674 | 107 | vacant_mil_positions_(0), | ||
2675 | 108 | last_attack_time_(0), | ||
2676 | 109 | enemysites_check_delay_(60), | ||
2677 | 110 | spots_(0), | ||
2678 | 111 | new_buildings_stop_(false), | ||
2679 | 112 | resource_necessity_territory_(100), | ||
2680 | 113 | resource_necessity_mines_(100), | ||
2681 | 114 | resource_necessity_water_(0), | ||
2682 | 115 | resource_necessity_water_needed_(false), | 110 | resource_necessity_water_needed_(false), |
2683 | 116 | highest_nonmil_prio_(0), | 111 | highest_nonmil_prio_(0), |
2684 | 117 | seafaring_economy(false), | 112 | seafaring_economy(false), |
2685 | @@ -249,6 +244,8 @@ | |||
2686 | 249 | 244 | ||
2687 | 250 | const int32_t delay_time = gametime - taskPool.front().due_time; | 245 | const int32_t delay_time = gametime - taskPool.front().due_time; |
2688 | 251 | 246 | ||
2689 | 247 | Map& map = game().map(); | ||
2690 | 248 | |||
2691 | 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) |
2692 | 253 | // in case no job is due now, it can be zero | 250 | // in case no job is due now, it can be zero |
2693 | 254 | uint32_t jobs_to_run_count = (delay_time < 0) ? 0 : 1; | 251 | uint32_t jobs_to_run_count = (delay_time < 0) ? 0 : 1; |
2694 | @@ -400,7 +397,7 @@ | |||
2695 | 400 | // checking 3 mines if possible | 397 | // checking 3 mines if possible |
2696 | 401 | { | 398 | { |
2697 | 402 | int32_t mines_to_check = (mines_.size() < 5) ? mines_.size() : 5; | 399 | int32_t mines_to_check = (mines_.size() < 5) ? mines_.size() : 5; |
2699 | 403 | for (int j = 0; j < mines_to_check; j += 1) { | 400 | for (int j = 0; j < mines_to_check; ++j) { |
2700 | 404 | // every run of check_mines_() checks one mine | 401 | // every run of check_mines_() checks one mine |
2701 | 405 | if (check_mines_(gametime)) { | 402 | if (check_mines_(gametime)) { |
2702 | 406 | // if significant change takes place do not go on | 403 | // if significant change takes place do not go on |
2703 | @@ -411,9 +408,11 @@ | |||
2704 | 411 | break; | 408 | break; |
2705 | 412 | case SchedulerTaskId::kCheckMilitarysites: | 409 | case SchedulerTaskId::kCheckMilitarysites: |
2706 | 413 | // just to be sure the value is reset | 410 | // just to be sure the value is reset |
2710 | 414 | // 4 seconds is really fine | 411 | if (check_militarysites(gametime)) { |
2711 | 415 | set_taskpool_task_time(gametime + 4 * 1000, SchedulerTaskId::kCheckMilitarysites); | 412 | set_taskpool_task_time(gametime + 15 * 1000, SchedulerTaskId::kCheckMilitarysites); |
2712 | 416 | check_militarysites(gametime); | 413 | } else { |
2713 | 414 | set_taskpool_task_time(gametime + 4 * 1000, SchedulerTaskId::kCheckMilitarysites); | ||
2714 | 415 | } | ||
2715 | 417 | break; | 416 | break; |
2716 | 418 | case SchedulerTaskId::kCheckTrainingsites: | 417 | case SchedulerTaskId::kCheckTrainingsites: |
2717 | 419 | set_taskpool_task_time( | 418 | set_taskpool_task_time( |
2718 | @@ -422,7 +421,7 @@ | |||
2719 | 422 | break; | 421 | break; |
2720 | 423 | case SchedulerTaskId::kCountMilitaryVacant: | 422 | case SchedulerTaskId::kCountMilitaryVacant: |
2721 | 424 | count_military_vacant_positions(); | 423 | count_military_vacant_positions(); |
2723 | 425 | set_taskpool_task_time(gametime + 45 * 1000, SchedulerTaskId::kCountMilitaryVacant); | 424 | set_taskpool_task_time(gametime + 25 * 1000, SchedulerTaskId::kCountMilitaryVacant); |
2724 | 426 | break; | 425 | break; |
2725 | 427 | case SchedulerTaskId::kWareReview: | 426 | case SchedulerTaskId::kWareReview: |
2726 | 428 | if (check_economies()) { // economies must be consistent | 427 | if (check_economies()) { // economies must be consistent |
2727 | @@ -435,13 +434,38 @@ | |||
2728 | 435 | if (check_economies()) { // economies must be consistent | 434 | if (check_economies()) { // economies must be consistent |
2729 | 436 | return; | 435 | return; |
2730 | 437 | } | 436 | } |
2733 | 438 | set_taskpool_task_time(gametime + 30 * 60 * 1000, SchedulerTaskId::kPrintStats); | 437 | set_taskpool_task_time(gametime + 10 * 60 * 1000, SchedulerTaskId::kPrintStats); |
2734 | 439 | print_stats(); | 438 | print_stats(gametime); |
2735 | 440 | break; | 439 | break; |
2736 | 441 | case SchedulerTaskId::kCheckEnemySites: | 440 | case SchedulerTaskId::kCheckEnemySites: |
2737 | 442 | check_enemy_sites(gametime); | 441 | check_enemy_sites(gametime); |
2738 | 443 | set_taskpool_task_time(gametime + 19 * 1000, SchedulerTaskId::kCheckEnemySites); | 442 | set_taskpool_task_time(gametime + 19 * 1000, SchedulerTaskId::kCheckEnemySites); |
2739 | 444 | break; | 443 | break; |
2740 | 444 | case SchedulerTaskId::kManagementUpdate: | ||
2741 | 445 | // This task is used for training the AI, so it should be usually disabled | ||
2742 | 446 | { // statistics for spotted warehouses | ||
2743 | 447 | uint16_t conquered_wh = 0; | ||
2744 | 448 | for (auto coords : enemy_warehouses) { | ||
2745 | 449 | if (get_land_owner(map, coords) == player_number()) { | ||
2746 | 450 | ++conquered_wh; | ||
2747 | 451 | } | ||
2748 | 452 | }; | ||
2749 | 453 | if (!enemy_warehouses.empty()) | ||
2750 | 454 | log("Conquered warehouses: %d / %lu\n", conquered_wh, enemy_warehouses.size()); | ||
2751 | 455 | management_data.review(gametime, player_number(), | ||
2752 | 456 | player_statistics.get_player_land(player_number()), | ||
2753 | 457 | player_statistics.get_enemies_max_land(), | ||
2754 | 458 | player_statistics.get_old60_player_land(player_number()), | ||
2755 | 459 | attackers_count_, soldier_trained_log.count(gametime), | ||
2756 | 460 | soldier_attacks_log.count(gametime), conquered_wh); | ||
2757 | 461 | set_taskpool_task_time( | ||
2758 | 462 | gametime + kManagementUpdateInterval, SchedulerTaskId::kManagementUpdate); | ||
2759 | 463 | } | ||
2760 | 464 | break; | ||
2761 | 465 | case SchedulerTaskId::kUpdateStats: | ||
2762 | 466 | update_player_stat(gametime); | ||
2763 | 467 | set_taskpool_task_time(gametime + kStatUpdateInterval, SchedulerTaskId::kUpdateStats); | ||
2764 | 468 | break; | ||
2765 | 445 | case SchedulerTaskId::kUnset: | 469 | case SchedulerTaskId::kUnset: |
2766 | 446 | NEVER_HERE(); | 470 | NEVER_HERE(); |
2767 | 447 | } | 471 | } |
2768 | @@ -474,7 +498,92 @@ | |||
2769 | 474 | 498 | ||
2770 | 475 | const DescriptionIndex& nr_buildings = game().tribes().nrbuildings(); | 499 | const DescriptionIndex& nr_buildings = game().tribes().nrbuildings(); |
2771 | 476 | 500 | ||
2773 | 477 | // Collect information about the different buildings that our tribe can have | 501 | // The data struct below is owned by Player object, the purpose is to have them saved therein |
2774 | 502 | persistent_data = player_->get_mutable_ai_persistent_state(); | ||
2775 | 503 | management_data.pd = player_->get_mutable_ai_persistent_state(); | ||
2776 | 504 | const bool create_basic_buildings_list = (gametime < kRemainingBasicBuildingsResetTime); | ||
2777 | 505 | |||
2778 | 506 | if (persistent_data->initialized == kFalse) { | ||
2779 | 507 | // As all data are initialized without given values, they must be populated with reasonable | ||
2780 | 508 | // values first | ||
2781 | 509 | persistent_data->colony_scan_area = kColonyScanStartArea; | ||
2782 | 510 | persistent_data->trees_around_cutters = 0; | ||
2783 | 511 | persistent_data->initialized = kTrue; | ||
2784 | 512 | persistent_data->last_attacked_player = std::numeric_limits<int16_t>::max(); | ||
2785 | 513 | persistent_data->expedition_start_time = kNoExpedition; | ||
2786 | 514 | persistent_data->ships_utilization = 200; | ||
2787 | 515 | persistent_data->no_more_expeditions = kFalse; | ||
2788 | 516 | persistent_data->target_military_score = 100; | ||
2789 | 517 | persistent_data->least_military_score = 0; | ||
2790 | 518 | persistent_data->ai_productionsites_ratio = std::rand() % 5 + 7; | ||
2791 | 519 | persistent_data->ai_personality_mil_upper_limit = 100; | ||
2792 | 520 | |||
2793 | 521 | // all zeroes | ||
2794 | 522 | assert(persistent_data->neuron_weights.empty()); | ||
2795 | 523 | assert(persistent_data->neuron_functs.empty()); | ||
2796 | 524 | assert(persistent_data->magic_numbers_size == 0); | ||
2797 | 525 | assert(persistent_data->neuron_pool_size == 0); | ||
2798 | 526 | assert(persistent_data->magic_numbers.empty()); | ||
2799 | 527 | |||
2800 | 528 | // AI's DNA population | ||
2801 | 529 | management_data.new_dna_for_persistent(player_number(), type_); | ||
2802 | 530 | management_data.copy_persistent_to_local(); | ||
2803 | 531 | management_data.mutate(player_number()); | ||
2804 | 532 | if (kAITrainingMode) { | ||
2805 | 533 | management_data.dump_data(); | ||
2806 | 534 | } | ||
2807 | 535 | |||
2808 | 536 | management_data.test_consistency(true); | ||
2809 | 537 | assert(management_data.get_military_number_at(42) == | ||
2810 | 538 | management_data.get_military_number_at(kMutationRatePosition)); | ||
2811 | 539 | |||
2812 | 540 | } else if (persistent_data->initialized == kTrue) { | ||
2813 | 541 | // Doing some consistency checks | ||
2814 | 542 | check_range<uint32_t>( | ||
2815 | 543 | persistent_data->expedition_start_time, gametime, "expedition_start_time"); | ||
2816 | 544 | check_range<uint16_t>(persistent_data->ships_utilization, 0, 10000, "ships_utilization_"); | ||
2817 | 545 | |||
2818 | 546 | // for backward consistency | ||
2819 | 547 | if (persistent_data->ai_personality_mil_upper_limit < | ||
2820 | 548 | persistent_data->target_military_score) { | ||
2821 | 549 | persistent_data->ai_personality_mil_upper_limit = persistent_data->target_military_score; | ||
2822 | 550 | } | ||
2823 | 551 | if (persistent_data->least_military_score > persistent_data->target_military_score) { | ||
2824 | 552 | persistent_data->least_military_score = persistent_data->target_military_score; | ||
2825 | 553 | } | ||
2826 | 554 | |||
2827 | 555 | if (kAITrainingMode) { | ||
2828 | 556 | log("%2d: reinitializing dna (kAITrainingMode set true)", player_number()); | ||
2829 | 557 | management_data.new_dna_for_persistent(player_number(), type_); | ||
2830 | 558 | management_data.copy_persistent_to_local(); | ||
2831 | 559 | management_data.mutate(player_number()); | ||
2832 | 560 | |||
2833 | 561 | } else { | ||
2834 | 562 | management_data.copy_persistent_to_local(); | ||
2835 | 563 | } | ||
2836 | 564 | |||
2837 | 565 | management_data.test_consistency(true); | ||
2838 | 566 | if (kAITrainingMode) { | ||
2839 | 567 | management_data.dump_data(); | ||
2840 | 568 | } | ||
2841 | 569 | |||
2842 | 570 | log(" %2d: %lu basic buildings in savegame file. %s\n", player_number(), | ||
2843 | 571 | persistent_data->remaining_basic_buildings.size(), | ||
2844 | 572 | (create_basic_buildings_list) ? | ||
2845 | 573 | "New list will be recreated though (kAITrainingMode is true)" : | ||
2846 | 574 | ""); | ||
2847 | 575 | |||
2848 | 576 | } else { | ||
2849 | 577 | throw wexception("Corrupted AI data"); | ||
2850 | 578 | } | ||
2851 | 579 | |||
2852 | 580 | // Even if we have basic buildings from savefile, we ignore them and recreate them based | ||
2853 | 581 | // on lua conf files | ||
2854 | 582 | if (create_basic_buildings_list) { | ||
2855 | 583 | persistent_data->remaining_basic_buildings.clear(); | ||
2856 | 584 | persistent_data->remaining_buildings_size = 0; | ||
2857 | 585 | } | ||
2858 | 586 | |||
2859 | 478 | for (DescriptionIndex building_index = 0; building_index < nr_buildings; ++building_index) { | 587 | for (DescriptionIndex building_index = 0; building_index < nr_buildings; ++building_index) { |
2860 | 479 | const BuildingDescr& bld = *tribe_->get_building_descr(building_index); | 588 | const BuildingDescr& bld = *tribe_->get_building_descr(building_index); |
2861 | 480 | if (!tribe_->has_building(building_index) && bld.type() != MapObjectType::MILITARYSITE) { | 589 | if (!tribe_->has_building(building_index) && bld.type() != MapObjectType::MILITARYSITE) { |
2862 | @@ -494,7 +603,7 @@ | |||
2863 | 494 | bo.cnt_target = 1; // default for everything | 603 | bo.cnt_target = 1; // default for everything |
2864 | 495 | bo.cnt_limit_by_aimode = std::numeric_limits<int32_t>::max(); | 604 | bo.cnt_limit_by_aimode = std::numeric_limits<int32_t>::max(); |
2865 | 496 | bo.cnt_upgrade_pending = 0; | 605 | bo.cnt_upgrade_pending = 0; |
2867 | 497 | bo.stocklevel = 0; | 606 | bo.stocklevel_count = 0; |
2868 | 498 | bo.stocklevel_time = 0; | 607 | bo.stocklevel_time = 0; |
2869 | 499 | bo.last_dismantle_time = 0; | 608 | bo.last_dismantle_time = 0; |
2870 | 500 | // this is set to negative number, otherwise the AI would wait 25 sec | 609 | // this is set to negative number, otherwise the AI would wait 25 sec |
2871 | @@ -508,23 +617,41 @@ | |||
2872 | 508 | bo.unconnected_count = 0; | 617 | bo.unconnected_count = 0; |
2873 | 509 | bo.new_building_overdue = 0; | 618 | bo.new_building_overdue = 0; |
2874 | 510 | bo.primary_priority = 0; | 619 | bo.primary_priority = 0; |
2882 | 511 | bo.is_buildable = bld.is_buildable(); | 620 | if (bld.is_buildable()) { |
2883 | 512 | bo.need_trees = bh.is_logproducer(); | 621 | bo.set_is(BuildingAttribute::kBuildable); |
2884 | 513 | bo.need_rocks = bh.is_graniteproducer(); | 622 | } |
2885 | 514 | bo.need_water = bh.get_needs_water(); | 623 | if (bh.is_logproducer()) { |
2886 | 515 | bo.mines_water = bh.mines_water(); | 624 | bo.set_is(BuildingAttribute::kLumberjack); |
2887 | 516 | bo.recruitment = bh.for_recruitment(); | 625 | } |
2888 | 517 | bo.space_consumer = bh.is_space_consumer(); | 626 | if (bh.is_graniteproducer()) { |
2889 | 627 | bo.set_is(BuildingAttribute::kNeedsRocks); | ||
2890 | 628 | } | ||
2891 | 629 | if (create_basic_buildings_list && | ||
2892 | 630 | bh.basic_amount() > 0) { // This is the very begining of the game | ||
2893 | 631 | persistent_data->remaining_basic_buildings[bo.id] = bh.basic_amount(); | ||
2894 | 632 | ++persistent_data->remaining_buildings_size; | ||
2895 | 633 | } | ||
2896 | 634 | if (bh.get_needs_water()) { | ||
2897 | 635 | bo.set_is(BuildingAttribute::kNeedsCoast); | ||
2898 | 636 | } | ||
2899 | 637 | if (bh.mines_water()) { | ||
2900 | 638 | bo.set_is(BuildingAttribute::kWell); | ||
2901 | 639 | } | ||
2902 | 640 | if (bh.is_space_consumer()) { | ||
2903 | 641 | bo.set_is(BuildingAttribute::kSpaceConsumer); | ||
2904 | 642 | } | ||
2905 | 643 | if (bh.for_recruitment()) { | ||
2906 | 644 | bo.set_is(BuildingAttribute::kRecruitment); | ||
2907 | 645 | } | ||
2908 | 518 | bo.expansion_type = bh.is_expansion_type(); | 646 | bo.expansion_type = bh.is_expansion_type(); |
2909 | 519 | bo.fighting_type = bh.is_fighting_type(); | 647 | bo.fighting_type = bh.is_fighting_type(); |
2910 | 520 | bo.mountain_conqueror = bh.is_mountain_conqueror(); | 648 | bo.mountain_conqueror = bh.is_mountain_conqueror(); |
2911 | 521 | bo.prohibited_till = bh.get_prohibited_till() * 1000; // value in conf is in seconds | 649 | bo.prohibited_till = bh.get_prohibited_till() * 1000; // value in conf is in seconds |
2912 | 522 | bo.forced_after = bh.get_forced_after() * 1000; // value in conf is in seconds | 650 | bo.forced_after = bh.get_forced_after() * 1000; // value in conf is in seconds |
2918 | 523 | bo.is_port = bld.get_isport(); | 651 | if (bld.get_isport()) { |
2919 | 524 | bo.trainingsite_type = TrainingSiteType::kNoTS; | 652 | bo.set_is(BuildingAttribute::kPort); |
2920 | 525 | bo.upgrade_substitutes = false; | 653 | } |
2921 | 526 | bo.upgrade_extends = false; | 654 | bo.max_trainingsites_proportion = 100; |
2917 | 527 | bo.produces_building_material = false; | ||
2922 | 528 | bo.max_preciousness = 0; | 655 | bo.max_preciousness = 0; |
2923 | 529 | bo.max_needed_preciousness = 0; | 656 | bo.max_needed_preciousness = 0; |
2924 | 530 | 657 | ||
2925 | @@ -534,18 +661,16 @@ | |||
2926 | 534 | 661 | ||
2927 | 535 | // I just presume cut wood is named "log" in the game | 662 | // I just presume cut wood is named "log" in the game |
2928 | 536 | if (tribe_->safe_ware_index("log") == bo.production_hint) { | 663 | if (tribe_->safe_ware_index("log") == bo.production_hint) { |
2932 | 537 | bo.plants_trees = true; | 664 | bo.set_is(BuildingAttribute::kRanger); |
2930 | 538 | } else { | ||
2931 | 539 | bo.plants_trees = false; | ||
2933 | 540 | } | 665 | } |
2934 | 541 | 666 | ||
2935 | 542 | // Is total count of this building limited by AI mode? | 667 | // Is total count of this building limited by AI mode? |
2937 | 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) { |
2938 | 544 | bo.cnt_limit_by_aimode = bh.get_very_weak_ai_limit(); | 669 | bo.cnt_limit_by_aimode = bh.get_very_weak_ai_limit(); |
2939 | 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(), |
2940 | 546 | bo.cnt_limit_by_aimode, bo.name); | 671 | bo.cnt_limit_by_aimode, bo.name); |
2941 | 547 | } | 672 | } |
2943 | 548 | if (type_ == DefaultAI::Type::kWeak && bh.get_weak_ai_limit() >= 0) { | 673 | if (type_ == Widelands::AiType::kWeak && bh.get_weak_ai_limit() >= 0) { |
2944 | 549 | bo.cnt_limit_by_aimode = bh.get_weak_ai_limit(); | 674 | bo.cnt_limit_by_aimode = bh.get_weak_ai_limit(); |
2945 | 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(), |
2946 | 551 | bo.cnt_limit_by_aimode, bo.name); | 676 | bo.cnt_limit_by_aimode, bo.name); |
2947 | @@ -562,6 +687,11 @@ | |||
2948 | 562 | for (const DescriptionIndex& temp_output : prod.output_ware_types()) { | 687 | for (const DescriptionIndex& temp_output : prod.output_ware_types()) { |
2949 | 563 | bo.outputs.push_back(temp_output); | 688 | bo.outputs.push_back(temp_output); |
2950 | 564 | } | 689 | } |
2951 | 690 | for (const auto temp_position : prod.working_positions()) { | ||
2952 | 691 | bo.positions.push_back(temp_position.first); | ||
2953 | 692 | } | ||
2954 | 693 | |||
2955 | 694 | iron_ore_id = tribe_->ironore(); | ||
2956 | 565 | 695 | ||
2957 | 566 | if (bo.type == BuildingObserver::Type::kMine) { | 696 | if (bo.type == BuildingObserver::Type::kMine) { |
2958 | 567 | // get the resource needed by the mine | 697 | // get the resource needed by the mine |
2959 | @@ -575,23 +705,36 @@ | |||
2960 | 575 | if (mines_per_type.count(bo.mines) == 0) { | 705 | if (mines_per_type.count(bo.mines) == 0) { |
2961 | 576 | mines_per_type[bo.mines] = MineTypesObserver(); | 706 | mines_per_type[bo.mines] = MineTypesObserver(); |
2962 | 577 | } | 707 | } |
2963 | 708 | // Identify iron mines based on output | ||
2964 | 709 | if (bo.outputs[0] == iron_ore_id) { | ||
2965 | 710 | bo.set_is(BuildingAttribute::kIronMine); | ||
2966 | 711 | mines_per_type[bo.mines].is_critical = true; | ||
2967 | 712 | } | ||
2968 | 578 | } | 713 | } |
2969 | 579 | 714 | ||
2970 | 580 | // here we identify hunters | 715 | // here we identify hunters |
2971 | 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)) { |
2975 | 582 | bo.is_hunter = true; | 717 | bo.set_is(BuildingAttribute::kHunter); |
2973 | 583 | } else { | ||
2974 | 584 | bo.is_hunter = false; | ||
2976 | 585 | } | 718 | } |
2977 | 586 | 719 | ||
2978 | 587 | // and fishers | 720 | // and fishers |
2979 | 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)) { |
2983 | 589 | bo.is_fisher = true; | 722 | bo.set_is(BuildingAttribute::kFisher); |
2981 | 590 | } else { | ||
2982 | 591 | bo.is_fisher = false; | ||
2984 | 592 | } | 723 | } |
2985 | 593 | 724 | ||
2987 | 594 | bo.is_shipyard = bh.is_shipyard(); | 725 | if (bh.is_shipyard()) { |
2988 | 726 | bo.set_is(BuildingAttribute::kShipyard); | ||
2989 | 727 | } | ||
2990 | 728 | if (building_index == tribe_->barracks()) { | ||
2991 | 729 | bo.set_is(BuildingAttribute::kBarracks); | ||
2992 | 730 | } | ||
2993 | 731 | if (building_index == tribe_->bakery()) { | ||
2994 | 732 | bo.set_is(BuildingAttribute::kBakery); | ||
2995 | 733 | } | ||
2996 | 734 | // Identify refined log producer | ||
2997 | 735 | if (bo.outputs.size() == 1 && bo.outputs[0] == tribe_->refinedlog()) { | ||
2998 | 736 | bo.set_is(BuildingAttribute::kLogRefiner); | ||
2999 | 737 | } | ||
3000 | 595 | 738 | ||
3001 | 596 | // now we find out if the upgrade of the building is a full substitution | 739 | // now we find out if the upgrade of the building is a full substitution |
3002 | 597 | // (produces all wares as current one) | 740 | // (produces all wares as current one) |
3003 | @@ -607,10 +750,10 @@ | |||
3004 | 607 | } | 750 | } |
3005 | 608 | // now testing outputs of current building | 751 | // now testing outputs of current building |
3006 | 609 | // and comparing | 752 | // and comparing |
3008 | 610 | bo.upgrade_substitutes = true; | 753 | bo.set_is(BuildingAttribute::kUpgradeSubstitutes); |
3009 | 611 | for (DescriptionIndex ware : bo.outputs) { | 754 | for (DescriptionIndex ware : bo.outputs) { |
3010 | 612 | if (enh_outputs.count(ware) == 0) { | 755 | if (enh_outputs.count(ware) == 0) { |
3012 | 613 | bo.upgrade_substitutes = false; | 756 | bo.unset_is(BuildingAttribute::kUpgradeSubstitutes); |
3013 | 614 | break; | 757 | break; |
3014 | 615 | } | 758 | } |
3015 | 616 | } | 759 | } |
3016 | @@ -620,40 +763,50 @@ | |||
3017 | 620 | for (const DescriptionIndex& ware : bo.outputs) { | 763 | for (const DescriptionIndex& ware : bo.outputs) { |
3018 | 621 | cur_outputs.insert(ware); | 764 | cur_outputs.insert(ware); |
3019 | 622 | } | 765 | } |
3021 | 623 | bo.upgrade_extends = false; | 766 | // Does upgraded building produce any different outputs? |
3022 | 624 | for (DescriptionIndex ware : enh_outputs) { | 767 | for (DescriptionIndex ware : enh_outputs) { |
3023 | 625 | if (cur_outputs.count(ware) == 0) { | 768 | if (cur_outputs.count(ware) == 0) { |
3025 | 626 | bo.upgrade_extends = true; | 769 | bo.set_is(BuildingAttribute::kUpgradeExtends); |
3026 | 627 | break; | 770 | break; |
3027 | 628 | } | 771 | } |
3028 | 629 | } | 772 | } |
3029 | 630 | } | 773 | } |
3030 | 631 | 774 | ||
3031 | 632 | // now we identify producers of critical build materials | 775 | // now we identify producers of critical build materials |
3032 | 633 | // hardwood now | ||
3033 | 634 | for (DescriptionIndex ware : bo.outputs) { | 776 | for (DescriptionIndex ware : bo.outputs) { |
3040 | 635 | // iterating over wares subsitutes | 777 | // building material except for trivial material |
3041 | 636 | if (tribe_->ware_index("wood") == ware || tribe_->ware_index("blackwood") == ware || | 778 | if (tribe_->is_construction_material(ware) && |
3042 | 637 | tribe_->ware_index("marble") == ware || tribe_->ware_index("planks") == ware) { | 779 | !(ware == tribe_->rawlog() || ware == tribe_->granite())) { |
3043 | 638 | bo.produces_building_material = true; | 780 | bo.set_is(BuildingAttribute::kBuildingMatProducer); |
3044 | 639 | } | 781 | if (bo.type == BuildingObserver::Type::kMine) { |
3045 | 640 | } | 782 | has_critical_mines = true; |
3046 | 783 | mines_per_type[bo.mines].is_critical = true; | ||
3047 | 784 | } | ||
3048 | 785 | } | ||
3049 | 786 | } | ||
3050 | 787 | |||
3051 | 788 | for (const auto& temp_buildcosts : prod.buildcost()) { | ||
3052 | 789 | // building material except for trivial material | ||
3053 | 790 | if (tribe_->is_construction_material(temp_buildcosts.first) && | ||
3054 | 791 | !(temp_buildcosts.first == tribe_->rawlog() || | ||
3055 | 792 | temp_buildcosts.first == tribe_->granite())) { | ||
3056 | 793 | bo.critical_building_material.push_back(temp_buildcosts.first); | ||
3057 | 794 | } | ||
3058 | 795 | } | ||
3059 | 796 | |||
3060 | 641 | continue; | 797 | continue; |
3061 | 642 | } | 798 | } |
3062 | 643 | 799 | ||
3063 | 644 | // now for every military building, we fill critical_building_material vector | 800 | // now for every military building, we fill critical_building_material vector |
3064 | 645 | // with critical construction wares | 801 | // with critical construction wares |
3065 | 646 | // non critical are excluded (see below) | ||
3066 | 647 | if (bld.type() == MapObjectType::MILITARYSITE) { | 802 | if (bld.type() == MapObjectType::MILITARYSITE) { |
3067 | 648 | bo.type = BuildingObserver::Type::kMilitarysite; | 803 | bo.type = BuildingObserver::Type::kMilitarysite; |
3068 | 649 | const MilitarySiteDescr& milit = dynamic_cast<const MilitarySiteDescr&>(bld); | 804 | const MilitarySiteDescr& milit = dynamic_cast<const MilitarySiteDescr&>(bld); |
3069 | 650 | for (const auto& temp_buildcosts : milit.buildcost()) { | 805 | for (const auto& temp_buildcosts : milit.buildcost()) { |
3074 | 651 | // bellow are non-critical wares (well, various types of wood) | 806 | // Below are non-critical wares (well, various types of wood) |
3075 | 652 | if (tribe_->ware_index("log") == temp_buildcosts.first || | 807 | if (temp_buildcosts.first == tribe_->rawlog() || |
3076 | 653 | tribe_->ware_index("blackwood") == temp_buildcosts.first || | 808 | temp_buildcosts.first == tribe_->refinedlog()) |
3073 | 654 | tribe_->ware_index("planks") == temp_buildcosts.first) | ||
3077 | 655 | continue; | 809 | continue; |
3078 | 656 | |||
3079 | 657 | bo.critical_building_material.push_back(temp_buildcosts.first); | 810 | bo.critical_building_material.push_back(temp_buildcosts.first); |
3080 | 658 | } | 811 | } |
3081 | 659 | continue; | 812 | continue; |
3082 | @@ -666,6 +819,8 @@ | |||
3083 | 666 | 819 | ||
3084 | 667 | if (bld.type() == MapObjectType::TRAININGSITE) { | 820 | if (bld.type() == MapObjectType::TRAININGSITE) { |
3085 | 668 | bo.type = BuildingObserver::Type::kTrainingsite; | 821 | bo.type = BuildingObserver::Type::kTrainingsite; |
3086 | 822 | bo.max_trainingsites_proportion = bh.trainingsites_max_percent(); | ||
3087 | 823 | assert(bo.max_trainingsites_proportion <= 100); | ||
3088 | 669 | const TrainingSiteDescr& train = dynamic_cast<const TrainingSiteDescr&>(bld); | 824 | const TrainingSiteDescr& train = dynamic_cast<const TrainingSiteDescr&>(bld); |
3089 | 670 | for (const auto& temp_input : train.input_wares()) { | 825 | for (const auto& temp_input : train.input_wares()) { |
3090 | 671 | bo.inputs.push_back(temp_input.first); | 826 | bo.inputs.push_back(temp_input.first); |
3091 | @@ -678,19 +833,17 @@ | |||
3092 | 678 | bo.substitute_inputs.insert(temp_input.first); | 833 | bo.substitute_inputs.insert(temp_input.first); |
3093 | 679 | } | 834 | } |
3094 | 680 | 835 | ||
3095 | 836 | // Creating vector with critical material, to be used to discourage | ||
3096 | 837 | // building of new sites if ware is lacking | ||
3097 | 681 | for (const auto& temp_buildcosts : train.buildcost()) { | 838 | for (const auto& temp_buildcosts : train.buildcost()) { |
3102 | 682 | // critical wares for trainingsites | 839 | // building material except for trivial material |
3103 | 683 | if (tribe_->ware_index("spidercloth") == temp_buildcosts.first || | 840 | if (!(temp_buildcosts.first == tribe_->rawlog() || |
3104 | 684 | tribe_->ware_index("gold") == temp_buildcosts.first || | 841 | temp_buildcosts.first == tribe_->refinedlog() || |
3105 | 685 | tribe_->ware_index("grout") == temp_buildcosts.first) { | 842 | temp_buildcosts.first == tribe_->granite())) { |
3106 | 686 | bo.critical_building_material.push_back(temp_buildcosts.first); | 843 | bo.critical_building_material.push_back(temp_buildcosts.first); |
3107 | 687 | } | 844 | } |
3108 | 688 | } | 845 | } |
3109 | 689 | } | 846 | } |
3110 | 690 | bo.trainingsite_type = bh.get_trainingsite_type(); | ||
3111 | 691 | // it would behave badly if no type was set | ||
3112 | 692 | // make sure all TS have its type set properly in conf files | ||
3113 | 693 | assert(bo.trainingsite_type != TrainingSiteType::kNoTS); | ||
3114 | 694 | continue; | 847 | continue; |
3115 | 695 | } | 848 | } |
3116 | 696 | 849 | ||
3117 | @@ -700,6 +853,16 @@ | |||
3118 | 700 | } | 853 | } |
3119 | 701 | } | 854 | } |
3120 | 702 | 855 | ||
3121 | 856 | // We must verify that some buildings has been identified | ||
3122 | 857 | // Also note that the AI assumes that some buildings are unique, if you want to | ||
3123 | 858 | // create e.g. two barracks or bakeries, the impact on the AI must be considered | ||
3124 | 859 | assert(count_buildings_with_attribute(BuildingAttribute::kBarracks) == 1); | ||
3125 | 860 | assert(count_buildings_with_attribute(BuildingAttribute::kBakery) == 1); | ||
3126 | 861 | assert(count_buildings_with_attribute(BuildingAttribute::kLogRefiner) == 1); | ||
3127 | 862 | assert(count_buildings_with_attribute(BuildingAttribute::kIronMine) >= 1); | ||
3128 | 863 | // If there will be a tribe with more than 3 mines of the same type, just increase the number | ||
3129 | 864 | assert(count_buildings_with_attribute(BuildingAttribute::kIronMine) <= 3); | ||
3130 | 865 | |||
3131 | 703 | // atlanteans they consider water as a resource | 866 | // atlanteans they consider water as a resource |
3132 | 704 | // (together with mines, rocks and wood) | 867 | // (together with mines, rocks and wood) |
3133 | 705 | if (tribe_->name() == "atlanteans") { | 868 | if (tribe_->name() == "atlanteans") { |
3134 | @@ -743,13 +906,21 @@ | |||
3135 | 743 | "check unbuildable fields")); | 906 | "check unbuildable fields")); |
3136 | 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), |
3137 | 745 | SchedulerTaskId::kWareReview, 9, "wares review")); | 908 | SchedulerTaskId::kWareReview, 9, "wares review")); |
3139 | 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), |
3140 | 747 | SchedulerTaskId::kPrintStats, 9, "print statistics")); | 910 | SchedulerTaskId::kPrintStats, 9, "print statistics")); |
3141 | 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), |
3142 | 749 | SchedulerTaskId::kCountMilitaryVacant, 2, | 912 | SchedulerTaskId::kCountMilitaryVacant, 2, |
3143 | 750 | "count military vacant")); | 913 | "count military vacant")); |
3144 | 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), |
3145 | 752 | SchedulerTaskId::kCheckEnemySites, 6, "check enemy sites")); | 915 | SchedulerTaskId::kCheckEnemySites, 6, "check enemy sites")); |
3146 | 916 | if (kAITrainingMode) { | ||
3147 | 917 | taskPool.push_back(SchedulerTask(std::max<uint32_t>(gametime, 10 * 1000), | ||
3148 | 918 | SchedulerTaskId::kManagementUpdate, 8, "reviewing")); | ||
3149 | 919 | } | ||
3150 | 920 | taskPool.push_back(SchedulerTask(std::max<uint32_t>(gametime, 9 * 1000), | ||
3151 | 921 | SchedulerTaskId::kUpdateStats, 6, "update player stats")); | ||
3152 | 922 | taskPool.push_back(SchedulerTask( | ||
3153 | 923 | std::max<uint32_t>(gametime, 10 * 1000), SchedulerTaskId::kUpdateStats, 15, "review")); | ||
3154 | 753 | 924 | ||
3155 | 754 | Map& map = game().map(); | 925 | Map& map = game().map(); |
3156 | 755 | 926 | ||
3157 | @@ -821,7 +992,8 @@ | |||
3158 | 821 | 992 | ||
3159 | 822 | // blocking space consumers vicinity (when reloading a game) | 993 | // blocking space consumers vicinity (when reloading a game) |
3160 | 823 | for (const ProductionSiteObserver& ps_obs : productionsites) { | 994 | for (const ProductionSiteObserver& ps_obs : productionsites) { |
3162 | 824 | if (ps_obs.bo->space_consumer && !ps_obs.bo->plants_trees) { | 995 | if (ps_obs.bo->is(BuildingAttribute::kSpaceConsumer) && |
3163 | 996 | !ps_obs.bo->is(BuildingAttribute::kRanger)) { | ||
3164 | 825 | MapRegion<Area<FCoords>> mr( | 997 | MapRegion<Area<FCoords>> mr( |
3165 | 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)); |
3166 | 827 | do { | 999 | do { |
3167 | @@ -830,45 +1002,19 @@ | |||
3168 | 830 | } | 1002 | } |
3169 | 831 | } | 1003 | } |
3170 | 832 | 1004 | ||
3209 | 833 | // The data struct below is owned by Player object, the purpose is to have them saved therein | 1005 | // printing identified basic buildings if we are in the basic economy mode |
3210 | 834 | persistent_data = player_->get_mutable_ai_persistent_state(); | 1006 | basic_economy_established = persistent_data->remaining_basic_buildings.empty(); |
3211 | 835 | 1007 | if (!basic_economy_established) { | |
3212 | 836 | if (persistent_data->initialized == kFalse) { | 1008 | log("%2d: Initializing in the basic economy mode, required buildings:\n", player_number()); |
3213 | 837 | // As all data are initialized without given values, they must be populated with reasonable | 1009 | for (auto bb : persistent_data->remaining_basic_buildings) { |
3214 | 838 | // values first | 1010 | log(" %3d / %-25s- target %d\n", bb.first, get_building_observer(bb.first).name, |
3215 | 839 | persistent_data->colony_scan_area = kColonyScanStartArea; | 1011 | bb.second); |
3216 | 840 | persistent_data->trees_around_cutters = 0; | 1012 | } |
3179 | 841 | persistent_data->initialized = kTrue; | ||
3180 | 842 | persistent_data->last_attacked_player = std::numeric_limits<int16_t>::max(); | ||
3181 | 843 | persistent_data->expedition_start_time = kNoExpedition; | ||
3182 | 844 | persistent_data->ships_utilization = 200; | ||
3183 | 845 | persistent_data->no_more_expeditions = kFalse; | ||
3184 | 846 | persistent_data->target_military_score = 0; | ||
3185 | 847 | persistent_data->least_military_score = 100; | ||
3186 | 848 | persistent_data->ai_personality_military_loneliness = std::rand() % 5 * 30 - 60; | ||
3187 | 849 | persistent_data->ai_personality_attack_margin = std::max(std::rand() % 20 - 5, 0); | ||
3188 | 850 | persistent_data->ai_productionsites_ratio = std::rand() % 5 + 7; | ||
3189 | 851 | persistent_data->ai_personality_wood_difference = std::rand() % 40 - 20; | ||
3190 | 852 | persistent_data->ai_personality_early_militarysites = std::rand() % 20 + 20; | ||
3191 | 853 | persistent_data->last_soldier_trained = kNever; | ||
3192 | 854 | } else if (persistent_data->initialized == kTrue) { | ||
3193 | 855 | // Doing some consistency checks | ||
3194 | 856 | check_range<uint32_t>( | ||
3195 | 857 | persistent_data->expedition_start_time, gametime, "expedition_start_time"); | ||
3196 | 858 | check_range<uint16_t>(persistent_data->ships_utilization, 0, 10000, "ships_utilization_"); | ||
3197 | 859 | check_range<int16_t>(persistent_data->ai_personality_military_loneliness, -60, 60, | ||
3198 | 860 | "ai_personality_military_loneliness"); | ||
3199 | 861 | check_range<int32_t>( | ||
3200 | 862 | persistent_data->ai_personality_attack_margin, 15, "ai_personality_attack_margin"); | ||
3201 | 863 | check_range<uint32_t>( | ||
3202 | 864 | persistent_data->ai_productionsites_ratio, 5, 15, "ai_productionsites_ratio"); | ||
3203 | 865 | check_range<int32_t>(persistent_data->ai_personality_wood_difference, -20, 19, | ||
3204 | 866 | "ai_personality_wood_difference"); | ||
3205 | 867 | check_range<uint32_t>(persistent_data->ai_personality_early_militarysites, 20, 40, | ||
3206 | 868 | "ai_personality_early_militarysites"); | ||
3207 | 869 | } else { | ||
3208 | 870 | throw wexception("Corrupted AI data"); | ||
3217 | 871 | } | 1013 | } |
3218 | 1014 | assert(persistent_data->remaining_basic_buildings.size() == | ||
3219 | 1015 | persistent_data->remaining_buildings_size); | ||
3220 | 1016 | |||
3221 | 1017 | update_player_stat(gametime); | ||
3222 | 872 | 1018 | ||
3223 | 873 | // Initialise the max duration of a single ship's expedition | 1019 | // Initialise the max duration of a single ship's expedition |
3224 | 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(); |
3225 | @@ -893,6 +1039,18 @@ | |||
3226 | 893 | // Current gametime is better then 'kNoExpedition' | 1039 | // Current gametime is better then 'kNoExpedition' |
3227 | 894 | persistent_data->expedition_start_time = gametime; | 1040 | persistent_data->expedition_start_time = gametime; |
3228 | 895 | } | 1041 | } |
3229 | 1042 | |||
3230 | 1043 | // just to be sure we have iron mines identified | ||
3231 | 1044 | assert(iron_ore_id != INVALID_INDEX); | ||
3232 | 1045 | |||
3233 | 1046 | productionsites_ratio_ = management_data.get_military_number_at(86) / 10 + 12; | ||
3234 | 1047 | |||
3235 | 1048 | // Just to be initialized | ||
3236 | 1049 | soldier_status_ = SoldiersStatus::kEnough; | ||
3237 | 1050 | vacant_mil_positions_average_ = 0; | ||
3238 | 1051 | spots_avail.resize(4); | ||
3239 | 1052 | trees_nearby_treshold_ = 3 + std::abs(management_data.get_military_number_at(121)) / 2; | ||
3240 | 1053 | last_road_dismantled_ = 0; | ||
3241 | 896 | } | 1054 | } |
3242 | 897 | 1055 | ||
3243 | 898 | /** | 1056 | /** |
3244 | @@ -1022,27 +1180,66 @@ | |||
3245 | 1022 | } | 1180 | } |
3246 | 1023 | 1181 | ||
3247 | 1024 | /// Updates one buildable field | 1182 | /// Updates one buildable field |
3249 | 1025 | void DefaultAI::update_buildable_field(BuildableField& field, uint16_t range, bool military) { | 1183 | void DefaultAI::update_buildable_field(BuildableField& field) { |
3250 | 1026 | // look if there is any unowned land nearby | 1184 | // look if there is any unowned land nearby |
3251 | 1027 | Map& map = game().map(); | 1185 | Map& map = game().map(); |
3252 | 1028 | const uint32_t gametime = game().get_gametime(); | 1186 | const uint32_t gametime = game().get_gametime(); |
3253 | 1029 | FindNodeUnownedWalkable find_unowned_walkable(player_, game()); | 1187 | FindNodeUnownedWalkable find_unowned_walkable(player_, game()); |
3254 | 1188 | FindEnemyNodeWalkable find_enemy_owned_walkable(player_, game()); | ||
3255 | 1189 | FindNodeUnownedBuildable find_unowned_buildable(player_, game()); | ||
3256 | 1030 | FindNodeUnownedMineable find_unowned_mines_pots(player_, game()); | 1190 | FindNodeUnownedMineable find_unowned_mines_pots(player_, game()); |
3257 | 1191 | FindNodeUnownedMineable find_unowned_iron_mines(player_, game(), iron_ore_id); | ||
3258 | 1192 | FindNodeAllyOwned find_ally(player_, game(), player_number()); | ||
3259 | 1031 | PlayerNumber const pn = player_->player_number(); | 1193 | PlayerNumber const pn = player_->player_number(); |
3260 | 1032 | const World& world = game().world(); | 1194 | const World& world = game().world(); |
3269 | 1033 | field.unowned_land_nearby = | 1195 | |
3270 | 1034 | map.find_fields(Area<FCoords>(field.coords, range), nullptr, find_unowned_walkable); | 1196 | constexpr uint16_t kProductionArea = 6; |
3271 | 1035 | FindNodeAllyOwned find_ally(player_, game(), player_number()); | 1197 | constexpr uint16_t kBuildableSpotsCheckArea = 10; |
3272 | 1036 | const int32_t AllyOwnedFields = | 1198 | constexpr uint16_t kEnemyCheckArea = 16; |
3273 | 1037 | map.find_fields(Area<FCoords>(field.coords, 3), nullptr, find_ally); | 1199 | const uint16_t ms_enemy_check_area = |
3274 | 1038 | 1200 | kEnemyCheckArea + std::abs(management_data.get_military_number_at(75)) / 10; | |
3275 | 1039 | field.near_border = false; | 1201 | constexpr uint16_t kDistantResourcesArea = 20; |
3276 | 1040 | if (AllyOwnedFields > 0) { | 1202 | |
3277 | 1203 | uint16_t actual_enemy_check_area = kEnemyCheckArea; | ||
3278 | 1204 | field.is_militarysite = false; | ||
3279 | 1205 | if (field.coords.field->get_immovable()) { | ||
3280 | 1206 | if (field.coords.field->get_immovable()->descr().type() == | ||
3281 | 1207 | Widelands::MapObjectType::MILITARYSITE) { | ||
3282 | 1208 | field.is_militarysite = true; | ||
3283 | 1209 | actual_enemy_check_area = ms_enemy_check_area; | ||
3284 | 1210 | } | ||
3285 | 1211 | } | ||
3286 | 1212 | |||
3287 | 1213 | field.unowned_land_nearby = map.find_fields( | ||
3288 | 1214 | Area<FCoords>(field.coords, actual_enemy_check_area), nullptr, find_unowned_walkable); | ||
3289 | 1215 | |||
3290 | 1216 | field.enemy_owned_land_nearby = map.find_fields( | ||
3291 | 1217 | Area<FCoords>(field.coords, actual_enemy_check_area), nullptr, find_enemy_owned_walkable); | ||
3292 | 1218 | |||
3293 | 1219 | field.nearest_buildable_spot_nearby = std::numeric_limits<uint16_t>::max(); | ||
3294 | 1220 | if (field.unowned_land_nearby > 0) { | ||
3295 | 1221 | std::vector<Coords> found_buildable_fields; | ||
3296 | 1222 | |||
3297 | 1223 | field.unowned_buildable_spots_nearby = | ||
3298 | 1224 | map.find_fields(Area<FCoords>(field.coords, kBuildableSpotsCheckArea), | ||
3299 | 1225 | &found_buildable_fields, find_unowned_buildable); | ||
3300 | 1226 | // Now iterate over fields to get nearest one | ||
3301 | 1227 | for (auto& coords : found_buildable_fields) { | ||
3302 | 1228 | const uint32_t cur_distance = map.calc_distance(coords, field.coords); | ||
3303 | 1229 | if (cur_distance < field.nearest_buildable_spot_nearby) { | ||
3304 | 1230 | field.nearest_buildable_spot_nearby = cur_distance; | ||
3305 | 1231 | } | ||
3306 | 1232 | } | ||
3307 | 1233 | } else { | ||
3308 | 1234 | field.unowned_buildable_spots_nearby = 0; | ||
3309 | 1235 | } | ||
3310 | 1236 | |||
3311 | 1237 | // Is this near the border? Get rid of fields owned by ally | ||
3312 | 1238 | if (map.find_fields(Area<FCoords>(field.coords, 3), nullptr, find_ally) || | ||
3313 | 1239 | map.find_fields(Area<FCoords>(field.coords, 3), nullptr, find_unowned_walkable)) { | ||
3314 | 1041 | field.near_border = true; | 1240 | field.near_border = true; |
3319 | 1042 | } else if (field.unowned_land_nearby > 0) { | 1241 | } else { |
3320 | 1043 | if (map.find_fields(Area<FCoords>(field.coords, 4), nullptr, find_unowned_walkable) > 0) { | 1242 | field.near_border = false; |
3317 | 1044 | field.near_border = true; | ||
3318 | 1045 | } | ||
3321 | 1046 | } | 1243 | } |
3322 | 1047 | 1244 | ||
3323 | 1048 | // are we going to count resources now? | 1245 | // are we going to count resources now? |
3324 | @@ -1054,26 +1251,39 @@ | |||
3325 | 1054 | field.last_resources_check_time = gametime; | 1251 | field.last_resources_check_time = gametime; |
3326 | 1055 | } | 1252 | } |
3327 | 1056 | 1253 | ||
3334 | 1057 | // to save some CPU | 1254 | // testing mines |
3335 | 1058 | if (mines_.size() > 8 && !resource_count_now) { | 1255 | if (resource_count_now) { |
3336 | 1059 | field.unowned_mines_spots_nearby = 0; | 1256 | uint32_t close_mines = map.find_fields( |
3337 | 1060 | } else { | 1257 | Area<FCoords>(field.coords, kProductionArea), nullptr, find_unowned_mines_pots); |
3332 | 1061 | uint32_t close_mines = | ||
3333 | 1062 | map.find_fields(Area<FCoords>(field.coords, 4), nullptr, find_unowned_mines_pots); | ||
3338 | 1063 | uint32_t distant_mines = | 1258 | uint32_t distant_mines = |
3340 | 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, |
3341 | 1260 | |||
3342 | 1065 | find_unowned_mines_pots); | 1261 | find_unowned_mines_pots); |
3343 | 1066 | distant_mines = distant_mines - close_mines; | 1262 | distant_mines = distant_mines - close_mines; |
3344 | 1067 | field.unowned_mines_spots_nearby = 4 * close_mines + distant_mines / 2; | 1263 | field.unowned_mines_spots_nearby = 4 * close_mines + distant_mines / 2; |
3345 | 1068 | if (distant_mines > 0) { | 1264 | if (distant_mines > 0) { |
3346 | 1069 | field.unowned_mines_spots_nearby += 15; | 1265 | field.unowned_mines_spots_nearby += 15; |
3347 | 1070 | } | 1266 | } |
3348 | 1267 | if (field.unowned_mines_spots_nearby > 0 && | ||
3349 | 1268 | // for performance considerations we count iron nodes only if we have less than 2 iron | ||
3350 | 1269 | // mines now... | ||
3351 | 1270 | (mines_per_type[iron_ore_id].in_construction + mines_per_type[iron_ore_id].finished) <= | ||
3352 | 1271 | 1) { | ||
3353 | 1272 | // counting iron mines, if we have less than two iron mines | ||
3354 | 1273 | field.unowned_iron_mines_nearby = map.find_fields( | ||
3355 | 1274 | Area<FCoords>(field.coords, kDistantResourcesArea), nullptr, find_unowned_iron_mines); | ||
3356 | 1275 | } else { | ||
3357 | 1276 | field.unowned_iron_mines_nearby = 0; | ||
3358 | 1277 | } | ||
3359 | 1071 | } | 1278 | } |
3360 | 1072 | 1279 | ||
3361 | 1073 | // identifying portspace fields | 1280 | // identifying portspace fields |
3363 | 1074 | if (!field.is_portspace) { // if we know it, no need to do it once more | 1281 | if (field.is_portspace == |
3364 | 1282 | Widelands::ExtendedBool::kUnset) { // if we know it, no need to do it once more | ||
3365 | 1075 | if (player_->get_buildcaps(field.coords) & BUILDCAPS_PORT) { | 1283 | if (player_->get_buildcaps(field.coords) & BUILDCAPS_PORT) { |
3367 | 1076 | field.is_portspace = true; | 1284 | field.is_portspace = ExtendedBool::kTrue; |
3368 | 1285 | } else { | ||
3369 | 1286 | field.is_portspace = ExtendedBool::kFalse; | ||
3370 | 1077 | } | 1287 | } |
3371 | 1078 | } | 1288 | } |
3372 | 1079 | 1289 | ||
3373 | @@ -1090,15 +1300,20 @@ | |||
3374 | 1090 | } | 1300 | } |
3375 | 1091 | 1301 | ||
3376 | 1092 | // testing if a port is nearby, such field will get a priority boost | 1302 | // testing if a port is nearby, such field will get a priority boost |
3386 | 1093 | uint16_t nearest_distance = std::numeric_limits<uint16_t>::max(); | 1303 | if (resource_count_now) { // misusing a bit |
3387 | 1094 | for (const WarehouseSiteObserver& wh_obs : warehousesites) { | 1304 | uint16_t nearest_distance = std::numeric_limits<uint16_t>::max(); |
3388 | 1095 | const uint16_t actual_distance = map.calc_distance(field.coords, wh_obs.site->get_position()); | 1305 | for (const WarehouseSiteObserver& wh_obs : warehousesites) { |
3389 | 1096 | nearest_distance = std::min(nearest_distance, actual_distance); | 1306 | if (wh_obs.bo->is(BuildingAttribute::kPort)) { |
3390 | 1097 | } | 1307 | const uint16_t actual_distance = |
3391 | 1098 | if (nearest_distance < 15) { | 1308 | map.calc_distance(field.coords, wh_obs.site->get_position()); |
3392 | 1099 | field.port_nearby = true; | 1309 | nearest_distance = std::min(nearest_distance, actual_distance); |
3393 | 1100 | } else { | 1310 | } |
3394 | 1101 | field.port_nearby = false; | 1311 | } |
3395 | 1312 | if (nearest_distance < 15) { | ||
3396 | 1313 | field.port_nearby = true; | ||
3397 | 1314 | } else { | ||
3398 | 1315 | field.port_nearby = false; | ||
3399 | 1316 | } | ||
3400 | 1102 | } | 1317 | } |
3401 | 1103 | 1318 | ||
3402 | 1104 | // testing fields in radius 1 to find biggest buildcaps. | 1319 | // testing fields in radius 1 to find biggest buildcaps. |
3403 | @@ -1115,119 +1330,63 @@ | |||
3404 | 1115 | 1330 | ||
3405 | 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); |
3406 | 1117 | 1332 | ||
3510 | 1118 | // collect information about resources in the area | 1333 | // Testing surface water (once only) |
3511 | 1119 | std::vector<ImmovableFound> immovables; | 1334 | // TODO(GunChleoc): We can change the terrain by scripting, so we should work with notifications |
3512 | 1120 | // Search in a radius of range | 1335 | // here. |
3513 | 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 |
3514 | 1122 | 1337 | // currently only | |
3515 | 1123 | // Is this a general update or just for military consideration | 1338 | // used in the Atlantean scenario. |
3516 | 1124 | // (second is used in check_militarysites) | 1339 | if (field.water_nearby == kUncalculated) { |
3517 | 1125 | if (!military) { | 1340 | assert(field.open_water_nearby == kUncalculated); |
3518 | 1126 | int32_t const tree_attr = MapObjectDescr::get_attribute_id("tree"); | 1341 | |
3519 | 1127 | field.preferred = false; | 1342 | FindNodeWater find_water(game().world()); |
3520 | 1128 | field.enemy_nearby = false; | 1343 | field.water_nearby = |
3521 | 1129 | field.area_military_capacity = 0; | 1344 | map.find_fields(Area<FCoords>(field.coords, kProductionArea), nullptr, find_water); |
3522 | 1130 | field.military_loneliness = 1000; // instead of floats(v- | 1345 | |
3523 | 1131 | field.area_military_presence = 0; | 1346 | if (field.water_nearby > 0) { |
3524 | 1132 | field.military_stationed = 0; | 1347 | FindNodeOpenWater find_open_water(game().world()); |
3525 | 1133 | field.unconnected_nearby = false; | 1348 | field.open_water_nearby = |
3526 | 1134 | field.trees_nearby = 0; | 1349 | map.find_fields(Area<FCoords>(field.coords, kProductionArea), nullptr, find_open_water); |
3527 | 1135 | field.space_consumers_nearby = 0; | 1350 | } |
3528 | 1136 | field.rangers_nearby = 0; | 1351 | |
3529 | 1137 | field.producers_nearby.clear(); | 1352 | if (resource_necessity_water_needed_) { // for atlanteans |
3530 | 1138 | field.producers_nearby.resize(wares.size()); | 1353 | field.distant_water = map.find_fields(Area<FCoords>(field.coords, kDistantResourcesArea), |
3531 | 1139 | field.consumers_nearby.clear(); | 1354 | nullptr, find_water) - |
3532 | 1140 | field.consumers_nearby.resize(wares.size()); | 1355 | field.water_nearby; |
3533 | 1141 | field.supporters_nearby.clear(); | 1356 | assert(field.open_water_nearby <= field.water_nearby); |
3534 | 1142 | field.supporters_nearby.resize(wares.size()); | 1357 | } |
3535 | 1143 | std::vector<Coords> resource_list; | 1358 | } |
3536 | 1144 | std::vector<Bob*> critters_list; | 1359 | |
3537 | 1145 | 1360 | FCoords fse; | |
3538 | 1146 | if (field.water_nearby == kUncalculated) { | 1361 | map.get_neighbour(field.coords, WALK_SE, &fse); |
3539 | 1147 | assert(field.open_water_nearby == kUncalculated); | 1362 | field.preferred = false; |
3540 | 1148 | 1363 | if (BaseImmovable const* const imm = fse.field->get_immovable()) { | |
3541 | 1149 | FindNodeWater find_water(game().world()); | 1364 | if (dynamic_cast<Flag const*>(imm) || |
3542 | 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))) { |
3543 | 1151 | 1366 | field.preferred = true; | |
3544 | 1152 | if (field.water_nearby > 0) { | 1367 | } |
3545 | 1153 | FindNodeOpenWater find_open_water(game().world()); | 1368 | } |
3546 | 1154 | field.open_water_nearby = | 1369 | |
3547 | 1155 | map.find_fields(Area<FCoords>(field.coords, 5), nullptr, find_open_water); | 1370 | // counting fields with fish |
3548 | 1156 | } | 1371 | if (field.water_nearby > 0 && (field.fish_nearby == kUncalculated || resource_count_now)) { |
3549 | 1157 | 1372 | field.fish_nearby = map.find_fields(Area<FCoords>(field.coords, kProductionArea), nullptr, | |
3550 | 1158 | if (resource_necessity_water_needed_) { // for atlanteans | 1373 | FindNodeResource(world.get_resource("fish"))); |
3551 | 1159 | field.distant_water = | 1374 | } |
3552 | 1160 | map.find_fields(Area<FCoords>(field.coords, 14), nullptr, find_water) - | 1375 | |
3553 | 1161 | field.water_nearby; | 1376 | // Counting resources that do not change fast |
3554 | 1162 | assert(field.open_water_nearby <= field.water_nearby); | 1377 | if (resource_count_now) { |
3555 | 1163 | } | 1378 | // Counting fields with critters (game) |
3556 | 1164 | } | 1379 | field.critters_nearby = |
3557 | 1165 | 1380 | map.find_bobs(Area<FCoords>(field.coords, kProductionArea), nullptr, FindBobCritter()); | |
3455 | 1166 | // counting fields with fish | ||
3456 | 1167 | if (field.water_nearby > 0 && (field.fish_nearby == kUncalculated || resource_count_now)) { | ||
3457 | 1168 | map.find_fields(Area<FCoords>(field.coords, 6), &resource_list, | ||
3458 | 1169 | FindNodeResource(world.get_resource("fish"))); | ||
3459 | 1170 | field.fish_nearby = resource_list.size(); | ||
3460 | 1171 | } | ||
3461 | 1172 | |||
3462 | 1173 | // counting fields with critters (game) | ||
3463 | 1174 | // not doing this always, this does not change fast | ||
3464 | 1175 | if (resource_count_now) { | ||
3465 | 1176 | map.find_bobs(Area<FCoords>(field.coords, 6), &critters_list, FindBobCritter()); | ||
3466 | 1177 | field.critters_nearby = critters_list.size(); | ||
3467 | 1178 | } | ||
3468 | 1179 | |||
3469 | 1180 | FCoords fse; | ||
3470 | 1181 | map.get_neighbour(field.coords, WALK_SE, &fse); | ||
3471 | 1182 | |||
3472 | 1183 | if (BaseImmovable const* const imm = fse.field->get_immovable()) { | ||
3473 | 1184 | if (dynamic_cast<Flag const*>(imm) || | ||
3474 | 1185 | (dynamic_cast<Road const*>(imm) && (fse.field->nodecaps() & BUILDCAPS_FLAG))) { | ||
3475 | 1186 | field.preferred = true; | ||
3476 | 1187 | } | ||
3477 | 1188 | } | ||
3478 | 1189 | |||
3479 | 1190 | for (uint32_t i = 0; i < immovables.size(); ++i) { | ||
3480 | 1191 | const BaseImmovable& base_immovable = *immovables.at(i).object; | ||
3481 | 1192 | |||
3482 | 1193 | if (upcast(PlayerImmovable const, player_immovable, &base_immovable)) { | ||
3483 | 1194 | |||
3484 | 1195 | // TODO(unknown): Only continue; if this is an opposing site | ||
3485 | 1196 | // allied sites should be counted for military influence | ||
3486 | 1197 | if (player_immovable->owner().player_number() != pn) { | ||
3487 | 1198 | if (player_->is_hostile(player_immovable->owner())) { | ||
3488 | 1199 | field.enemy_nearby = true; | ||
3489 | 1200 | } | ||
3490 | 1201 | |||
3491 | 1202 | continue; | ||
3492 | 1203 | } | ||
3493 | 1204 | // here we identify the buiding (including expected building if constructionsite) | ||
3494 | 1205 | // and calculate some statistics about nearby buildings | ||
3495 | 1206 | if (upcast(ProductionSite const, productionsite, player_immovable)) { | ||
3496 | 1207 | BuildingObserver& bo = get_building_observer(productionsite->descr().name().c_str()); | ||
3497 | 1208 | consider_productionsite_influence(field, immovables.at(i).coords, bo); | ||
3498 | 1209 | } | ||
3499 | 1210 | if (upcast(ConstructionSite const, constructionsite, player_immovable)) { | ||
3500 | 1211 | const BuildingDescr& target_descr = constructionsite->building(); | ||
3501 | 1212 | BuildingObserver& bo = get_building_observer(target_descr.name().c_str()); | ||
3502 | 1213 | consider_productionsite_influence(field, immovables.at(i).coords, bo); | ||
3503 | 1214 | } | ||
3504 | 1215 | } | ||
3505 | 1216 | |||
3506 | 1217 | if (immovables.at(i).object->has_attribute(tree_attr)) { | ||
3507 | 1218 | ++field.trees_nearby; | ||
3508 | 1219 | } | ||
3509 | 1220 | } | ||
3558 | 1221 | 1381 | ||
3559 | 1222 | // Rocks are not renewable, we will count them only if previous state is nonzero | 1382 | // Rocks are not renewable, we will count them only if previous state is nonzero |
3568 | 1223 | if (field.rocks_nearby > 0 && resource_count_now) { | 1383 | if (field.rocks_nearby > 0) { |
3569 | 1224 | 1384 | field.rocks_nearby = map.find_immovables( | |
3570 | 1225 | field.rocks_nearby = | 1385 | Area<FCoords>(map.get_fcoords(field.coords), kProductionArea), nullptr, |
3571 | 1226 | map.find_immovables(Area<FCoords>(map.get_fcoords(field.coords), 6), nullptr, | 1386 | FindImmovableAttribute(MapObjectDescr::get_attribute_id("rocks"))); |
3572 | 1227 | FindImmovableAttribute(MapObjectDescr::get_attribute_id("rocks"))); | 1387 | |
3573 | 1228 | 1388 | // adding 5 if rocks found | |
3574 | 1229 | // adding 10 if rocks found | 1389 | field.rocks_nearby = (field.rocks_nearby > 0) ? field.rocks_nearby + 2 : 0; |
3567 | 1230 | field.rocks_nearby = (field.rocks_nearby > 0) ? field.rocks_nearby + 10 : 0; | ||
3575 | 1231 | } | 1390 | } |
3576 | 1232 | 1391 | ||
3577 | 1233 | // ground water is not renewable and its amount can only fall, we will count them only if | 1392 | // ground water is not renewable and its amount can only fall, we will count them only if |
3578 | @@ -1235,47 +1394,136 @@ | |||
3579 | 1235 | if (field.ground_water > 0) { | 1394 | if (field.ground_water > 0) { |
3580 | 1236 | field.ground_water = field.coords.field->get_resources_amount(); | 1395 | field.ground_water = field.coords.field->get_resources_amount(); |
3581 | 1237 | } | 1396 | } |
3589 | 1238 | } | 1397 | |
3590 | 1239 | 1398 | // Counting trees nearby | |
3591 | 1240 | // The following is done always (regardless of military or not) | 1399 | int32_t const tree_attr = MapObjectDescr::get_attribute_id("tree"); |
3592 | 1241 | 1400 | field.trees_nearby = | |
3593 | 1242 | // We get immovables with higher radius | 1401 | map.find_immovables(Area<FCoords>(map.get_fcoords(field.coords), kProductionArea), nullptr, |
3594 | 1243 | immovables.clear(); | 1402 | FindImmovableAttribute(tree_attr)); |
3595 | 1244 | map.find_immovables(Area<FCoords>(field.coords, (range < 11) ? 11 : range), &immovables); | 1403 | } |
3596 | 1404 | |||
3597 | 1405 | // resetting some values | ||
3598 | 1406 | field.enemy_nearby = | ||
3599 | 1407 | (field.enemy_owned_land_nearby > std::abs(management_data.get_military_number_at(41) / 4)) ? | ||
3600 | 1408 | true : | ||
3601 | 1409 | false; | ||
3602 | 1410 | if (field.enemy_owned_land_nearby == 0) { | ||
3603 | 1411 | assert(!field.enemy_nearby); | ||
3604 | 1412 | } | ||
3605 | 1413 | |||
3606 | 1414 | // resetting a bunch of values for the field | ||
3607 | 1415 | field.ally_military_presence = 0; | ||
3608 | 1416 | field.area_military_capacity = 0; | ||
3609 | 1417 | field.consumers_nearby.clear(); | ||
3610 | 1418 | field.consumers_nearby.resize(wares.size()); | ||
3611 | 1419 | field.enemy_military_presence = 0; | ||
3612 | 1420 | field.enemy_military_sites = 0; | ||
3613 | 1421 | field.enemy_wh_nearby = false; | ||
3614 | 1422 | field.military_in_constr_nearby = 0; | ||
3615 | 1423 | field.military_loneliness = 1000; | ||
3616 | 1245 | field.military_stationed = 0; | 1424 | field.military_stationed = 0; |
3617 | 1246 | field.military_unstationed = 0; | 1425 | field.military_unstationed = 0; |
3622 | 1247 | field.military_in_constr_nearby = 0; | 1426 | field.own_military_presence = 0; |
3623 | 1248 | field.area_military_capacity = 0; | 1427 | field.own_non_military_nearby = 0; |
3624 | 1249 | field.military_loneliness = 1000; | 1428 | field.producers_nearby.clear(); |
3625 | 1250 | field.area_military_presence = 0; | 1429 | field.producers_nearby.resize(wares.size()); |
3626 | 1430 | field.rangers_nearby = 0; | ||
3627 | 1431 | field.space_consumers_nearby = 0; | ||
3628 | 1432 | field.supporters_nearby.clear(); | ||
3629 | 1433 | field.supporters_nearby.resize(wares.size()); | ||
3630 | 1251 | field.unconnected_nearby = false; | 1434 | field.unconnected_nearby = false; |
3631 | 1252 | 1435 | ||
3632 | 1436 | // collect information about productionsites nearby | ||
3633 | 1437 | std::vector<ImmovableFound> immovables; | ||
3634 | 1438 | // Search in a radius of range | ||
3635 | 1439 | map.find_immovables(Area<FCoords>(field.coords, kProductionArea + 2), &immovables); | ||
3636 | 1440 | |||
3637 | 1441 | // function seems to return duplicates, so we will use serial numbers to filter them out | ||
3638 | 1442 | std::set<uint32_t> unique_serials; | ||
3639 | 1443 | |||
3640 | 1444 | for (uint32_t i = 0; i < immovables.size(); ++i) { | ||
3641 | 1445 | const BaseImmovable& base_immovable = *immovables.at(i).object; | ||
3642 | 1446 | if (!unique_serials.insert(base_immovable.serial()).second) { | ||
3643 | 1447 | continue; // serial was not inserted in the set, so this is a duplicate | ||
3644 | 1448 | } | ||
3645 | 1449 | |||
3646 | 1450 | if (upcast(PlayerImmovable const, player_immovable, &base_immovable)) { | ||
3647 | 1451 | |||
3648 | 1452 | // TODO(unknown): Only continue if this is an opposing site | ||
3649 | 1453 | // allied sites should be counted for military influence | ||
3650 | 1454 | if (player_immovable->owner().player_number() != pn) { | ||
3651 | 1455 | continue; | ||
3652 | 1456 | } | ||
3653 | 1457 | // here we identify the buiding (including expected building if constructionsite) | ||
3654 | 1458 | // and calculate some statistics about nearby buildings | ||
3655 | 1459 | if (player_immovable->descr().type() == MapObjectType::PRODUCTIONSITE) { | ||
3656 | 1460 | BuildingObserver& bo = get_building_observer(player_immovable->descr().name().c_str()); | ||
3657 | 1461 | consider_productionsite_influence(field, immovables.at(i).coords, bo); | ||
3658 | 1462 | } else if (upcast(ConstructionSite const, constructionsite, player_immovable)) { | ||
3659 | 1463 | const BuildingDescr& target_descr = constructionsite->building(); | ||
3660 | 1464 | BuildingObserver& bo = get_building_observer(target_descr.name().c_str()); | ||
3661 | 1465 | consider_productionsite_influence(field, immovables.at(i).coords, bo); | ||
3662 | 1466 | } | ||
3663 | 1467 | } | ||
3664 | 1468 | } | ||
3665 | 1469 | |||
3666 | 1470 | // Now testing military aspects | ||
3667 | 1471 | immovables.clear(); | ||
3668 | 1472 | map.find_immovables(Area<FCoords>(field.coords, actual_enemy_check_area), &immovables); | ||
3669 | 1473 | |||
3670 | 1253 | // We are interested in unconnected immovables, but we must be also close to connected ones | 1474 | // We are interested in unconnected immovables, but we must be also close to connected ones |
3671 | 1254 | bool any_connected_imm = false; | 1475 | bool any_connected_imm = false; |
3672 | 1255 | bool any_unconnected_imm = false; | 1476 | bool any_unconnected_imm = false; |
3673 | 1477 | unique_serials.clear(); | ||
3674 | 1256 | 1478 | ||
3675 | 1257 | for (uint32_t i = 0; i < immovables.size(); ++i) { | 1479 | for (uint32_t i = 0; i < immovables.size(); ++i) { |
3676 | 1258 | |||
3677 | 1259 | const BaseImmovable& base_immovable = *immovables.at(i).object; | 1480 | const BaseImmovable& base_immovable = *immovables.at(i).object; |
3678 | 1260 | 1481 | ||
3691 | 1261 | // testing if it is enemy-owned field | 1482 | if (!unique_serials.insert(base_immovable.serial()).second) { |
3692 | 1262 | // TODO(unknown): count such fields... | 1483 | continue; // serial was not inserted in the set, so this is duplicate |
3681 | 1263 | if (upcast(PlayerImmovable const, player_immovable, &base_immovable)) { | ||
3682 | 1264 | |||
3683 | 1265 | // TODO(unknown): Only continue; if this is an opposing site | ||
3684 | 1266 | // allied sites should be counted for military influence | ||
3685 | 1267 | if (player_immovable->owner().player_number() != pn) { | ||
3686 | 1268 | if (player_->is_hostile(player_immovable->owner())) { | ||
3687 | 1269 | field.enemy_nearby = true; | ||
3688 | 1270 | } | ||
3689 | 1271 | continue; | ||
3690 | 1272 | } | ||
3693 | 1273 | } | 1484 | } |
3694 | 1274 | 1485 | ||
3696 | 1275 | // if we are here, immovable is ours | 1486 | // testing if immovable is owned by someone else and collecting some statistics |
3697 | 1276 | if (upcast(Building const, building, &base_immovable)) { | 1487 | if (upcast(Building const, building, &base_immovable)) { |
3698 | 1277 | 1488 | ||
3700 | 1278 | // connected to warehouse | 1489 | const PlayerNumber bpn = building->owner().player_number(); |
3701 | 1490 | if (player_statistics.get_is_enemy(bpn)) { // owned by enemy | ||
3702 | 1491 | assert(!player_statistics.players_in_same_team(bpn, pn)); | ||
3703 | 1492 | field.enemy_nearby = true; | ||
3704 | 1493 | if (upcast(MilitarySite const, militarysite, building)) { | ||
3705 | 1494 | field.enemy_military_presence += | ||
3706 | 1495 | militarysite->soldier_control()->stationed_soldiers().size(); | ||
3707 | 1496 | ++field.enemy_military_sites; | ||
3708 | 1497 | } | ||
3709 | 1498 | if (upcast(ConstructionSite const, constructionsite, building)) { | ||
3710 | 1499 | const BuildingDescr& target_descr = constructionsite->building(); | ||
3711 | 1500 | if (target_descr.type() == MapObjectType::MILITARYSITE) { | ||
3712 | 1501 | ++field.enemy_military_sites; | ||
3713 | 1502 | } | ||
3714 | 1503 | } | ||
3715 | 1504 | |||
3716 | 1505 | // Warehouses are counted here too as they can host soldiers as well | ||
3717 | 1506 | if (upcast(Warehouse const, warehouse, building)) { | ||
3718 | 1507 | field.enemy_military_presence += | ||
3719 | 1508 | warehouse->soldier_control()->stationed_soldiers().size(); | ||
3720 | 1509 | ++field.enemy_military_sites; | ||
3721 | 1510 | field.enemy_wh_nearby = true; | ||
3722 | 1511 | enemy_warehouses.insert(building->get_position().hash()); | ||
3723 | 1512 | } | ||
3724 | 1513 | continue; | ||
3725 | 1514 | } else if (bpn != pn) { // it is an ally | ||
3726 | 1515 | assert(!player_statistics.get_is_enemy(bpn)); | ||
3727 | 1516 | if (upcast(MilitarySite const, militarysite, building)) { | ||
3728 | 1517 | field.ally_military_presence += | ||
3729 | 1518 | militarysite->soldier_control()->stationed_soldiers().size(); | ||
3730 | 1519 | } | ||
3731 | 1520 | continue; | ||
3732 | 1521 | } | ||
3733 | 1522 | |||
3734 | 1523 | // if we are here, the immovable is ours | ||
3735 | 1524 | assert(building->owner().player_number() == pn); | ||
3736 | 1525 | |||
3737 | 1526 | // connected to a warehouse | ||
3738 | 1279 | bool connected = !building->get_economy()->warehouses().empty(); | 1527 | bool connected = !building->get_economy()->warehouses().empty(); |
3739 | 1280 | if (connected) { | 1528 | if (connected) { |
3740 | 1281 | any_connected_imm = true; | 1529 | any_connected_imm = true; |
3741 | @@ -1297,7 +1545,7 @@ | |||
3742 | 1297 | } | 1545 | } |
3743 | 1298 | } | 1546 | } |
3744 | 1299 | } else if (!connected) { | 1547 | } else if (!connected) { |
3746 | 1300 | // we dont care about unconnected constructionsites | 1548 | // we don't care about unconnected constructionsites |
3747 | 1301 | any_unconnected_imm = true; | 1549 | any_unconnected_imm = true; |
3748 | 1302 | } | 1550 | } |
3749 | 1303 | 1551 | ||
3750 | @@ -1308,7 +1556,7 @@ | |||
3751 | 1308 | if (radius > dist) { | 1556 | if (radius > dist) { |
3752 | 1309 | field.area_military_capacity += | 1557 | field.area_military_capacity += |
3753 | 1310 | militarysite->soldier_control()->max_soldier_capacity(); | 1558 | militarysite->soldier_control()->max_soldier_capacity(); |
3755 | 1311 | field.area_military_presence += | 1559 | field.own_military_presence += |
3756 | 1312 | militarysite->soldier_control()->stationed_soldiers().size(); | 1560 | militarysite->soldier_control()->stationed_soldiers().size(); |
3757 | 1313 | 1561 | ||
3758 | 1314 | if (militarysite->soldier_control()->stationed_soldiers().empty()) { | 1562 | if (militarysite->soldier_control()->stationed_soldiers().empty()) { |
3759 | @@ -1321,12 +1569,241 @@ | |||
3760 | 1321 | field.military_loneliness *= static_cast<double_t>(dist) / radius; | 1569 | field.military_loneliness *= static_cast<double_t>(dist) / radius; |
3761 | 1322 | } | 1570 | } |
3762 | 1323 | } | 1571 | } |
3763 | 1572 | } else { | ||
3764 | 1573 | ++field.own_non_military_nearby; | ||
3765 | 1324 | } | 1574 | } |
3766 | 1325 | } | 1575 | } |
3767 | 1326 | } | 1576 | } |
3768 | 1577 | |||
3769 | 1578 | assert(field.military_loneliness <= 1000); | ||
3770 | 1579 | |||
3771 | 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) { |
3772 | 1328 | field.unconnected_nearby = true; | 1581 | field.unconnected_nearby = true; |
3773 | 1329 | } | 1582 | } |
3774 | 1583 | |||
3775 | 1584 | // if there is a militarysite on the field, we try to walk to enemy | ||
3776 | 1585 | field.enemy_accessible_ = false; | ||
3777 | 1586 | field.local_soldier_capacity = 0; | ||
3778 | 1587 | if (field.is_militarysite) { | ||
3779 | 1588 | if (upcast(MilitarySite, ms, field.coords.field->get_immovable())) { | ||
3780 | 1589 | if (field.enemy_nearby) { | ||
3781 | 1590 | uint32_t unused1 = 0; | ||
3782 | 1591 | uint16_t unused2 = 0; | ||
3783 | 1592 | field.enemy_accessible_ = other_player_accessible( | ||
3784 | 1593 | actual_enemy_check_area + 3, &unused1, &unused2, field.coords, WalkSearch::kEnemy); | ||
3785 | 1594 | } | ||
3786 | 1595 | field.local_soldier_capacity = ms->soldier_control()->max_soldier_capacity(); | ||
3787 | 1596 | field.is_militarysite = true; | ||
3788 | 1597 | } else { | ||
3789 | 1598 | NEVER_HERE(); | ||
3790 | 1599 | } | ||
3791 | 1600 | } | ||
3792 | 1601 | |||
3793 | 1602 | // Calculating field score | ||
3794 | 1603 | field.military_score_ = 0; | ||
3795 | 1604 | field.inland = false; | ||
3796 | 1605 | |||
3797 | 1606 | if (!(field.enemy_nearby || field.near_border)) { | ||
3798 | 1607 | field.inland = true; | ||
3799 | 1608 | } | ||
3800 | 1609 | |||
3801 | 1610 | const uint8_t score_parts_size = 55; | ||
3802 | 1611 | int32_t score_parts[score_parts_size] = {0}; | ||
3803 | 1612 | if (field.enemy_owned_land_nearby) { | ||
3804 | 1613 | score_parts[0] = 3 * | ||
3805 | 1614 | management_data.neuron_pool[73].get_result_safe( | ||
3806 | 1615 | field.enemy_owned_land_nearby / 5, kAbsValue); | ||
3807 | 1616 | score_parts[1] = | ||
3808 | 1617 | 3 * | ||
3809 | 1618 | management_data.neuron_pool[76].get_result_safe(field.enemy_owned_land_nearby, kAbsValue); | ||
3810 | 1619 | score_parts[2] = 3 * | ||
3811 | 1620 | management_data.neuron_pool[54].get_result_safe( | ||
3812 | 1621 | field.enemy_military_presence * 2, kAbsValue); | ||
3813 | 1622 | score_parts[3] = 3 * | ||
3814 | 1623 | management_data.neuron_pool[61].get_result_safe( | ||
3815 | 1624 | field.enemy_military_presence / 3, kAbsValue); | ||
3816 | 1625 | score_parts[4] = | ||
3817 | 1626 | (!field.enemy_accessible_) ? (-100 + management_data.get_military_number_at(55)) : 0; | ||
3818 | 1627 | score_parts[5] = | ||
3819 | 1628 | 2 * | ||
3820 | 1629 | management_data.neuron_pool[50].get_result_safe(field.enemy_owned_land_nearby, kAbsValue); | ||
3821 | 1630 | |||
3822 | 1631 | score_parts[6] = | ||
3823 | 1632 | field.enemy_military_sites * std::abs(management_data.get_military_number_at(67) / 2); | ||
3824 | 1633 | score_parts[7] = | ||
3825 | 1634 | 2 * | ||
3826 | 1635 | management_data.neuron_pool[34].get_result_safe(field.enemy_military_sites * 2, kAbsValue); | ||
3827 | 1636 | score_parts[8] = management_data.neuron_pool[56].get_result_safe( | ||
3828 | 1637 | field.enemy_military_presence * 2, kAbsValue); | ||
3829 | 1638 | |||
3830 | 1639 | score_parts[9] = management_data.neuron_pool[65].get_result_safe( | ||
3831 | 1640 | (field.unowned_land_nearby + field.enemy_owned_land_nearby) / 2, kAbsValue); | ||
3832 | 1641 | score_parts[10] = (field.enemy_accessible_) ? management_data.get_military_number_at(80) : 0; | ||
3833 | 1642 | |||
3834 | 1643 | score_parts[11] = | ||
3835 | 1644 | -3 * | ||
3836 | 1645 | management_data.neuron_pool[8].get_result_safe( | ||
3837 | 1646 | (field.military_in_constr_nearby + field.military_unstationed) * 3, kAbsValue); | ||
3838 | 1647 | score_parts[12] = | ||
3839 | 1648 | -3 * | ||
3840 | 1649 | management_data.neuron_pool[74].get_result_safe( | ||
3841 | 1650 | (field.military_in_constr_nearby + field.military_unstationed) * 5, kAbsValue); | ||
3842 | 1651 | score_parts[13] = ((field.military_in_constr_nearby + field.military_unstationed) > 0) ? | ||
3843 | 1652 | -std::abs(management_data.get_military_number_at(32)) : | ||
3844 | 1653 | 0; | ||
3845 | 1654 | score_parts[14] = -1 * (field.military_in_constr_nearby + field.military_unstationed) * | ||
3846 | 1655 | std::abs(management_data.get_military_number_at(12)); | ||
3847 | 1656 | |||
3848 | 1657 | score_parts[15] = | ||
3849 | 1658 | -2 * management_data.neuron_pool[75].get_result_safe(field.own_military_presence); | ||
3850 | 1659 | score_parts[16] = -5 * std::min<int16_t>(field.area_military_capacity, 20); | ||
3851 | 1660 | score_parts[17] = 3 * management_data.get_military_number_at(28); | ||
3852 | 1661 | score_parts[18] = | ||
3853 | 1662 | (field.enemy_nearby) ? 3 * std::abs(management_data.get_military_number_at(68)) : 0; | ||
3854 | 1663 | score_parts[19] = | ||
3855 | 1664 | (field.enemy_wh_nearby) ? 3 * std::abs(management_data.get_military_number_at(132)) : 0; | ||
3856 | 1665 | score_parts[58] = (field.enemy_wh_nearby) ? | ||
3857 | 1666 | std::abs(management_data.get_military_number_at(135)) : | ||
3858 | 1667 | -std::abs(management_data.get_military_number_at(135)); | ||
3859 | 1668 | |||
3860 | 1669 | } else { // for expansion or inner land | ||
3861 | 1670 | |||
3862 | 1671 | score_parts[20] = management_data.neuron_pool[22].get_result_safe( | ||
3863 | 1672 | (field.unowned_mines_spots_nearby + 2) / 3, kAbsValue); | ||
3864 | 1673 | score_parts[21] = (field.unowned_mines_spots_nearby > 0) ? | ||
3865 | 1674 | std::abs(management_data.get_military_number_at(58)) : | ||
3866 | 1675 | 0; | ||
3867 | 1676 | if (expansion_type.get_expansion_type() == ExpansionMode::kResources) { | ||
3868 | 1677 | score_parts[23] = 2 * | ||
3869 | 1678 | management_data.neuron_pool[78].get_result_safe( | ||
3870 | 1679 | (field.unowned_mines_spots_nearby + 2) / 3, kAbsValue); | ||
3871 | 1680 | } | ||
3872 | 1681 | |||
3873 | 1682 | score_parts[24] = | ||
3874 | 1683 | (field.unowned_land_nearby) ? | ||
3875 | 1684 | management_data.neuron_pool[25].get_result_safe(field.water_nearby / 2, kAbsValue) : | ||
3876 | 1685 | 0; | ||
3877 | 1686 | score_parts[25] = | ||
3878 | 1687 | (field.unowned_land_nearby) ? | ||
3879 | 1688 | management_data.neuron_pool[27].get_result_safe(field.trees_nearby / 2, kAbsValue) : | ||
3880 | 1689 | 0; | ||
3881 | 1690 | |||
3882 | 1691 | if (resource_necessity_water_needed_) { | ||
3883 | 1692 | score_parts[26] = | ||
3884 | 1693 | (field.unowned_land_nearby) ? | ||
3885 | 1694 | management_data.neuron_pool[15].get_result_safe(field.water_nearby, kAbsValue) : | ||
3886 | 1695 | 0; | ||
3887 | 1696 | score_parts[27] = | ||
3888 | 1697 | resource_necessity_water_needed_ * | ||
3889 | 1698 | management_data.neuron_pool[17].get_result_safe(field.distant_water, kAbsValue) / 100; | ||
3890 | 1699 | } | ||
3891 | 1700 | score_parts[28] = | ||
3892 | 1701 | (field.unowned_land_nearby) ? | ||
3893 | 1702 | management_data.neuron_pool[33].get_result_safe(field.water_nearby, kAbsValue) : | ||
3894 | 1703 | 0; | ||
3895 | 1704 | score_parts[29] = | ||
3896 | 1705 | management_data.neuron_pool[10].get_result_safe(field.military_loneliness / 50, kAbsValue); | ||
3897 | 1706 | |||
3898 | 1707 | score_parts[30] = | ||
3899 | 1708 | -10 * | ||
3900 | 1709 | management_data.neuron_pool[8].get_result_safe( | ||
3901 | 1710 | 3 * (field.military_in_constr_nearby + field.military_unstationed), kAbsValue); | ||
3902 | 1711 | score_parts[31] = | ||
3903 | 1712 | -10 * | ||
3904 | 1713 | management_data.neuron_pool[31].get_result_safe( | ||
3905 | 1714 | 3 * (field.military_in_constr_nearby + field.military_unstationed), kAbsValue); | ||
3906 | 1715 | score_parts[32] = -4 * field.military_in_constr_nearby * | ||
3907 | 1716 | std::abs(management_data.get_military_number_at(82)); | ||
3908 | 1717 | score_parts[33] = (field.military_in_constr_nearby > 0) ? | ||
3909 | 1718 | -5 * management_data.get_military_number_at(85) : | ||
3910 | 1719 | 0; | ||
3911 | 1720 | |||
3912 | 1721 | score_parts[34] = -1 * | ||
3913 | 1722 | management_data.neuron_pool[4].get_result_safe( | ||
3914 | 1723 | (field.area_military_capacity + 4) / 5, kAbsValue); | ||
3915 | 1724 | score_parts[35] = 3 * management_data.get_military_number_at(133); | ||
3916 | 1725 | |||
3917 | 1726 | if (expansion_type.get_expansion_type() == ExpansionMode::kEconomy) { | ||
3918 | 1727 | score_parts[36] = -100 - 4 * std::abs(management_data.get_military_number_at(139)); | ||
3919 | 1728 | } else if (expansion_type.get_expansion_type() == ExpansionMode::kResources || | ||
3920 | 1729 | expansion_type.get_expansion_type() == ExpansionMode::kSpace) { | ||
3921 | 1730 | score_parts[37] = | ||
3922 | 1731 | +100 + 4 * std::abs(management_data.get_military_number_at(139)); // The same as above | ||
3923 | 1732 | } | ||
3924 | 1733 | if (msites_in_constr() > 0 && field.max_buildcap_nearby == BUILDCAPS_BIG && | ||
3925 | 1734 | spots_avail.at(BUILDCAPS_BIG) <= 2) { | ||
3926 | 1735 | score_parts[57] = -10 * std::abs(management_data.get_military_number_at(54)); | ||
3927 | 1736 | } | ||
3928 | 1737 | } | ||
3929 | 1738 | |||
3930 | 1739 | // common inputs | ||
3931 | 1740 | if (field.unowned_iron_mines_nearby > 0 && ((mines_per_type[iron_ore_id].in_construction + | ||
3932 | 1741 | mines_per_type[iron_ore_id].finished) == 0)) { | ||
3933 | 1742 | score_parts[40] = field.unowned_iron_mines_nearby * | ||
3934 | 1743 | std::abs(management_data.get_military_number_at(92)) / 50; | ||
3935 | 1744 | } | ||
3936 | 1745 | if (field.unowned_iron_mines_nearby && ((mines_per_type[iron_ore_id].in_construction + | ||
3937 | 1746 | mines_per_type[iron_ore_id].finished) <= 1)) { | ||
3938 | 1747 | score_parts[41] = 3 * std::abs(management_data.get_military_number_at(93)); | ||
3939 | 1748 | } | ||
3940 | 1749 | |||
3941 | 1750 | score_parts[42] = | ||
3942 | 1751 | (field.unowned_land_nearby) ? | ||
3943 | 1752 | management_data.neuron_pool[18].get_result_safe(field.own_non_military_nearby, kAbsValue) : | ||
3944 | 1753 | 0; | ||
3945 | 1754 | |||
3946 | 1755 | score_parts[43] = 2 * | ||
3947 | 1756 | management_data.neuron_pool[11].get_result_safe( | ||
3948 | 1757 | field.unowned_buildable_spots_nearby, kAbsValue); | ||
3949 | 1758 | score_parts[44] = | ||
3950 | 1759 | management_data.neuron_pool[12].get_result_safe(field.unowned_mines_spots_nearby, kAbsValue); | ||
3951 | 1760 | score_parts[45] = | ||
3952 | 1761 | (field.unowned_land_nearby) ? | ||
3953 | 1762 | field.military_loneliness * std::abs(management_data.get_military_number_at(53)) / 800 : | ||
3954 | 1763 | 0; | ||
3955 | 1764 | |||
3956 | 1765 | score_parts[46] = | ||
3957 | 1766 | -1 * management_data.neuron_pool[55].get_result_safe(field.ally_military_presence, kAbsValue); | ||
3958 | 1767 | score_parts[47] = | ||
3959 | 1768 | -1 * | ||
3960 | 1769 | management_data.neuron_pool[53].get_result_safe(2 * field.ally_military_presence, kAbsValue); | ||
3961 | 1770 | score_parts[48] = -2 * | ||
3962 | 1771 | management_data.neuron_pool[4].get_result_safe( | ||
3963 | 1772 | (field.area_military_capacity + 4) / 5, kAbsValue); | ||
3964 | 1773 | score_parts[49] = ((field.military_in_constr_nearby + field.military_unstationed) > 0) ? | ||
3965 | 1774 | -std::abs(management_data.get_military_number_at(81)) : | ||
3966 | 1775 | 0; | ||
3967 | 1776 | score_parts[55] = (field.military_loneliness < 10) ? | ||
3968 | 1777 | 2 * std::abs(management_data.get_military_number_at(141)) : | ||
3969 | 1778 | 0; | ||
3970 | 1779 | score_parts[56] = | ||
3971 | 1780 | (any_unconnected_imm) ? 2 * std::abs(management_data.get_military_number_at(23)) : 0; | ||
3972 | 1781 | |||
3973 | 1782 | for (uint16_t i = 0; i < score_parts_size; i++) { | ||
3974 | 1783 | field.military_score_ += score_parts[i]; | ||
3975 | 1784 | } | ||
3976 | 1785 | |||
3977 | 1786 | if (kAITrainingMode) { | ||
3978 | 1787 | if (field.military_score_ < -5000 || field.military_score_ > 2000) { | ||
3979 | 1788 | log("Warning field.military_score_ %5d, compounds: ", field.military_score_); | ||
3980 | 1789 | for (uint16_t i = 0; i < score_parts_size; i++) { | ||
3981 | 1790 | log("%d, ", score_parts[i]); | ||
3982 | 1791 | } | ||
3983 | 1792 | log("\n"); | ||
3984 | 1793 | } | ||
3985 | 1794 | } | ||
3986 | 1795 | |||
3987 | 1796 | // is new site allowed at all here? | ||
3988 | 1797 | field.defense_msite_allowed = false; | ||
3989 | 1798 | int16_t multiplicator = 10; | ||
3990 | 1799 | if (soldier_status_ == SoldiersStatus::kBadShortage) { | ||
3991 | 1800 | multiplicator = 4; | ||
3992 | 1801 | } else if (soldier_status_ == SoldiersStatus::kShortage) { | ||
3993 | 1802 | multiplicator = 7; | ||
3994 | 1803 | } | ||
3995 | 1804 | if (field.area_military_capacity < field.enemy_military_presence * multiplicator / 10) { | ||
3996 | 1805 | field.defense_msite_allowed = true; | ||
3997 | 1806 | } | ||
3998 | 1330 | } | 1807 | } |
3999 | 1331 | 1808 | ||
4000 | 1332 | /// Updates one mineable field | 1809 | /// Updates one mineable field |
4001 | @@ -1378,7 +1855,6 @@ | |||
4002 | 1378 | 1855 | ||
4003 | 1379 | /// Updates the production and MINE sites statistics needed for construction decision. | 1856 | /// Updates the production and MINE sites statistics needed for construction decision. |
4004 | 1380 | void DefaultAI::update_productionsite_stats() { | 1857 | void DefaultAI::update_productionsite_stats() { |
4005 | 1381 | uint16_t fishers_count = 0; // used for atlanteans only | ||
4006 | 1382 | 1858 | ||
4007 | 1383 | // Reset statistics for all buildings | 1859 | // Reset statistics for all buildings |
4008 | 1384 | for (uint32_t i = 0; i < buildings_.size(); ++i) { | 1860 | for (uint32_t i = 0; i < buildings_.size(); ++i) { |
4009 | @@ -1400,11 +1876,6 @@ | |||
4010 | 1400 | productionsites.front().bo->current_stats += | 1876 | productionsites.front().bo->current_stats += |
4011 | 1401 | productionsites.front().site->get_crude_statistics(); | 1877 | productionsites.front().site->get_crude_statistics(); |
4012 | 1402 | 1878 | ||
4013 | 1403 | // counting fishers | ||
4014 | 1404 | if (productionsites.front().bo->is_fisher) { | ||
4015 | 1405 | fishers_count += 1; | ||
4016 | 1406 | } | ||
4017 | 1407 | |||
4018 | 1408 | // Check whether this building is completely occupied | 1879 | // Check whether this building is completely occupied |
4019 | 1409 | if (!productionsites.front().site->can_start_working()) { | 1880 | if (!productionsites.front().site->can_start_working()) { |
4020 | 1410 | productionsites.front().bo->unoccupied_count += 1; | 1881 | productionsites.front().bo->unoccupied_count += 1; |
4021 | @@ -1418,16 +1889,6 @@ | |||
4022 | 1418 | productionsites.pop_front(); | 1889 | productionsites.pop_front(); |
4023 | 1419 | } | 1890 | } |
4024 | 1420 | 1891 | ||
4025 | 1421 | if (resource_necessity_water_needed_) { | ||
4026 | 1422 | if (fishers_count == 0) { | ||
4027 | 1423 | resource_necessity_water_ = 100; | ||
4028 | 1424 | } else if (fishers_count == 1) { | ||
4029 | 1425 | resource_necessity_water_ = 50; | ||
4030 | 1426 | } else { | ||
4031 | 1427 | resource_necessity_water_ = 10; | ||
4032 | 1428 | } | ||
4033 | 1429 | } | ||
4034 | 1430 | |||
4035 | 1431 | // for mines_ also | 1892 | // for mines_ also |
4036 | 1432 | // Check all available mines | 1893 | // Check all available mines |
4037 | 1433 | for (uint32_t i = 0; i < mines_.size(); ++i) { | 1894 | for (uint32_t i = 0; i < mines_.size(); ++i) { |
4038 | @@ -1467,29 +1928,23 @@ | |||
4039 | 1467 | // is built. | 1928 | // is built. |
4040 | 1468 | // * Buildings are split into categories | 1929 | // * Buildings are split into categories |
4041 | 1469 | // * The logic is complex but approximately: | 1930 | // * The logic is complex but approximately: |
4044 | 1470 | // - buildings producing building material are preferred | 1931 | // - some buildings belong to "basic economy" - these are preferred |
4045 | 1471 | // - buildings identified as basic are preferred | 1932 | // - some small huts are exempt from basic economy logic |
4046 | 1472 | // - first bulding of a type is preferred | 1933 | // - first bulding of a type is preferred |
4047 | 1473 | // - buildings identified as 'direct food supplier' are built after 15 min. | ||
4048 | 1474 | // from game start | ||
4049 | 1475 | // - if a building is upgradeable, second building is also preferred | ||
4050 | 1476 | // (there should be no upgrade when there are not two buildings of the same type) | ||
4051 | 1477 | // - algorithm is trying to take into account actual utlization of buildings | 1934 | // - algorithm is trying to take into account actual utlization of buildings |
4052 | 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) |
4056 | 1479 | // * military buildings have own strategy, split into two situations: | 1936 | // * military buildings use genetic algorithm logic to score fields |
4054 | 1480 | // - there is no enemy | ||
4055 | 1481 | // - there is an enemy | ||
4057 | 1482 | // Currently more military buildings are built than needed | 1937 | // Currently more military buildings are built than needed |
4059 | 1483 | // and "optimization" (dismantling not needed buildings) is done afterwards | 1938 | // so there are always some vacant positions |
4060 | 1484 | bool DefaultAI::construct_building(uint32_t gametime) { | 1939 | bool DefaultAI::construct_building(uint32_t gametime) { |
4061 | 1485 | if (buildable_fields.empty()) { | 1940 | if (buildable_fields.empty()) { |
4062 | 1486 | return false; | 1941 | return false; |
4063 | 1487 | } | 1942 | } |
4064 | 1943 | |||
4065 | 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. |
4066 | 1489 | bool mine = false; | 1945 | bool mine = false; |
4067 | 1490 | uint32_t consumers_nearby_count = 0; | 1946 | uint32_t consumers_nearby_count = 0; |
4070 | 1491 | std::vector<int32_t> spots_avail; | 1947 | |
4069 | 1492 | spots_avail.resize(4); | ||
4071 | 1493 | Map& map = game().map(); | 1948 | Map& map = game().map(); |
4072 | 1494 | 1949 | ||
4073 | 1495 | for (int32_t i = 0; i < 4; ++i) | 1950 | for (int32_t i = 0; i < 4; ++i) |
4074 | @@ -1503,9 +1958,6 @@ | |||
4075 | 1503 | spots_ += spots_avail.at(BUILDCAPS_MEDIUM); | 1958 | spots_ += spots_avail.at(BUILDCAPS_MEDIUM); |
4076 | 1504 | spots_ += spots_avail.at(BUILDCAPS_BIG); | 1959 | spots_ += spots_avail.at(BUILDCAPS_BIG); |
4077 | 1505 | 1960 | ||
4078 | 1506 | // here we possible stop building of new buildings | ||
4079 | 1507 | new_buildings_stop_ = false; | ||
4080 | 1508 | |||
4081 | 1509 | // helper variable - we need some proportion of free spots vs productionsites | 1961 | // helper variable - we need some proportion of free spots vs productionsites |
4082 | 1510 | // the proportion depends on size of economy | 1962 | // the proportion depends on size of economy |
4083 | 1511 | // this proportion defines how dense the buildings will be | 1963 | // this proportion defines how dense the buildings will be |
4084 | @@ -1522,8 +1974,22 @@ | |||
4085 | 1522 | } | 1974 | } |
4086 | 1523 | const bool has_enough_space = (spots_ > needed_spots); | 1975 | const bool has_enough_space = (spots_ > needed_spots); |
4087 | 1524 | 1976 | ||
4090 | 1525 | // This is a replacement for simple count of mines | 1977 | // Do we have basic economy established? Informing that we just left the basic economy mode. |
4091 | 1526 | const int32_t virtual_mines = mines_.size() + mineable_fields.size() / 25; | 1978 | if (!basic_economy_established && persistent_data->remaining_basic_buildings.empty()) { |
4092 | 1979 | log("%2d: Player has achieved the basic economy at %s\n", player_number(), | ||
4093 | 1980 | gamestring_with_leading_zeros(gametime)); | ||
4094 | 1981 | basic_economy_established = true; | ||
4095 | 1982 | assert(persistent_data->remaining_buildings_size == 0); | ||
4096 | 1983 | } | ||
4097 | 1984 | |||
4098 | 1985 | if (!basic_economy_established && player_statistics.any_enemy_seen_lately(gametime) && | ||
4099 | 1986 | management_data.f_neuron_pool[17].get_position(0)) { | ||
4100 | 1987 | log("%2d: Player has not all buildings for basic economy yet (%lu missing), but enemy is " | ||
4101 | 1988 | "nearby, so quitting the mode at %s\n", | ||
4102 | 1989 | player_number(), persistent_data->remaining_basic_buildings.size(), | ||
4103 | 1990 | gamestring_with_leading_zeros(gametime)); | ||
4104 | 1991 | basic_economy_established = true; | ||
4105 | 1992 | } | ||
4106 | 1527 | 1993 | ||
4107 | 1528 | // *_military_scores are used as minimal score for a new military building | 1994 | // *_military_scores are used as minimal score for a new military building |
4108 | 1529 | // to be built. As AI does not traverse all building fields at once, these thresholds | 1995 | // to be built. As AI does not traverse all building fields at once, these thresholds |
4109 | @@ -1534,102 +2000,210 @@ | |||
4110 | 1534 | // score) and quickly falling down until it reaches the least_military_score | 2000 | // score) and quickly falling down until it reaches the least_military_score |
4111 | 1535 | // this one (=target_military_score) is actually used to decide if building&field is allowed | 2001 | // this one (=target_military_score) is actually used to decide if building&field is allowed |
4112 | 1536 | // candidate | 2002 | // candidate |
4126 | 1537 | // least_military_score is allowed to get bellow 100 only if there is no military site in | 2003 | |
4127 | 1538 | // construction | 2004 | const PlayerNumber pn = player_number(); |
4128 | 1539 | // right now in order to (try to) avoid expansion lockup | 2005 | |
4129 | 1540 | 2006 | // Genetic algorithm is used here | |
4130 | 1541 | // Bools below are helpers to improve readability of code | 2007 | bool inputs[2 * kFNeuronBitSize] = {0}; |
4131 | 1542 | 2008 | inputs[0] = (pow(msites_in_constr(), 2) > militarysites.size() + 2); | |
4132 | 1543 | // It is bit complicated balance building militarysites and productionsites so this is small hack | 2009 | inputs[1] = !(pow(msites_in_constr(), 2) > militarysites.size() + 2); |
4133 | 1544 | // to help | 2010 | inputs[2] = |
4134 | 1545 | // it | 2011 | (highest_nonmil_prio_ > 18 + std::abs(management_data.get_military_number_at(29) / 10)); |
4135 | 1546 | bool needs_boost_economy = false; | 2012 | inputs[3] = |
4136 | 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)); |
4137 | 1548 | needs_boost_economy = true; | 2014 | inputs[4] = (highest_nonmil_prio_ > 18 + std::abs(management_data.get_military_number_at(48))); |
4138 | 1549 | } | 2015 | inputs[5] = !(highest_nonmil_prio_ > 18 + std::abs(management_data.get_military_number_at(49))); |
4139 | 2016 | inputs[6] = ((numof_psites_in_constr + mines_in_constr()) > | ||
4140 | 2017 | (productionsites.size() + mines_built()) / productionsites_ratio_); | ||
4141 | 2018 | inputs[7] = !((numof_psites_in_constr + mines_in_constr()) > | ||
4142 | 2019 | (productionsites.size() + mines_built()) / productionsites_ratio_); | ||
4143 | 2020 | |||
4144 | 2021 | inputs[8] = (has_enough_space); | ||
4145 | 2022 | inputs[9] = !(has_enough_space); | ||
4146 | 2023 | inputs[10] = (has_enough_space); | ||
4147 | 2024 | inputs[11] = !(has_enough_space); | ||
4148 | 2025 | |||
4149 | 2026 | inputs[12] = (gametime > 45 * 60 * 1000); | ||
4150 | 2027 | inputs[13] = !(gametime > 45 * 60 * 1000); | ||
4151 | 2028 | |||
4152 | 2029 | inputs[14] = (expansion_type.get_expansion_type() == ExpansionMode::kEconomy); | ||
4153 | 2030 | inputs[15] = !(expansion_type.get_expansion_type() == ExpansionMode::kEconomy); | ||
4154 | 2031 | inputs[16] = (expansion_type.get_expansion_type() == ExpansionMode::kSpace); | ||
4155 | 2032 | inputs[17] = !(expansion_type.get_expansion_type() == ExpansionMode::kSpace); | ||
4156 | 2033 | |||
4157 | 2034 | inputs[18] = (player_statistics.any_enemy_seen_lately(gametime)); | ||
4158 | 2035 | inputs[19] = !(player_statistics.any_enemy_seen_lately(gametime)); | ||
4159 | 2036 | inputs[20] = (player_statistics.get_player_power(pn) > | ||
4160 | 2037 | player_statistics.get_old60_player_power(pn) + | ||
4161 | 2038 | std::abs(management_data.get_military_number_at(130)) / 10); | ||
4162 | 2039 | inputs[21] = !(player_statistics.get_player_power(pn) > | ||
4163 | 2040 | player_statistics.get_old60_player_power(pn) + | ||
4164 | 2041 | std::abs(management_data.get_military_number_at(131)) / 10); | ||
4165 | 2042 | inputs[22] = | ||
4166 | 2043 | (player_statistics.get_player_power(pn) > player_statistics.get_old_player_power(pn)); | ||
4167 | 2044 | inputs[23] = | ||
4168 | 2045 | !(player_statistics.get_player_power(pn) > player_statistics.get_old_player_power(pn)); | ||
4169 | 2046 | inputs[24] = (highest_nonmil_prio_ > 18 + management_data.get_military_number_at(65) / 10); | ||
4170 | 2047 | inputs[25] = !(highest_nonmil_prio_ > 18 + management_data.get_military_number_at(65) / 10); | ||
4171 | 2048 | inputs[26] = (player_statistics.get_modified_player_power(pn) > | ||
4172 | 2049 | player_statistics.get_visible_enemies_power(pn)); | ||
4173 | 2050 | inputs[27] = (player_statistics.get_modified_player_power(pn) <= | ||
4174 | 2051 | player_statistics.get_visible_enemies_power(pn)); | ||
4175 | 2052 | inputs[28] = | ||
4176 | 2053 | (player_statistics.get_player_power(pn) > player_statistics.get_enemies_average_power()); | ||
4177 | 2054 | inputs[29] = | ||
4178 | 2055 | !(player_statistics.get_player_power(pn) > player_statistics.get_enemies_average_power()); | ||
4179 | 2056 | inputs[30] = | ||
4180 | 2057 | (player_statistics.get_player_power(pn) > player_statistics.get_enemies_max_power()); | ||
4181 | 2058 | inputs[31] = | ||
4182 | 2059 | !(player_statistics.get_player_power(pn) > player_statistics.get_enemies_max_power()); | ||
4183 | 2060 | |||
4184 | 2061 | inputs[32] = (persistent_data->least_military_score < | ||
4185 | 2062 | persistent_data->ai_personality_mil_upper_limit * | ||
4186 | 2063 | std::abs(management_data.get_military_number_at(69)) / 100); | ||
4187 | 2064 | inputs[33] = !(persistent_data->least_military_score < | ||
4188 | 2065 | persistent_data->ai_personality_mil_upper_limit * | ||
4189 | 2066 | std::abs(management_data.get_military_number_at(69)) / 100); | ||
4190 | 2067 | inputs[34] = player_statistics.strong_enough(pn); | ||
4191 | 2068 | inputs[35] = !player_statistics.strong_enough(pn); | ||
4192 | 2069 | |||
4193 | 2070 | inputs[36] = (player_statistics.get_player_land(pn) < 500); | ||
4194 | 2071 | inputs[37] = (player_statistics.get_player_land(pn) < 700); | ||
4195 | 2072 | inputs[38] = (player_statistics.get_player_land(pn) < 900); | ||
4196 | 2073 | inputs[39] = (player_statistics.get_player_land(pn) < 1100); | ||
4197 | 2074 | inputs[40] = (player_statistics.get_player_land(pn) > 500); | ||
4198 | 2075 | inputs[41] = (player_statistics.get_player_land(pn) > 700); | ||
4199 | 2076 | inputs[42] = (player_statistics.get_player_land(pn) > 900); | ||
4200 | 2077 | inputs[43] = (player_statistics.get_player_land(pn) > 1100); | ||
4201 | 2078 | inputs[44] = (player_statistics.get_player_power(pn) > | ||
4202 | 2079 | player_statistics.get_old60_player_power(pn) + | ||
4203 | 2080 | std::abs(management_data.get_military_number_at(130)) / 10); | ||
4204 | 2081 | inputs[45] = !(player_statistics.get_player_power(pn) > | ||
4205 | 2082 | player_statistics.get_old60_player_power(pn) + | ||
4206 | 2083 | std::abs(management_data.get_military_number_at(131)) / 10); | ||
4207 | 2084 | inputs[46] = | ||
4208 | 2085 | (player_statistics.get_player_power(pn) > player_statistics.get_old_player_power(pn)); | ||
4209 | 2086 | inputs[47] = | ||
4210 | 2087 | !(player_statistics.get_player_power(pn) > player_statistics.get_old_player_power(pn)); | ||
4211 | 2088 | inputs[48] = (bakeries_count_ == 0); | ||
4212 | 2089 | inputs[49] = (bakeries_count_ <= 1); | ||
4213 | 2090 | inputs[50] = (bakeries_count_ <= 1); | ||
4214 | 2091 | inputs[51] = (numof_psites_in_constr > 8); | ||
4215 | 2092 | inputs[52] = (numof_psites_in_constr < 8); | ||
4216 | 2093 | |||
4217 | 2094 | int16_t needs_boost_economy_score = management_data.get_military_number_at(61) / 5; | ||
4218 | 2095 | int16_t increase_score_limit_score = 0; | ||
4219 | 2096 | |||
4220 | 2097 | for (uint8_t i = 0; i < kFNeuronBitSize; ++i) { | ||
4221 | 2098 | if (management_data.f_neuron_pool[51].get_position(i)) { | ||
4222 | 2099 | needs_boost_economy_score += (inputs[i]) ? 1 : -1; | ||
4223 | 2100 | } | ||
4224 | 2101 | if (management_data.f_neuron_pool[52].get_position(i)) { | ||
4225 | 2102 | increase_score_limit_score += (inputs[i]) ? 1 : -1; | ||
4226 | 2103 | } | ||
4227 | 2104 | if (management_data.f_neuron_pool[21].get_position(i)) { | ||
4228 | 2105 | needs_boost_economy_score += (inputs[kFNeuronBitSize + i]) ? 1 : -1; | ||
4229 | 2106 | } | ||
4230 | 2107 | if (management_data.f_neuron_pool[22].get_position(i)) { | ||
4231 | 2108 | increase_score_limit_score += (inputs[kFNeuronBitSize + i]) ? 1 : -1; | ||
4232 | 2109 | } | ||
4233 | 2110 | } | ||
4234 | 2111 | |||
4235 | 2112 | // Finding expansion policy | ||
4236 | 2113 | // Do we need basic resources? | ||
4237 | 2114 | // This is a replacement for simple count of mines | ||
4238 | 2115 | const int32_t virtual_mines = mines_.size() + mineable_fields.size() / 15; | ||
4239 | 2116 | const bool needs_fishers = resource_necessity_water_needed_ && fishers_count_ < 1; | ||
4240 | 2117 | |||
4241 | 2118 | if (virtual_mines < 4 || mines_per_type[iron_ore_id].total_count() < 1 || needs_fishers) { | ||
4242 | 2119 | expansion_type.set_expantion_type(ExpansionMode::kResources); | ||
4243 | 2120 | } else { | ||
4244 | 2121 | // now we must decide if we go after spots or economy boost | ||
4245 | 2122 | if (needs_boost_economy_score >= 3) { | ||
4246 | 2123 | expansion_type.set_expantion_type(ExpansionMode::kEconomy); | ||
4247 | 2124 | } else if (needs_boost_economy_score >= -2) { | ||
4248 | 2125 | expansion_type.set_expantion_type(ExpansionMode::kBoth); | ||
4249 | 2126 | } else { | ||
4250 | 2127 | expansion_type.set_expantion_type(ExpansionMode::kSpace); | ||
4251 | 2128 | } | ||
4252 | 2129 | } | ||
4253 | 2130 | |||
4254 | 2131 | const bool increase_least_score_limit = | ||
4255 | 2132 | (increase_score_limit_score > management_data.get_military_number_at(45) / 5); | ||
4256 | 2133 | |||
4257 | 2134 | uint16_t concurent_ms_in_constr_no_enemy = 1; | ||
4258 | 2135 | uint16_t concurent_ms_in_constr_enemy_nearby = 2; | ||
4259 | 1550 | 2136 | ||
4260 | 1551 | // resetting highest_nonmil_prio_ so it can be recalculated anew | 2137 | // resetting highest_nonmil_prio_ so it can be recalculated anew |
4261 | 1552 | highest_nonmil_prio_ = 0; | 2138 | highest_nonmil_prio_ = 0; |
4262 | 1553 | 2139 | ||
4271 | 1554 | const bool too_many_ms_constructionsites = | 2140 | if (increase_least_score_limit) { |
4264 | 1555 | (pow(msites_in_constr(), 2) > militarysites.size() + 2); | ||
4265 | 1556 | const bool too_many_vacant_mil = | ||
4266 | 1557 | (vacant_mil_positions_ * 3 > static_cast<int32_t>(militarysites.size())); | ||
4267 | 1558 | const int32_t kUpperLimit = 325; | ||
4268 | 1559 | const int32_t kBottomLimit = 40; // to prevent too dense militarysites | ||
4269 | 1560 | // modifying least_military_score, down if more military sites are needed and vice versa | ||
4270 | 1561 | if (too_many_ms_constructionsites || too_many_vacant_mil || needs_boost_economy) { | ||
4272 | 1562 | if (persistent_data->least_military_score < | 2141 | if (persistent_data->least_military_score < |
4274 | 1563 | kUpperLimit) { // No sense in letting it grow too high | 2142 | persistent_data |
4275 | 2143 | ->ai_personality_mil_upper_limit) { // No sense in letting it grow too high | ||
4276 | 1564 | persistent_data->least_military_score += 20; | 2144 | persistent_data->least_military_score += 20; |
4277 | 2145 | if (persistent_data->least_military_score > persistent_data->target_military_score) { | ||
4278 | 2146 | persistent_data->target_military_score = persistent_data->least_military_score; | ||
4279 | 2147 | } | ||
4280 | 2148 | if (persistent_data->target_military_score > | ||
4281 | 2149 | persistent_data->ai_personality_mil_upper_limit) { | ||
4282 | 2150 | persistent_data->ai_personality_mil_upper_limit = | ||
4283 | 2151 | persistent_data->target_military_score; | ||
4284 | 2152 | } | ||
4285 | 1565 | } | 2153 | } |
4286 | 1566 | } else { | 2154 | } else { |
4287 | 2155 | |||
4288 | 2156 | uint16_t divider = 1; // this is to slow down decrementing the least military score | ||
4289 | 2157 | switch (expansion_type.get_expansion_type()) { | ||
4290 | 2158 | case ExpansionMode::kEconomy: | ||
4291 | 2159 | divider = 3; | ||
4292 | 2160 | break; | ||
4293 | 2161 | case ExpansionMode::kBoth: | ||
4294 | 2162 | divider = 2; | ||
4295 | 2163 | break; | ||
4296 | 2164 | default: | ||
4297 | 2165 | divider = 1; | ||
4298 | 2166 | } | ||
4299 | 2167 | |||
4300 | 1567 | // least_military_score is decreased, but depending on the size of territory | 2168 | // least_military_score is decreased, but depending on the size of territory |
4301 | 1568 | switch (static_cast<uint32_t>(log10(buildable_fields.size()))) { | 2169 | switch (static_cast<uint32_t>(log10(buildable_fields.size()))) { |
4302 | 1569 | case 0: | 2170 | case 0: |
4304 | 1570 | persistent_data->least_military_score -= 10; | 2171 | persistent_data->least_military_score -= 10 / divider; |
4305 | 1571 | break; | 2172 | break; |
4306 | 1572 | case 1: | 2173 | case 1: |
4308 | 1573 | persistent_data->least_military_score -= 8; | 2174 | persistent_data->least_military_score -= 8 / divider; |
4309 | 1574 | break; | 2175 | break; |
4310 | 1575 | case 2: | 2176 | case 2: |
4312 | 1576 | persistent_data->least_military_score -= 5; | 2177 | persistent_data->least_military_score -= 5 / divider; |
4313 | 1577 | break; | 2178 | break; |
4314 | 1578 | case 3: | 2179 | case 3: |
4316 | 1579 | persistent_data->least_military_score -= 3; | 2180 | persistent_data->least_military_score -= 3 / divider; |
4317 | 1580 | break; | 2181 | break; |
4318 | 1581 | default: | 2182 | default: |
4325 | 1582 | persistent_data->least_military_score -= 2; | 2183 | persistent_data->least_military_score -= 2 / divider; |
4320 | 1583 | } | ||
4321 | 1584 | // do not get bellow kBottomLimit if there is at least one ms in construction | ||
4322 | 1585 | if ((msites_in_constr() > 0 || too_many_vacant_mil) && | ||
4323 | 1586 | persistent_data->least_military_score < kBottomLimit) { | ||
4324 | 1587 | persistent_data->least_military_score = kBottomLimit; | ||
4326 | 1588 | } | 2184 | } |
4327 | 1589 | if (persistent_data->least_military_score < 0) { | 2185 | if (persistent_data->least_military_score < 0) { |
4328 | 1590 | persistent_data->least_military_score = 0; | 2186 | persistent_data->least_military_score = 0; |
4329 | 1591 | } | 2187 | } |
4330 | 1592 | } | 2188 | } |
4331 | 1593 | 2189 | ||
4338 | 1594 | // This is effective score, falling down very quickly | 2190 | assert(persistent_data->least_military_score <= persistent_data->target_military_score); |
4339 | 1595 | if (persistent_data->target_military_score > kUpperLimit + 150) { | 2191 | assert(persistent_data->target_military_score <= |
4340 | 1596 | persistent_data->target_military_score = 8 * persistent_data->target_military_score / 10; | 2192 | persistent_data->ai_personality_mil_upper_limit); |
4341 | 1597 | } else { | 2193 | persistent_data->target_military_score = 9 * persistent_data->target_military_score / 10; |
4336 | 1598 | persistent_data->target_military_score = 9 * persistent_data->target_military_score / 10; | ||
4337 | 1599 | } | ||
4342 | 1600 | if (persistent_data->target_military_score < persistent_data->least_military_score) { | 2194 | if (persistent_data->target_military_score < persistent_data->least_military_score) { |
4343 | 1601 | persistent_data->target_military_score = persistent_data->least_military_score; | 2195 | persistent_data->target_military_score = persistent_data->least_military_score; |
4344 | 1602 | } | 2196 | } |
4366 | 1603 | 2197 | assert(persistent_data->target_military_score >= persistent_data->least_military_score); | |
4346 | 1604 | // there are many reasons why to stop building production buildings | ||
4347 | 1605 | // (note there are numerous exceptions) | ||
4348 | 1606 | // 1. to not have too many constructionsites | ||
4349 | 1607 | if ((num_prod_constructionsites + mines_in_constr()) > | ||
4350 | 1608 | (productionsites.size() + mines_built()) / persistent_data->ai_productionsites_ratio + 2) { | ||
4351 | 1609 | new_buildings_stop_ = true; | ||
4352 | 1610 | } | ||
4353 | 1611 | // 2. to not exhaust all free spots | ||
4354 | 1612 | if (!has_enough_space) { | ||
4355 | 1613 | new_buildings_stop_ = true; | ||
4356 | 1614 | } | ||
4357 | 1615 | // 3. too keep some proportions production sites vs military sites | ||
4358 | 1616 | if ((num_prod_constructionsites + productionsites.size()) > | ||
4359 | 1617 | (msites_in_constr() + militarysites.size()) * 5) { | ||
4360 | 1618 | new_buildings_stop_ = true; | ||
4361 | 1619 | } | ||
4362 | 1620 | // 4. if we do not have 2 mines at least | ||
4363 | 1621 | if (mines_.size() < 2) { | ||
4364 | 1622 | new_buildings_stop_ = true; | ||
4365 | 1623 | } | ||
4367 | 1624 | 2198 | ||
4368 | 1625 | // we must calculate wood policy | 2199 | // we must calculate wood policy |
4369 | 1626 | const DescriptionIndex wood_index = tribe_->safe_ware_index("log"); | 2200 | const DescriptionIndex wood_index = tribe_->safe_ware_index("log"); |
4370 | 1627 | // stocked wood is to be in some propotion to productionsites and | 2201 | // stocked wood is to be in some propotion to productionsites and |
4371 | 1628 | // constructionsites (this proportion is bit artifical, or we can say | 2202 | // constructionsites (this proportion is bit artifical, or we can say |
4372 | 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' |
4376 | 1630 | const int32_t stocked_wood_margin = get_warehoused_stock(wood_index) - | 2204 | const int32_t stocked_wood_margin = calculate_stocklevel(wood_index) - |
4377 | 1631 | productionsites.size() * 2 - num_prod_constructionsites + | 2205 | productionsites.size() * 2 - numof_psites_in_constr + |
4378 | 1632 | persistent_data->ai_personality_wood_difference; | 2206 | management_data.get_military_number_at(87) / 5; |
4379 | 1633 | if (gametime < 15 * 60 * 1000) { | 2207 | if (gametime < 15 * 60 * 1000) { |
4380 | 1634 | wood_policy_ = WoodPolicy::kAllowRangers; | 2208 | wood_policy_ = WoodPolicy::kAllowRangers; |
4381 | 1635 | } else if (stocked_wood_margin > 80) { | 2209 | } else if (stocked_wood_margin > 80) { |
4382 | @@ -1640,34 +2214,6 @@ | |||
4383 | 1640 | wood_policy_ = WoodPolicy::kAllowRangers; | 2214 | wood_policy_ = WoodPolicy::kAllowRangers; |
4384 | 1641 | } | 2215 | } |
4385 | 1642 | 2216 | ||
4386 | 1643 | // we must consider need for mines | ||
4387 | 1644 | // set necessity for mines | ||
4388 | 1645 | // we use 'virtual mines', because also mine spots can be changed | ||
4389 | 1646 | // to mines when AI decides so | ||
4390 | 1647 | |||
4391 | 1648 | resource_necessity_mines_ = 100 * (15 - virtual_mines) / 15; | ||
4392 | 1649 | resource_necessity_mines_ = (resource_necessity_mines_ > 100) ? 100 : resource_necessity_mines_; | ||
4393 | 1650 | resource_necessity_mines_ = (resource_necessity_mines_ < 20) ? 10 : resource_necessity_mines_; | ||
4394 | 1651 | |||
4395 | 1652 | // here we calculate how badly we need to expand, result is number (0-100) | ||
4396 | 1653 | // like a percent | ||
4397 | 1654 | if (spots_ == 0) { | ||
4398 | 1655 | resource_necessity_territory_ = 100; | ||
4399 | 1656 | } else { | ||
4400 | 1657 | resource_necessity_territory_ = 100 * 3 * (productionsites.size() + 5) / spots_; | ||
4401 | 1658 | resource_necessity_territory_ = | ||
4402 | 1659 | (resource_necessity_territory_ > 100) ? 100 : resource_necessity_territory_; | ||
4403 | 1660 | resource_necessity_territory_ = | ||
4404 | 1661 | (resource_necessity_territory_ < 10) ? 10 : resource_necessity_territory_; | ||
4405 | 1662 | // alse we need at lest 4 big spots | ||
4406 | 1663 | if (spots_avail.at(BUILDCAPS_BIG) < 2) { | ||
4407 | 1664 | resource_necessity_territory_ = 100; | ||
4408 | 1665 | } | ||
4409 | 1666 | if (spots_avail.at(BUILDCAPS_MEDIUM) < 4) { | ||
4410 | 1667 | resource_necessity_territory_ = 100; | ||
4411 | 1668 | } | ||
4412 | 1669 | } | ||
4413 | 1670 | |||
4414 | 1671 | BuildingObserver* best_building = nullptr; | 2217 | BuildingObserver* best_building = nullptr; |
4415 | 1672 | int32_t proposed_priority = 0; | 2218 | int32_t proposed_priority = 0; |
4416 | 1673 | Coords proposed_coords; | 2219 | Coords proposed_coords; |
4417 | @@ -1685,7 +2231,8 @@ | |||
4418 | 1685 | 2231 | ||
4419 | 1686 | // not doing this for non-military buildins | 2232 | // not doing this for non-military buildins |
4420 | 1687 | if (!(bo.type == BuildingObserver::Type::kMilitarysite || | 2233 | if (!(bo.type == BuildingObserver::Type::kMilitarysite || |
4422 | 1688 | bo.type == BuildingObserver::Type::kTrainingsite)) | 2234 | bo.type == BuildingObserver::Type::kTrainingsite || |
4423 | 2235 | bo.type == BuildingObserver::Type::kProductionsite)) | ||
4424 | 1689 | continue; | 2236 | continue; |
4425 | 1690 | 2237 | ||
4426 | 1691 | // and neither for small military buildings | 2238 | // and neither for small military buildings |
4427 | @@ -1698,13 +2245,17 @@ | |||
4428 | 1698 | // checking we have enough critical material on stock | 2245 | // checking we have enough critical material on stock |
4429 | 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) { |
4430 | 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))); |
4432 | 1701 | uint32_t treshold = 3; | 2248 | uint32_t treshold = 7; |
4433 | 1702 | // generally trainingsites are more important | 2249 | // generally trainingsites are more important |
4434 | 1703 | if (bo.type == BuildingObserver::Type::kTrainingsite) { | 2250 | if (bo.type == BuildingObserver::Type::kTrainingsite) { |
4435 | 2251 | treshold = 4; | ||
4436 | 2252 | } | ||
4437 | 2253 | |||
4438 | 2254 | if (bo.type == BuildingObserver::Type::kProductionsite) { | ||
4439 | 1704 | treshold = 2; | 2255 | treshold = 2; |
4440 | 1705 | } | 2256 | } |
4441 | 1706 | 2257 | ||
4443 | 1707 | if (get_warehoused_stock(wt) < treshold) { | 2258 | if (calculate_stocklevel(wt) <= treshold) { |
4444 | 1708 | bo.build_material_shortage = true; | 2259 | bo.build_material_shortage = true; |
4445 | 1709 | break; | 2260 | break; |
4446 | 1710 | } | 2261 | } |
4447 | @@ -1722,6 +2273,11 @@ | |||
4448 | 1722 | 2273 | ||
4449 | 1723 | bo.new_building = check_building_necessity(bo, PerfEvaluation::kForConstruction, gametime); | 2274 | bo.new_building = check_building_necessity(bo, PerfEvaluation::kForConstruction, gametime); |
4450 | 1724 | 2275 | ||
4451 | 2276 | if (bo.is(BuildingAttribute::kShipyard)) { | ||
4452 | 2277 | assert(bo.new_building == BuildingNecessity::kAllowed || | ||
4453 | 2278 | bo.new_building == BuildingNecessity::kForbidden); | ||
4454 | 2279 | } | ||
4455 | 2280 | |||
4456 | 1725 | if (bo.new_building == BuildingNecessity::kAllowed) { | 2281 | if (bo.new_building == BuildingNecessity::kAllowed) { |
4457 | 1726 | bo.new_building_overdue = 0; | 2282 | bo.new_building_overdue = 0; |
4458 | 1727 | } | 2283 | } |
4459 | @@ -1732,7 +2288,7 @@ | |||
4460 | 1732 | bo.new_building == BuildingNecessity::kForced || | 2288 | bo.new_building == BuildingNecessity::kForced || |
4461 | 1733 | bo.new_building == BuildingNecessity::kAllowed || | 2289 | bo.new_building == BuildingNecessity::kAllowed || |
4462 | 1734 | bo.new_building == BuildingNecessity::kNeededPending) && | 2290 | bo.new_building == BuildingNecessity::kNeededPending) && |
4464 | 1735 | !bo.outputs.empty()) { | 2291 | (!bo.outputs.empty() || bo.is(BuildingAttribute::kBarracks))) { |
4465 | 1736 | if (bo.max_needed_preciousness <= 0) { | 2292 | if (bo.max_needed_preciousness <= 0) { |
4466 | 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", |
4467 | 1738 | bo.desc->name().c_str()); | 2294 | bo.desc->name().c_str()); |
4468 | @@ -1741,6 +2297,7 @@ | |||
4469 | 1741 | bo.max_needed_preciousness = 0; | 2297 | bo.max_needed_preciousness = 0; |
4470 | 1742 | } else { | 2298 | } else { |
4471 | 1743 | // For other situations we make sure max_needed_preciousness is zero | 2299 | // For other situations we make sure max_needed_preciousness is zero |
4472 | 2300 | |||
4473 | 1744 | assert(bo.max_needed_preciousness == 0); | 2301 | assert(bo.max_needed_preciousness == 0); |
4474 | 1745 | } | 2302 | } |
4475 | 1746 | 2303 | ||
4476 | @@ -1763,42 +2320,31 @@ | |||
4477 | 1763 | // c) all other cases: primary_priority = 0; | 2320 | // c) all other cases: primary_priority = 0; |
4478 | 1764 | if (bo.max_needed_preciousness > 0) { | 2321 | if (bo.max_needed_preciousness > 0) { |
4479 | 1765 | if (bo.new_building == BuildingNecessity::kAllowed) { | 2322 | if (bo.new_building == BuildingNecessity::kAllowed) { |
4481 | 1766 | bo.primary_priority = bo.max_needed_preciousness; | 2323 | bo.primary_priority += bo.max_needed_preciousness; |
4482 | 1767 | } else { | 2324 | } else { |
4486 | 1768 | bo.primary_priority = bo.max_needed_preciousness + | 2325 | bo.primary_priority += bo.primary_priority * bo.new_building_overdue * |
4487 | 1769 | bo.max_needed_preciousness * bo.new_building_overdue / 100 + | 2326 | std::abs(management_data.get_military_number_at(120)) / 500; |
4488 | 1770 | bo.new_building_overdue / 20; | 2327 | bo.primary_priority += bo.max_needed_preciousness + |
4489 | 2328 | bo.max_needed_preciousness * bo.new_building_overdue * | ||
4490 | 2329 | std::abs(management_data.get_military_number_at(70)) / | ||
4491 | 2330 | 1000 + | ||
4492 | 2331 | bo.new_building_overdue * | ||
4493 | 2332 | std::abs(management_data.get_military_number_at(71)) / 50; | ||
4494 | 2333 | if (bo.new_building == BuildingNecessity::kForced) { | ||
4495 | 2334 | bo.primary_priority += bo.new_building_overdue * | ||
4496 | 2335 | std::abs(management_data.get_military_number_at(119)) / 50; | ||
4497 | 2336 | } | ||
4498 | 1771 | } | 2337 | } |
4499 | 1772 | } else { | 2338 | } else { |
4500 | 1773 | bo.primary_priority = 0; | 2339 | bo.primary_priority = 0; |
4501 | 1774 | } | 2340 | } |
4502 | 1775 | 2341 | ||
4503 | 1776 | // Generally we don't start another building if there is some of the same type in | ||
4504 | 1777 | // construction | ||
4505 | 1778 | // Some types of building allow two buildings in construction though, but not more | ||
4506 | 1779 | // Below checks are to guarantee that there is no logical error in previous steps, or | ||
4507 | 1780 | // inconsistency in AI data | ||
4508 | 1781 | if (bo.new_building == BuildingNecessity::kNeeded || | ||
4509 | 1782 | bo.new_building == BuildingNecessity::kForced || | ||
4510 | 1783 | bo.new_building == BuildingNecessity::kAllowed || | ||
4511 | 1784 | bo.new_building == BuildingNecessity::kNeededPending) { | ||
4512 | 1785 | if (bo.plants_trees || bo.need_trees || bo.max_needed_preciousness >= 10) { | ||
4513 | 1786 | if (bo.cnt_under_construction + bo.unoccupied_count > 1) { | ||
4514 | 1787 | throw wexception("AI inconsistency: %s: total_count %d > 1, unoccupied: %d", | ||
4515 | 1788 | bo.name, bo.total_count(), bo.unoccupied_count); | ||
4516 | 1789 | } | ||
4517 | 1790 | } else { | ||
4518 | 1791 | if (bo.cnt_under_construction + bo.unoccupied_count > 0) { | ||
4519 | 1792 | throw wexception("AI inconsistency: %s: total_count %d > 0, unoccupied: %d", | ||
4520 | 1793 | bo.name, bo.total_count(), bo.unoccupied_count); | ||
4521 | 1794 | } | ||
4522 | 1795 | } | ||
4523 | 1796 | } | ||
4524 | 1797 | |||
4525 | 1798 | } else if (bo.type == BuildingObserver::Type::kMilitarysite) { | 2342 | } else if (bo.type == BuildingObserver::Type::kMilitarysite) { |
4527 | 1799 | bo.new_building = check_building_necessity(bo.desc->get_size(), gametime); | 2343 | bo.new_building = check_building_necessity(bo, gametime); |
4528 | 1800 | } else if (bo.type == BuildingObserver::Type::kTrainingsite) { | 2344 | } else if (bo.type == BuildingObserver::Type::kTrainingsite) { |
4529 | 1801 | bo.new_building = check_building_necessity(bo, PerfEvaluation::kForConstruction, gametime); | 2345 | bo.new_building = check_building_necessity(bo, PerfEvaluation::kForConstruction, gametime); |
4530 | 2346 | } else if (bo.type == BuildingObserver::Type::kWarehouse) { | ||
4531 | 2347 | bo.new_building = check_warehouse_necessity(bo, gametime); | ||
4532 | 1802 | } else if (bo.aimode_limit_status() != AiModeBuildings::kAnotherAllowed) { | 2348 | } else if (bo.aimode_limit_status() != AiModeBuildings::kAnotherAllowed) { |
4533 | 1803 | bo.new_building = BuildingNecessity::kNotNeeded; | 2349 | bo.new_building = BuildingNecessity::kNotNeeded; |
4534 | 1804 | } else { | 2350 | } else { |
4535 | @@ -1848,13 +2394,13 @@ | |||
4536 | 1848 | } | 2394 | } |
4537 | 1849 | 2395 | ||
4538 | 1850 | // testing for reserved ports | 2396 | // testing for reserved ports |
4540 | 1851 | if (!bo.is_port) { | 2397 | if (!bo.is(BuildingAttribute::kPort)) { |
4541 | 1852 | if (port_reserved_coords.count(bf->coords.hash()) > 0) { | 2398 | if (port_reserved_coords.count(bf->coords.hash()) > 0) { |
4542 | 1853 | continue; | 2399 | continue; |
4543 | 1854 | } | 2400 | } |
4544 | 1855 | } | 2401 | } |
4545 | 1856 | 2402 | ||
4547 | 1857 | if (time(nullptr) % 3 == 0 && bo.total_count() > 0) { | 2403 | if (std::rand() % 3 == 0 && bo.total_count() > 0) { |
4548 | 1858 | continue; | 2404 | continue; |
4549 | 1859 | } // add randomnes and ease AI | 2405 | } // add randomnes and ease AI |
4550 | 1860 | 2406 | ||
4551 | @@ -1864,7 +2410,8 @@ | |||
4552 | 1864 | 2410 | ||
4553 | 1865 | // here we do an exemption for lumberjacks, mainly in early stages of game | 2411 | // here we do an exemption for lumberjacks, mainly in early stages of game |
4554 | 1866 | // sometimes the first one is not built and AI waits too long for second attempt | 2412 | // sometimes the first one is not built and AI waits too long for second attempt |
4556 | 1867 | if (gametime - bo.construction_decision_time < kBuildingMinInterval && !bo.need_trees) { | 2413 | if (gametime - bo.construction_decision_time < kBuildingMinInterval && |
4557 | 2414 | !bo.is(BuildingAttribute::kLumberjack)) { | ||
4558 | 1868 | continue; | 2415 | continue; |
4559 | 1869 | } | 2416 | } |
4560 | 1870 | 2417 | ||
4561 | @@ -1877,8 +2424,11 @@ | |||
4562 | 1877 | 2424 | ||
4563 | 1878 | if (bo.type == BuildingObserver::Type::kProductionsite) { | 2425 | if (bo.type == BuildingObserver::Type::kProductionsite) { |
4564 | 1879 | 2426 | ||
4565 | 2427 | prio = management_data.neuron_pool[44].get_result_safe(bf->military_score_ / 20) / 5; | ||
4566 | 2428 | assert(prio >= -20 && prio <= 20); | ||
4567 | 2429 | |||
4568 | 1880 | // this can be only a well (as by now) | 2430 | // this can be only a well (as by now) |
4570 | 1881 | if (bo.mines_water) { | 2431 | if (bo.is(BuildingAttribute::kWell)) { |
4571 | 1882 | 2432 | ||
4572 | 1883 | if (bo.new_building == BuildingNecessity::kForced) { | 2433 | if (bo.new_building == BuildingNecessity::kForced) { |
4573 | 1884 | assert(bo.total_count() - bo.unconnected_count == 0); | 2434 | assert(bo.total_count() - bo.unconnected_count == 0); |
4574 | @@ -1900,33 +2450,41 @@ | |||
4575 | 1900 | prio += 200; | 2450 | prio += 200; |
4576 | 1901 | } | 2451 | } |
4577 | 1902 | 2452 | ||
4579 | 1903 | prio += bf->ground_water - 2; | 2453 | prio += -10 + 2 * bf->ground_water; |
4580 | 1904 | 2454 | ||
4582 | 1905 | } else if (bo.need_trees) { // LUMBERJACS | 2455 | } else if (bo.is(BuildingAttribute::kLumberjack)) { |
4583 | 1906 | 2456 | ||
4584 | 1907 | prio = bo.primary_priority; | 2457 | prio = bo.primary_priority; |
4585 | 1908 | 2458 | ||
4586 | 1909 | prio += -20 + 200 / (bo.total_count() + 1); | ||
4587 | 1910 | |||
4588 | 1911 | if (bo.new_building == BuildingNecessity::kForced) { | 2459 | if (bo.new_building == BuildingNecessity::kForced) { |
4591 | 1912 | prio *= 2; | 2460 | prio += 5 * std::abs(management_data.get_military_number_at(17)); |
4592 | 1913 | } else if (bf->trees_nearby < 2 && bf->supporters_nearby.at(bo.outputs.at(0) == 0)) { | 2461 | } |
4593 | 2462 | |||
4594 | 2463 | if (bf->trees_nearby < trees_nearby_treshold_ && | ||
4595 | 2464 | bo.new_building == BuildingNecessity::kAllowed) { | ||
4596 | 1914 | continue; | 2465 | continue; |
4597 | 1915 | } | 2466 | } |
4598 | 1916 | 2467 | ||
4599 | 2468 | prio += std::abs(management_data.get_military_number_at(26)) * | ||
4600 | 2469 | (bf->trees_nearby - trees_nearby_treshold_) / 10; | ||
4601 | 2470 | |||
4602 | 1917 | // consider cutters and rangers nearby | 2471 | // consider cutters and rangers nearby |
4609 | 1918 | prio -= bf->producers_nearby.at(bo.outputs.at(0)) * 20; | 2472 | prio += 2 * bf->supporters_nearby.at(bo.outputs.at(0)) * |
4610 | 1919 | prio += bf->supporters_nearby.at(bo.outputs.at(0)) * 5; | 2473 | std::abs(management_data.get_military_number_at(25)); |
4611 | 1920 | 2474 | prio -= bf->producers_nearby.at(bo.outputs.at(0)) * | |
4612 | 1921 | prio += 2 * bf->trees_nearby; | 2475 | std::abs(management_data.get_military_number_at(36)) * 3; |
4613 | 1922 | 2476 | ||
4614 | 1923 | } else if (bo.need_rocks) { | 2477 | } else if (bo.is(BuildingAttribute::kNeedsRocks)) { |
4615 | 1924 | 2478 | ||
4616 | 1925 | // Quarries are generally to be built everywhere where rocks are | 2479 | // Quarries are generally to be built everywhere where rocks are |
4617 | 1926 | // no matter the need for granite, as rocks are considered an obstacle | 2480 | // no matter the need for granite, as rocks are considered an obstacle |
4618 | 1927 | // to expansion | 2481 | // to expansion |
4619 | 1928 | prio = 2 * bf->rocks_nearby; | 2482 | prio = 2 * bf->rocks_nearby; |
4620 | 1929 | 2483 | ||
4621 | 2484 | if (bf->rocks_nearby > 0 && bf->near_border) { | ||
4622 | 2485 | prio += management_data.get_military_number_at(27) / 2; | ||
4623 | 2486 | } | ||
4624 | 2487 | |||
4625 | 1930 | // value is initialized with 1 but minimal value that can be | 2488 | // value is initialized with 1 but minimal value that can be |
4626 | 1931 | // calculated is 11 | 2489 | // calculated is 11 |
4627 | 1932 | if (prio <= 1) { | 2490 | if (prio <= 1) { |
4628 | @@ -1937,19 +2495,14 @@ | |||
4629 | 1937 | prio += 150; | 2495 | prio += 150; |
4630 | 1938 | } | 2496 | } |
4631 | 1939 | 2497 | ||
4638 | 1940 | if (bo.stocklevel_time < game().get_gametime() - 5 * 1000) { | 2498 | if (get_stocklevel(bo, gametime) == 0) { |
4633 | 1941 | bo.stocklevel = get_stocklevel(static_cast<size_t>(bo.production_hint)); | ||
4634 | 1942 | bo.stocklevel_time = game().get_gametime(); | ||
4635 | 1943 | } | ||
4636 | 1944 | |||
4637 | 1945 | if (bo.stocklevel == 0) { | ||
4639 | 1946 | prio *= 2; | 2499 | prio *= 2; |
4640 | 1947 | } | 2500 | } |
4641 | 1948 | 2501 | ||
4642 | 1949 | // to prevent to many quaries on one spot | 2502 | // to prevent to many quaries on one spot |
4643 | 1950 | prio = prio - 50 * bf->producers_nearby.at(bo.outputs.at(0)); | 2503 | prio = prio - 50 * bf->producers_nearby.at(bo.outputs.at(0)); |
4644 | 1951 | 2504 | ||
4646 | 1952 | } else if (bo.is_hunter) { | 2505 | } else if (bo.is(BuildingAttribute::kHunter)) { |
4647 | 1953 | 2506 | ||
4648 | 1954 | if (bf->critters_nearby < 5) { | 2507 | if (bf->critters_nearby < 5) { |
4649 | 1955 | continue; | 2508 | continue; |
4650 | @@ -1967,26 +2520,31 @@ | |||
4651 | 1967 | prio += | 2520 | prio += |
4652 | 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)); |
4653 | 1969 | 2522 | ||
4655 | 1970 | } else if (bo.is_fisher) { // fisher | 2523 | } else if (bo.is(BuildingAttribute::kFisher)) { // fisher |
4656 | 1971 | 2524 | ||
4657 | 1972 | if (bf->water_nearby < 2 || bf->fish_nearby < 2) { | 2525 | if (bf->water_nearby < 2 || bf->fish_nearby < 2) { |
4658 | 1973 | continue; | 2526 | continue; |
4659 | 1974 | } | 2527 | } |
4660 | 1975 | 2528 | ||
4661 | 1976 | if (bo.new_building == BuildingNecessity::kForced) { | 2529 | if (bo.new_building == BuildingNecessity::kForced) { |
4663 | 1977 | prio += 20; | 2530 | prio += 200; |
4664 | 1978 | } | 2531 | } |
4665 | 1979 | 2532 | ||
4666 | 1980 | // Overdue priority here | 2533 | // Overdue priority here |
4667 | 1981 | prio += bo.primary_priority; | 2534 | prio += bo.primary_priority; |
4668 | 1982 | 2535 | ||
4669 | 1983 | prio -= bf->producers_nearby.at(bo.outputs.at(0)) * 20; | 2536 | prio -= bf->producers_nearby.at(bo.outputs.at(0)) * 20; |
4671 | 1984 | prio += bf->supporters_nearby.at(bo.outputs.at(0)) * 10; | 2537 | prio += bf->supporters_nearby.at(bo.outputs.at(0)) * 20; |
4672 | 1985 | 2538 | ||
4674 | 1986 | prio += -5 + bf->fish_nearby; | 2539 | prio += |
4675 | 2540 | -5 + | ||
4676 | 2541 | bf->fish_nearby * (1 + std::abs(management_data.get_military_number_at(63) / 15)); | ||
4677 | 2542 | if (resource_necessity_water_needed_) { | ||
4678 | 2543 | prio *= 3; | ||
4679 | 2544 | } | ||
4680 | 1987 | 2545 | ||
4681 | 1988 | } else if (bo.production_hint >= 0) { | 2546 | } else if (bo.production_hint >= 0) { |
4683 | 1989 | if (bo.plants_trees) { | 2547 | if (bo.is(BuildingAttribute::kRanger)) { |
4684 | 1990 | assert(bo.cnt_target > 0); | 2548 | assert(bo.cnt_target > 0); |
4685 | 1991 | } else { | 2549 | } else { |
4686 | 1992 | bo.cnt_target = | 2550 | bo.cnt_target = |
4687 | @@ -1996,39 +2554,41 @@ | |||
4688 | 1996 | // They have no own primary priority | 2554 | // They have no own primary priority |
4689 | 1997 | assert(bo.primary_priority == 0); | 2555 | assert(bo.primary_priority == 0); |
4690 | 1998 | 2556 | ||
4692 | 1999 | if (bo.plants_trees) { // RANGERS | 2557 | if (bo.is(BuildingAttribute::kRanger)) { |
4693 | 2000 | 2558 | ||
4694 | 2001 | assert(bo.new_building == BuildingNecessity::kNeeded); | 2559 | assert(bo.new_building == BuildingNecessity::kNeeded); |
4695 | 2002 | 2560 | ||
4705 | 2003 | // if there are too many trees nearby | 2561 | prio = 0; |
4697 | 2004 | if (bf->trees_nearby > 25 && bo.total_count() >= 1) { | ||
4698 | 2005 | continue; | ||
4699 | 2006 | } | ||
4700 | 2007 | |||
4701 | 2008 | // for small starting spots - to prevent crowding by rangers and trees | ||
4702 | 2009 | if (spots_ < (4 * bo.total_count()) && bo.total_count() > 0) { | ||
4703 | 2010 | continue; | ||
4704 | 2011 | } | ||
4706 | 2012 | 2562 | ||
4707 | 2013 | if (bo.total_count() == 0) { | 2563 | if (bo.total_count() == 0) { |
4709 | 2014 | prio = 200; | 2564 | prio += 200; |
4710 | 2015 | } else { | 2565 | } else { |
4712 | 2016 | prio = 50 / bo.total_count(); | 2566 | prio += std::abs(management_data.get_military_number_at(66)) * |
4713 | 2567 | (bo.cnt_target - bo.total_count()); | ||
4714 | 2017 | } | 2568 | } |
4721 | 2018 | 2569 | prio -= bf->water_nearby / 5; | |
4722 | 2019 | // considering producers | 2570 | |
4723 | 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( |
4724 | 2021 | new_buildings_stop_ * 15 - bf->space_consumers_nearby * 5 - | 2572 | bf->producers_nearby.at(bo.production_hint) * 5, kAbsValue) / |
4725 | 2022 | bf->rocks_nearby / 3 + bf->trees_nearby / 2 + | 2573 | 2; |
4726 | 2023 | std::min<uint8_t>(bf->supporters_nearby.at(bo.production_hint), 4) * 3; | 2574 | |
4727 | 2575 | prio += | ||
4728 | 2576 | management_data.neuron_pool[49].get_result_safe(bf->trees_nearby, kAbsValue) / | ||
4729 | 2577 | 5; | ||
4730 | 2578 | |||
4731 | 2579 | prio += bf->producers_nearby.at(bo.production_hint) * 5 - | ||
4732 | 2580 | (expansion_type.get_expansion_type() != ExpansionMode::kEconomy) * 15 - | ||
4733 | 2581 | bf->space_consumers_nearby * 5 - bf->rocks_nearby / 3 + | ||
4734 | 2582 | bf->supporters_nearby.at(bo.production_hint) * 3; | ||
4735 | 2024 | 2583 | ||
4736 | 2025 | } else { // FISH BREEDERS and GAME KEEPERS | 2584 | } else { // FISH BREEDERS and GAME KEEPERS |
4737 | 2026 | 2585 | ||
4738 | 2027 | // especially for fish breeders | 2586 | // especially for fish breeders |
4740 | 2028 | if (bo.need_water && (bf->water_nearby < 6 || bf->fish_nearby < 6)) { | 2587 | if (bo.is(BuildingAttribute::kNeedsCoast) && |
4741 | 2588 | (bf->water_nearby < 6 || bf->fish_nearby < 6)) { | ||
4742 | 2029 | continue; | 2589 | continue; |
4743 | 2030 | } | 2590 | } |
4745 | 2031 | if (bo.need_water) { | 2591 | if (bo.is(BuildingAttribute::kNeedsCoast)) { |
4746 | 2032 | prio += (-6 + bf->water_nearby) / 3; | 2592 | prio += (-6 + bf->water_nearby) / 3; |
4747 | 2033 | prio += (-6 + bf->fish_nearby) / 3; | 2593 | prio += (-6 + bf->fish_nearby) / 3; |
4748 | 2034 | } | 2594 | } |
4749 | @@ -2037,18 +2597,13 @@ | |||
4750 | 2037 | continue; | 2597 | continue; |
4751 | 2038 | } | 2598 | } |
4752 | 2039 | 2599 | ||
4759 | 2040 | if (bo.stocklevel_time < game().get_gametime() - 5 * 1000) { | 2600 | if (get_stocklevel(bo, gametime) > 50) { |
4754 | 2041 | bo.stocklevel = | ||
4755 | 2042 | get_stocklevel_by_hint(static_cast<size_t>(bo.production_hint)); | ||
4756 | 2043 | bo.stocklevel_time = game().get_gametime(); | ||
4757 | 2044 | } | ||
4758 | 2045 | if (bo.stocklevel > 50) { | ||
4760 | 2046 | continue; | 2601 | continue; |
4761 | 2047 | } | 2602 | } |
4762 | 2048 | 2603 | ||
4763 | 2049 | if (bo.total_count() == 0) { | 2604 | if (bo.total_count() == 0) { |
4764 | 2050 | prio += 100; | 2605 | prio += 100; |
4766 | 2051 | } else if (!bo.need_water) { | 2606 | } else if (!bo.is(BuildingAttribute::kNeedsCoast)) { |
4767 | 2052 | prio += 10 / bo.total_count(); | 2607 | prio += 10 / bo.total_count(); |
4768 | 2053 | } | 2608 | } |
4769 | 2054 | 2609 | ||
4770 | @@ -2060,21 +2615,18 @@ | |||
4771 | 2060 | } | 2615 | } |
4772 | 2061 | } | 2616 | } |
4773 | 2062 | 2617 | ||
4783 | 2063 | } else if (bo.recruitment && !new_buildings_stop_) { | 2618 | } else if (bo.is(BuildingAttribute::kRecruitment)) { |
4784 | 2064 | // this will depend on number of mines_ and productionsites | 2619 | prio = bo.primary_priority; |
4785 | 2065 | if (static_cast<int32_t>((productionsites.size() + mines_.size()) / 30) > | 2620 | prio -= bf->unowned_land_nearby * 2; |
4786 | 2066 | bo.total_count() && | 2621 | prio -= (bf->enemy_nearby) * 100; |
4787 | 2067 | (bo.cnt_under_construction + bo.unoccupied_count) == 0 && | 2622 | prio -= (expansion_type.get_expansion_type() != ExpansionMode::kEconomy) * 100; |
4779 | 2068 | // but only if current buildings are utilized enough | ||
4780 | 2069 | (bo.total_count() == 0 || bo.current_stats > 60)) { | ||
4781 | 2070 | prio = 10; | ||
4782 | 2071 | } | ||
4788 | 2072 | } else { // finally normal productionsites | 2623 | } else { // finally normal productionsites |
4789 | 2073 | assert(bo.production_hint < 0); | 2624 | assert(bo.production_hint < 0); |
4790 | 2074 | 2625 | ||
4791 | 2075 | if (bo.new_building == BuildingNecessity::kForced) { | 2626 | if (bo.new_building == BuildingNecessity::kForced) { |
4792 | 2076 | prio += 150; | 2627 | prio += 150; |
4794 | 2077 | } else if (bo.is_shipyard) { | 2628 | assert(!bo.is(BuildingAttribute::kShipyard)); |
4795 | 2629 | } else if (bo.is(BuildingAttribute::kShipyard)) { | ||
4796 | 2078 | assert(bo.new_building == BuildingNecessity::kAllowed); | 2630 | assert(bo.new_building == BuildingNecessity::kAllowed); |
4797 | 2079 | if (!seafaring_economy) { | 2631 | if (!seafaring_economy) { |
4798 | 2080 | continue; | 2632 | continue; |
4799 | @@ -2089,33 +2641,43 @@ | |||
4800 | 2089 | // we check separatelly buildings with no inputs and some inputs | 2641 | // we check separatelly buildings with no inputs and some inputs |
4801 | 2090 | if (bo.inputs.empty()) { | 2642 | if (bo.inputs.empty()) { |
4802 | 2091 | 2643 | ||
4804 | 2092 | if (bo.space_consumer) { | 2644 | assert(!bo.is(BuildingAttribute::kShipyard)); |
4805 | 2645 | |||
4806 | 2646 | if (bo.is(BuildingAttribute::kSpaceConsumer)) { | ||
4807 | 2093 | // we dont like trees nearby | 2647 | // we dont like trees nearby |
4808 | 2094 | prio += 1 - bf->trees_nearby / 15; | 2648 | prio += 1 - bf->trees_nearby / 15; |
4809 | 2095 | // we attempt to cluster space consumers together | 2649 | // we attempt to cluster space consumers together |
4810 | 2096 | prio += bf->space_consumers_nearby * 2; | 2650 | prio += bf->space_consumers_nearby * 2; |
4811 | 2097 | // and be far from rangers | 2651 | // and be far from rangers |
4813 | 2098 | prio += 1 - bf->rangers_nearby * 3; | 2652 | prio += 1 - |
4814 | 2653 | bf->rangers_nearby * | ||
4815 | 2654 | std::abs(management_data.get_military_number_at(102)) / 5; | ||
4816 | 2099 | } else { | 2655 | } else { |
4817 | 2100 | // leave some free space between them | 2656 | // leave some free space between them |
4828 | 2101 | prio -= bf->producers_nearby.at(bo.outputs.at(0)) * 5; | 2657 | prio -= bf->producers_nearby.at(bo.outputs.at(0)) * |
4829 | 2102 | } | 2658 | std::abs(management_data.get_military_number_at(108)) / 5; |
4830 | 2103 | 2659 | } | |
4831 | 2104 | if (bo.space_consumer && !bf->water_nearby) { // not close to water | 2660 | |
4832 | 2105 | prio += 1; | 2661 | if (bo.is(BuildingAttribute::kSpaceConsumer) && |
4833 | 2106 | } | 2662 | bf->water_nearby) { // not close to water |
4834 | 2107 | 2663 | prio -= std::abs(management_data.get_military_number_at(103)) / 5; | |
4835 | 2108 | if (bo.space_consumer && | 2664 | } |
4836 | 2109 | !bf->unowned_mines_spots_nearby) { // not close to mountains | 2665 | |
4837 | 2110 | prio += 1; | 2666 | if (bo.is(BuildingAttribute::kSpaceConsumer) && |
4838 | 2667 | bf->unowned_mines_spots_nearby) { // not close to mountains | ||
4839 | 2668 | prio -= std::abs(management_data.get_military_number_at(104)) / 5; | ||
4840 | 2111 | } | 2669 | } |
4841 | 2112 | } | 2670 | } |
4842 | 2113 | 2671 | ||
4844 | 2114 | else if (bo.is_shipyard) { | 2672 | else if (bo.is(BuildingAttribute::kShipyard)) { |
4845 | 2115 | // for now AI builds only one shipyard | 2673 | // for now AI builds only one shipyard |
4849 | 2116 | if (bf->open_water_nearby > 1 && (bo.total_count() - bo.unconnected_count) == 0 && | 2674 | assert(bo.total_count() == 0); |
4850 | 2117 | seafaring_economy) { | 2675 | if (bf->open_water_nearby > 3 && seafaring_economy) { |
4851 | 2118 | prio += productionsites.size() * 5 + bf->open_water_nearby; | 2676 | prio += productionsites.size() * 5 + |
4852 | 2677 | bf->open_water_nearby * | ||
4853 | 2678 | std::abs(management_data.get_military_number_at(109)) / 10; | ||
4854 | 2679 | } else { | ||
4855 | 2680 | continue; | ||
4856 | 2119 | } | 2681 | } |
4857 | 2120 | } | 2682 | } |
4858 | 2121 | 2683 | ||
4859 | @@ -2125,11 +2687,11 @@ | |||
4860 | 2125 | 2687 | ||
4861 | 2126 | // bonus for big buildings if shortage of big fields | 2688 | // bonus for big buildings if shortage of big fields |
4862 | 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) { |
4864 | 2128 | prio += 10; | 2690 | prio += std::abs(management_data.get_military_number_at(105)) / 5; |
4865 | 2129 | } | 2691 | } |
4866 | 2130 | 2692 | ||
4867 | 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) { |
4869 | 2132 | prio += 5; | 2694 | prio += std::abs(management_data.get_military_number_at(106)) / 5; |
4870 | 2133 | } | 2695 | } |
4871 | 2134 | 2696 | ||
4872 | 2135 | // +1 if any consumers_ are nearby | 2697 | // +1 if any consumers_ are nearby |
4873 | @@ -2139,152 +2701,69 @@ | |||
4874 | 2139 | consumers_nearby_count += bf->consumers_nearby.at(bo.outputs.at(k)); | 2701 | consumers_nearby_count += bf->consumers_nearby.at(bo.outputs.at(k)); |
4875 | 2140 | 2702 | ||
4876 | 2141 | if (consumers_nearby_count > 0) { | 2703 | if (consumers_nearby_count > 0) { |
4878 | 2142 | prio += 1; | 2704 | prio += std::abs(management_data.get_military_number_at(107)) / 3; |
4879 | 2143 | } | 2705 | } |
4880 | 2144 | } | 2706 | } |
4881 | 2145 | 2707 | ||
4882 | 2146 | // Consider border with exemption of some huts | 2708 | // Consider border with exemption of some huts |
4884 | 2147 | if (!(bo.need_trees || bo.need_water || bo.is_fisher)) { | 2709 | if (!(bo.is(BuildingAttribute::kLumberjack) || bo.is(BuildingAttribute::kNeedsCoast) || |
4885 | 2710 | bo.is(BuildingAttribute::kFisher))) { | ||
4886 | 2148 | prio = recalc_with_border_range(*bf, prio); | 2711 | prio = recalc_with_border_range(*bf, prio); |
4888 | 2149 | } else if (bf->near_border && (bo.need_trees || bo.need_water)) { | 2712 | } else if (bf->near_border && (bo.is(BuildingAttribute::kLumberjack) || |
4889 | 2713 | bo.is(BuildingAttribute::kNeedsCoast))) { | ||
4890 | 2150 | prio /= 2; | 2714 | prio /= 2; |
4891 | 2151 | } | 2715 | } |
4892 | 2152 | 2716 | ||
4893 | 2153 | } // production sites done | 2717 | } // production sites done |
4894 | 2154 | else if (bo.type == BuildingObserver::Type::kMilitarysite) { | 2718 | else if (bo.type == BuildingObserver::Type::kMilitarysite) { |
4895 | 2155 | 2719 | ||
4974 | 2156 | if (!(bf->unowned_land_nearby || bf->enemy_nearby)) { | 2720 | assert(prio == 0); |
4975 | 2157 | continue; | 2721 | prio = bo.primary_priority; |
4976 | 2158 | } | 2722 | |
4977 | 2159 | 2723 | // Two possibilities why to construct militarysite here | |
4978 | 2160 | if (military_last_build_ > gametime - 15 * 1000) { | 2724 | if (!bf->defense_msite_allowed && |
4979 | 2161 | continue; | 2725 | bf->nearest_buildable_spot_nearby < bo.desc->get_conquers() && |
4980 | 2162 | } | 2726 | (bf->military_in_constr_nearby + bf->military_unstationed) < |
4981 | 2163 | 2727 | concurent_ms_in_constr_no_enemy) { | |
4982 | 2164 | // This is another restriction of military building - but general | 2728 | // it will conquer new buildable spots for buildings or mines |
4983 | 2165 | if (bf->enemy_nearby && bo.fighting_type) { | 2729 | ; |
4984 | 2166 | ; | 2730 | } else if (bf->defense_msite_allowed && |
4985 | 2167 | } // it is ok, go on | 2731 | (bf->military_in_constr_nearby + bf->military_unstationed) < |
4986 | 2168 | else if (bf->unowned_mines_spots_nearby > 2 && | 2732 | concurent_ms_in_constr_enemy_nearby) { |
4987 | 2169 | (bo.mountain_conqueror || bo.expansion_type)) { | 2733 | // we need it to increase capacity on the field |
4988 | 2170 | ; | 2734 | if (bo.fighting_type) { |
4989 | 2171 | } // it is ok, go on | 2735 | prio += 5; |
4990 | 2172 | else if (bo.expansion_type) { | 2736 | } |
4991 | 2173 | if (bo.desc->get_size() == 2 && gametime % 2 >= 1) { | 2737 | } else { |
4992 | 2174 | continue; | 2738 | continue; |
4993 | 2175 | } | 2739 | } |
4994 | 2176 | if (bo.desc->get_size() == 3 && gametime % 4 >= 1) { | 2740 | if (bf->unowned_mines_spots_nearby > 2 && bo.mountain_conqueror) { |
4995 | 2177 | continue; | 2741 | prio += 5; |
4996 | 2178 | }; | 2742 | } |
4997 | 2179 | } else { | 2743 | prio += std::abs(management_data.get_military_number_at(35)) / 5 * |
4998 | 2180 | continue; | 2744 | (static_cast<int16_t>(bo.desc->get_conquers()) - |
4999 | 2181 | } // the building is not suitable for situation | 2745 | static_cast<int16_t>(bf->nearest_buildable_spot_nearby)); |
5000 | 2182 | 2746 | ||
4923 | 2183 | // score here is a compound of various input values | ||
4924 | 2184 | // usually resources in vicinity, but when enemy is nearby | ||
4925 | 2185 | // additional bonus is added | ||
4926 | 2186 | if (bf->enemy_nearby) { | ||
4927 | 2187 | prio += bf->military_loneliness / 3; | ||
4928 | 2188 | prio += (20 - bf->area_military_capacity) * 10; | ||
4929 | 2189 | prio -= bo.build_material_shortage * 50; | ||
4930 | 2190 | prio -= (bf->military_in_constr_nearby + bf->military_unstationed) * 50; | ||
4931 | 2191 | } else { | ||
4932 | 2192 | if (bf->near_border) { | ||
4933 | 2193 | prio += 50; | ||
4934 | 2194 | prio -= bo.build_material_shortage * 150; | ||
4935 | 2195 | } else { | ||
4936 | 2196 | prio -= bo.build_material_shortage * 500; // prohibitive | ||
4937 | 2197 | } | ||
4938 | 2198 | prio -= (bf->military_in_constr_nearby + bf->military_unstationed) * 150; | ||
4939 | 2199 | prio += (5 - bf->own_military_sites_nearby_()) * 15; | ||
4940 | 2200 | } | ||
4941 | 2201 | prio += bf->unconnected_nearby * 50; | ||
4942 | 2202 | prio += bf->unowned_land_nearby * resource_necessity_territory_ / 100; | ||
4943 | 2203 | prio += bf->unowned_mines_spots_nearby * resource_necessity_mines_ / 100; | ||
4944 | 2204 | prio += | ||
4945 | 2205 | ((bf->unowned_mines_spots_nearby > 0) ? 35 : 0) * resource_necessity_mines_ / 100; | ||
4946 | 2206 | prio += bf->rocks_nearby / 2; | ||
4947 | 2207 | prio += bf->water_nearby; | ||
4948 | 2208 | prio += bf->distant_water * resource_necessity_water_needed_ / 100; | ||
4949 | 2209 | prio += bf->military_loneliness / 10; | ||
4950 | 2210 | prio += bf->trees_nearby / 3; | ||
4951 | 2211 | if (bf->portspace_nearby == ExtendedBool::kTrue) { | ||
4952 | 2212 | if (num_ports == 0) { | ||
4953 | 2213 | prio += 100; | ||
4954 | 2214 | } else { | ||
4955 | 2215 | prio += 25; | ||
4956 | 2216 | } | ||
4957 | 2217 | } | ||
4958 | 2218 | // sometimes expansion is stalled and this is to help boost it | ||
4959 | 2219 | if (msites_in_constr() == 0 && vacant_mil_positions_ <= 2) { | ||
4960 | 2220 | prio += 10; | ||
4961 | 2221 | if (bf->enemy_nearby) { | ||
4962 | 2222 | prio += 20; | ||
4963 | 2223 | } | ||
4964 | 2224 | } | ||
4965 | 2225 | |||
4966 | 2226 | // additional score for bigger buildings | ||
4967 | 2227 | int32_t prio_for_size = bo.desc->get_size() - 1; | ||
4968 | 2228 | if (bf->enemy_nearby) { | ||
4969 | 2229 | prio_for_size *= 30; | ||
4970 | 2230 | } else { | ||
4971 | 2231 | prio_for_size *= 5; | ||
4972 | 2232 | } | ||
4973 | 2233 | prio += prio_for_size; |
@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_trainingsite s_proportion/ +merge/ 324607