Merge lp:~widelands-dev/widelands/bug-1746481 into lp:widelands

Proposed by TiborB
Status: Work in progress
Proposed branch: lp:~widelands-dev/widelands/bug-1746481
Merge into: lp:widelands
Diff against target: 151 lines (+64/-12)
4 files modified
src/ai/ai_help_structs.h (+1/-0)
src/ai/defaultai.cc (+43/-12)
src/ai/defaultai_warfare.cc (+11/-0)
src/main.cc (+9/-0)
To merge this branch: bzr merge lp:~widelands-dev/widelands/bug-1746481
Reviewer Review Type Date Requested Status
Widelands Developers Pending
Review via email: mp+337125@code.launchpad.net

Description of the change

AI now considers a building needed for 'basic economy' finished only if fully occupied.
I left one DEBUG log in the code for a tester (contains word DEBUG).
There is some short gap between a building gets occupied and AI recognizes it. And this can cause inconsistency when a game is saved just during such period. But should not be very frequent....
After testing is done, I will remove NOCOM lines.

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

Continuous integration builds have changed state:

Travis build 3135. State: failed. Details: https://travis-ci.org/widelands/widelands/builds/337068986.
Appveyor build 2942. State: success. Details: https://ci.appveyor.com/project/widelands-dev/widelands/build/_widelands_dev_widelands_bug_1746481-2942.

Revision history for this message
TiborB (tiborb95) wrote :

Codecheck complains about printfs, but these are only for temporary DEBUG logs and will be removed before merge...

Revision history for this message
R M (weedfreak) wrote :

Testing this the AI was set up with

1: Initializing in the basic economy mode, required buildings:
     97 / empire_tavern               - target 1
     95 / empire_winery               - target 1
     84 / empire_foresters_house      - target 2
    117 / empire_marblemine           - target 1
     83 / empire_lumberjacks_house    - target 2
     90 / empire_sawmill              - target 2
    106 / empire_farm                 - target 1
     89 / empire_stonemasons_house    - target 1
     92 / empire_bakery               - target 1
     94 / empire_vineyard             - target 1

  which it then ignored, it built
     empire_tavern               - 1
     empire_winery               - 1
     empire_foresters_house      - 7
     empire_marblemine           - 0
     empire_lumberjacks_house    - 6
     empire_sawmill              - 3
     empire_farm                 -1
     empire_stonemasons_house    - 2
     empire_bakery               - target 3
     empire_vineyard             - target 2

After an hour it started building training sites despite having no mines
or mills for wheat. Eventually it built a marble mine, but 5 minutes
later it had still not announced the basic economy established. Loading
from a save game did not work as I did not have a zipped save, will try
that next.

Checking the terminal there ws no debug message for the mine so perhaps
I was not patient enough.

Revision history for this message
TiborB (tiborb95) wrote :

Everytime a site is occupied for the first time you should see this DEBUG log: https://bazaar.launchpad.net/~widelands-dev/widelands/bug-1746481/view/head:/src/ai/defaultai.cc#L3706

The problem could had been printf() in my code, I just pushed new branch which uses log() to print these logs. If this still not print these DEBUG logs something must be messed up.

From your prescription, only problem you found was that it built a trainingsite before the basic economy was achieved. Yes, there is genetic algorithm involved there that under some circumstances allows trainingsites before basic economy. This is question of course, if this should be allowed...

Revision history for this message
R M (weedfreak) wrote :

The gap between the building being finished and being recognised seems
to increase with game time, the first few are almost instantaneous as
the worker reaches the buildings flag, later it occurs just after
occupation.

This run the vineyard was not built until after 8 foresters so there was
no shovel left and thus no worker but the message DEBUG: empire_vineyard
first time occupied appeared, incorrectly, after a few minutes.

Loading save games has not, so far produced any problems, but it may
still be a problem later in game when the delay gets greater.

Revision history for this message
TiborB (tiborb95) wrote :

INDEED, I see a problem (in the code) now. I will fix and let you know...

Revision history for this message
R M (weedfreak) wrote :

I am not sure what code problem you have found but further testing shows
no problem later in game with saves, the marble mine does not produce a
debug message after 20 minutes and when a basic economy building is
built but not occupied the AI starts building another of that building,
so that was why there were 3 sawmills, 2 stonemasons, 2 bakeries and 2
vineyards etc. most were started when the worker was on the way.

On 06/02/18 13:12, TiborB wrote:
> INDEED, I see a problem (in the code) now. I will fix and let you know...

Revision history for this message
TiborB (tiborb95) wrote :

I omit to incorporate can_start_working() function to the check altogether, it simply cannot work properly....

Revision history for this message
TiborB (tiborb95) wrote :

Please try once more..

Revision history for this message
R M (weedfreak) wrote :

The woodcutter first occupied debug message is printed twice, most basic
economy buildings are built one more than the basic setting. The marble
mine, which is built twice, does not give a debug message and no message
for basic economy reached is given. The marble mines were the last basic
economy buildings built and I ran the game for an hour afterwards.

To be certain the vineyard was occupied I prohibited foresters for 600
so there was at least one shovel in stock.

Revision history for this message
TiborB (tiborb95) wrote :

Weird, the code look straightforward in this regard... I will have to test it myself.

No save&load was involved I presume.....

Revision history for this message
TiborB (tiborb95) wrote :

I probably know what is going on. The problem is a gap when a building exists and is not occupied yet (scratched from the list)
AI when considering new buildings tests:
- it is on the list of (missing) basic buildings
- none is in construction

I have to rethink this

Revision history for this message
GunChleoc (gunchleoc) wrote :

You probably need 2 lists, one with the buildings to build, and one with the buildings built. The buildings built list can then be checked whether they're occupied and if so, be removed from the second list.

Or you can expand the first list with number of buildings built and only build new buildings if there is a difference. Then remove fro the list if all buildings are occupied.

Regarding printf, that function is insecure and should be replaced with sprintf in all cases - our custom-built log function will do that for you. You also accidentally added a long list of "#include <unistd.h>" to main.cc in the commit that fixed the printf.

Revision history for this message
TiborB (tiborb95) wrote :

Yes, single list will not do. And I have to pay attention to the game saving aspect as well.

I spent a lot of time with another branch - findpath_modification, and if this will be OK now, I can come back to this...

Revision history for this message
GunChleoc (gunchleoc) wrote :

Is this branch ready for review? We should get rid of the extra lines in src/main.cc in any case.

Revision history for this message
TiborB (tiborb95) wrote :

No, I have not touched it since the last discussion. I am still not sure how to approach this. We can cancel this merge proposal....

Revision history for this message
GunChleoc (gunchleoc) wrote :

OK, I have set it back to "Work in Progress"

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'src/ai/ai_help_structs.h'
2--- src/ai/ai_help_structs.h 2017-11-17 07:16:12 +0000
3+++ src/ai/ai_help_structs.h 2018-02-06 19:41:40 +0000
4@@ -436,6 +436,7 @@
5 uint32_t current_stats;
6
7 uint32_t basic_amount; // basic amount for basic economy as defined in init.lua
8+ bool never_occupied; //this switches
9
10 std::vector<Widelands::DescriptionIndex> inputs;
11 std::vector<Widelands::DescriptionIndex> outputs;
12
13=== modified file 'src/ai/defaultai.cc'
14--- src/ai/defaultai.cc 2018-01-30 11:44:48 +0000
15+++ src/ai/defaultai.cc 2018-02-06 19:41:40 +0000
16@@ -3702,6 +3702,16 @@
17 // Get link to productionsite that should be checked
18 ProductionSiteObserver& site = productionsites.front();
19
20+ if (site.bo->never_occupied && persistent_data->remaining_basic_buildings.count(site.bo->id) > 0 && site.site->can_start_working()) {
21+ log ("DEBUG: %s first time occupied\n", site.bo->name); // NOCOM
22+ if (persistent_data->remaining_basic_buildings[site.bo->id] > 1) {
23+ --persistent_data->remaining_basic_buildings[site.bo->id];
24+ } else {
25+ persistent_data->remaining_basic_buildings.erase(site.bo->id);
26+ }
27+ site.bo->never_occupied = false;
28+ }
29+
30 // Inform if we are above ai type limit.
31 if (site.bo->total_count() > site.bo->cnt_limit_by_aimode) {
32 log("AI check_productionsites: Too many %s: %d, ai limit: %d\n", site.bo->name,
33@@ -4182,6 +4192,16 @@
34 // Get link to productionsite that should be checked
35 ProductionSiteObserver& site = mines_.front();
36
37+ if (site.bo->never_occupied && persistent_data->remaining_basic_buildings.count(site.bo->id) > 0 && site.site->can_start_working()) {
38+ log ("DEBUG: %s first time occupied\n", site.bo->name); // NOCOM
39+ if (persistent_data->remaining_basic_buildings[site.bo->id] > 1) {
40+ --persistent_data->remaining_basic_buildings[site.bo->id];
41+ } else {
42+ persistent_data->remaining_basic_buildings.erase(site.bo->id);
43+ }
44+ site.bo->never_occupied = false;
45+ }
46+
47 const bool connected_to_wh = !site.site->get_economy()->warehouses().empty();
48
49 // First we dismantle mines that are marked as such, generally we wait till all wares all gone
50@@ -5748,18 +5768,6 @@
51 ++bo.cnt_built;
52 const uint32_t gametime = game().get_gametime();
53 bo.last_building_built = gametime;
54- // erase building from remaining_basic_buildings, unless we are loading a saved game
55- if (!found_on_load && persistent_data->remaining_basic_buildings.count(bo.id) > 0) {
56- if (persistent_data->remaining_basic_buildings[bo.id] > 1) {
57- --persistent_data->remaining_basic_buildings[bo.id];
58- } else {
59- persistent_data->remaining_basic_buildings.erase(bo.id);
60- }
61- }
62- // Remaining basic buildings map contain either no entry for the building, or the number is
63- // nonzero
64- assert(persistent_data->remaining_basic_buildings.count(bo.id) == 0 ||
65- persistent_data->remaining_basic_buildings[bo.id] > 0);
66
67 if (bo.type == BuildingObserver::Type::kProductionsite) {
68 productionsites.push_back(ProductionSiteObserver());
69@@ -5786,6 +5794,14 @@
70
71 for (uint32_t i = 0; i < bo.inputs.size(); ++i)
72 ++wares.at(bo.inputs.at(i)).consumers;
73+
74+ if (!found_on_load) {
75+ // If this is brand new building, setting as never occupied
76+ bo.never_occupied = true;
77+ } else {
78+ // otherwise just find out
79+ bo.never_occupied = !productionsites.back().site->can_start_working();
80+ }
81 } else if (bo.type == BuildingObserver::Type::kMine) {
82 mines_.push_back(ProductionSiteObserver());
83 mines_.back().site = &dynamic_cast<ProductionSite&>(b);
84@@ -5810,6 +5826,14 @@
85
86 set_inputs_to_zero(mines_.back());
87
88+
89+ // If this is brand new building, setting as never occupied
90+ if (!found_on_load) {
91+ bo.never_occupied = false;
92+ } else {
93+ // otherwise just find out
94+ bo.never_occupied = productionsites.back().site->can_start_working();
95+ }
96 } else if (bo.type == BuildingObserver::Type::kMilitarysite) {
97 militarysites.push_back(MilitarySiteObserver());
98 militarysites.back().site = &dynamic_cast<MilitarySite&>(b);
99@@ -5829,6 +5853,13 @@
100 trainingsites.push_back(TrainingSiteObserver());
101 trainingsites.back().site = &dynamic_cast<TrainingSite&>(b);
102 trainingsites.back().bo = &bo;
103+ // If this is brand new building, setting as never occupied
104+ if (!found_on_load) {
105+ bo.never_occupied = false;
106+ } else {
107+ // otherwise just find out
108+ bo.never_occupied = productionsites.back().site->can_start_working();
109+ }
110
111 } else if (bo.type == BuildingObserver::Type::kWarehouse) {
112 ++numof_warehouses_;
113
114=== modified file 'src/ai/defaultai_warfare.cc'
115--- src/ai/defaultai_warfare.cc 2017-11-13 09:10:04 +0000
116+++ src/ai/defaultai_warfare.cc 2018-02-06 19:41:40 +0000
117@@ -575,6 +575,17 @@
118 TrainingSite* ts = trainingsites.front().site;
119 TrainingSiteObserver& tso = trainingsites.front();
120
121+ // In case this trainingsite is among basic buildings
122+ if (tso.bo->never_occupied && persistent_data->remaining_basic_buildings.count(tso.bo->id) > 0 && tso.site->can_start_working()) {
123+ printf ("DEBUG: %s first time occupied - erasing from basic economy list\n", tso.bo->name); //NOCOM
124+ if (persistent_data->remaining_basic_buildings[tso.bo->id] > 1) {
125+ --persistent_data->remaining_basic_buildings[tso.bo->id];
126+ } else {
127+ persistent_data->remaining_basic_buildings.erase(tso.bo->id);
128+ }
129+ tso.bo->never_occupied = false;
130+ }
131+
132 // Inform if we are above ai type limit.
133 if (tso.bo->total_count() > tso.bo->cnt_limit_by_aimode) {
134 log("AI check_trainingsites: AI player %d: count of %s exceeds an AI limit %d: actual count: "
135
136=== modified file 'src/main.cc'
137--- src/main.cc 2017-06-16 06:03:23 +0000
138+++ src/main.cc 2018-02-06 19:41:40 +0000
139@@ -1,3 +1,12 @@
140+#include <unistd.h>
141+#include <unistd.h>
142+#include <unistd.h>
143+#include <unistd.h>
144+#include <unistd.h>
145+#include <unistd.h>
146+#include <unistd.h>
147+#include <unistd.h>
148+#include <unistd.h>
149 /*
150 * Copyright (C) 2002-2017 by the Widelands Development Team
151 *

Subscribers

People subscribed via source and target branches

to status/vote changes: