~ubuntu-branches/ubuntu/precise/widelands/precise-backports

« back to all changes in this revision

Viewing changes to src/computer_player.cc

  • Committer: Bazaar Package Importer
  • Author(s): Martin Quinson
  • Date: 2005-02-14 10:41:12 UTC
  • Revision ID: james.westby@ubuntu.com-20050214104112-6v08iux9fptxpva9
Tags: upstream-build9
Import upstream version build9

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
 * Copyright (C) 2004 by The Widelands Development Team
 
3
 *
 
4
 * This program is free software; you can redistribute it and/or
 
5
 * modify it under the terms of the GNU General Public License
 
6
 * as published by the Free Software Foundation; either version 2
 
7
 * of the License, or (at your option) any later version.
 
8
 *
 
9
 * This program is distributed in the hope that it will be useful,
 
10
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 
11
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
12
 * GNU General Public License for more details.
 
13
 *
 
14
 * You should have received a copy of the GNU General Public License
 
15
 * along with this program; if not, write to the Free Software
 
16
 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 
17
 *
 
18
 */
 
19
 
 
20
#include "error.h"
 
21
#include "map.h"
 
22
#include "transport.h"
 
23
#include "player.h"
 
24
#include "tribe.h"
 
25
#include "constructionsite.h"
 
26
#include "computer_player.h"
 
27
 
 
28
class CheckStepRoadAI : public CheckStep {
 
29
public:
 
30
        CheckStepRoadAI(Player* player, uchar movecaps)
 
31
                : m_player(player), m_movecaps(movecaps) { }
 
32
 
 
33
        virtual bool allowed(Map* map, FCoords start, FCoords end, int dir, StepId id) const;
 
34
        virtual bool reachabledest(Map* map, FCoords dest) const;
 
35
 
 
36
private:
 
37
        Player*                                                 m_player;
 
38
        uchar                                                           m_movecaps;
 
39
};
 
40
 
 
41
Computer_Player::Computer_Player (Game *g, uchar pid)
 
42
{
 
43
        game = g;
 
44
        map = game->get_map();
 
45
        
 
46
        player_number = pid;
 
47
        player = g->get_player(player_number);
 
48
        tribe = player->get_tribe();
 
49
        
 
50
        log ("new Comp_Player for player %d\n", pid);
 
51
 
 
52
        // collect information about which buildings our tribe can construct
 
53
        for (int i=0; i<tribe->get_nrbuildings();i++) {
 
54
                const char* name=tribe->get_building_descr(i)->get_name();
 
55
                log ("\tcan build '%s', id is %d\n",name,i);
 
56
                
 
57
                BuildingObserver& bo=buildings[name];
 
58
                bo.id=i;
 
59
                bo.is_constructionsite=false;
 
60
                bo.cnt_built=0;
 
61
                bo.cnt_under_construction=0;
 
62
        }
 
63
        
 
64
        buildings["constructionsite"].is_constructionsite=true;
 
65
        
 
66
        total_constructionsites=0;
 
67
        delay_frontierhouse=0;
 
68
}
 
69
 
 
70
Computer_Player::~Computer_Player ()
 
71
{
 
72
}
 
73
 
 
74
void Computer_Player::think ()
 
75
{
 
76
/*      // update our fields 
 
77
        for (std::list<BuildableField>::iterator i=buildable_fields.begin(); i!=buildable_fields.end();) {
 
78
                // check whether we lost ownership of the field
 
79
                if (i->field->get_owned_by()!=player_number) {
 
80
                        log ("AI player %d lost field (%d,%d)\n", player_number, i->x, i->y);
 
81
                        i=buildable_fields.erase(i);
 
82
                        continue;
 
83
                }
 
84
                
 
85
                // check whether we can still build on the field
 
86
                if ((player->get_buildcaps(*i) & BUILDCAPS_SIZEMASK)==0) {
 
87
                        log ("Field (%d,%d) can no longer be built upon\n", i->x, i->y);
 
88
                        unusable_fields.push_back (*i);
 
89
                        i=buildable_fields.erase(i);
 
90
                        continue;
 
91
                }
 
92
                
 
93
                i++;
 
94
        }
 
95
        
 
96
        // update statistics about only one field at a time
 
97
        if (!buildable_fields.empty()) {
 
98
                update_buildable_field (buildable_fields.front());
 
99
                
 
100
                buildable_fields.push_back (buildable_fields.front());
 
101
                buildable_fields.pop_front ();
 
102
        }
 
103
 
 
104
        for (std::list<FCoords>::iterator i=unusable_fields.begin(); i!=unusable_fields.end();) {
 
105
                // check whether we lost ownership of the field
 
106
                if (i->field->get_owned_by()!=player_number) {
 
107
                        log ("AI player %d lost field (%d,%d)\n", player_number, i->x, i->y);
 
108
                        i=unusable_fields.erase(i);
 
109
                        continue;
 
110
                }
 
111
 
 
112
                // check whether building capabilities have improved
 
113
                if ((player->get_buildcaps(*i) & BUILDCAPS_SIZEMASK) != 0) {
 
114
                        log ("Field (%d,%d) can now be built upon\n", i->x, i->y);
 
115
                        buildable_fields.push_back (*i);
 
116
                        i=unusable_fields.erase(i);
 
117
 
 
118
                        update_buildable_field (buildable_fields.back());
 
119
                        continue;
 
120
                }
 
121
                
 
122
                i++;
 
123
        }
 
124
        
 
125
        // now build something if possible
 
126
        int proposed_building=-1;
 
127
        int proposed_priority=0;
 
128
        Coords proposed_coords;
 
129
        
 
130
        for (std::list<BuildableField>::iterator i=buildable_fields.begin(); i!=buildable_fields.end(); i++) {
 
131
                if (!i->reachable)
 
132
                        continue;
 
133
                
 
134
                int maxsize=i->field->get_caps() & BUILDCAPS_SIZEMASK;
 
135
                int prio;
 
136
                
 
137
                // frontierhouse
 
138
                if (delay_frontierhouse<=game->get_gametime()) {
 
139
                        prio=i->unowned_land;
 
140
                        prio-=i->frontierhouses*64;
 
141
                                
 
142
                        if (prio>proposed_priority) {
 
143
                                proposed_building=buildings["frontierhouse"].id;
 
144
                                proposed_priority=prio;
 
145
                                proposed_coords=*i;
 
146
                        }
 
147
                }
 
148
                
 
149
                // lumberjack
 
150
                prio=i->trees;
 
151
                prio-=i->lumberjacks*8;
 
152
                prio+=i->foresters*4;
 
153
                prio-=buildings["lumberjack"].cnt_built*4;
 
154
                prio-=buildings["lumberjack"].cnt_under_construction*16;
 
155
                
 
156
                if (maxsize>BUILDCAPS_SMALL)
 
157
                        prio-=6;
 
158
                
 
159
                if (prio>proposed_priority) {
 
160
                        proposed_building=buildings["lumberjack"].id;
 
161
                        proposed_priority=prio;
 
162
                        proposed_coords=*i;
 
163
                }
 
164
                
 
165
                // forester
 
166
                prio=-4;
 
167
                prio+=i->lumberjacks*4;
 
168
                prio-=i->foresters*12;
 
169
                prio-=buildings["forrester"].cnt_built*4;
 
170
                prio-=buildings["forrester"].cnt_under_construction*16;
 
171
                
 
172
                if (prio>proposed_priority) {
 
173
                        proposed_building=buildings["forrester"].id;
 
174
                        proposed_priority=prio;
 
175
                        proposed_coords=*i;
 
176
                }
 
177
                
 
178
                // quarry
 
179
                prio=i->stones;
 
180
                prio-=i->quarries*8;
 
181
                prio-=buildings["quarry"].cnt_built*4;
 
182
                prio-=buildings["quarry"].cnt_under_construction*16;
 
183
                
 
184
                if (maxsize>BUILDCAPS_SMALL)
 
185
                        prio-=6;
 
186
                
 
187
                if (prio>proposed_priority) {
 
188
                        proposed_building=buildings["quarry"].id;
 
189
                        proposed_priority=prio;
 
190
                        proposed_coords=*i;
 
191
                }
 
192
                
 
193
                // sawmill
 
194
                if (maxsize>=BUILDCAPS_MEDIUM) {
 
195
                        prio=8;
 
196
                        prio-=buildings["sawmill"].get_total_count() * 8;
 
197
                
 
198
                        if (prio>proposed_priority) {
 
199
                                proposed_building=buildings["sawmill"].id;
 
200
                                proposed_priority=prio;
 
201
                                proposed_coords=*i;
 
202
                        }
 
203
                }
 
204
                
 
205
                // farm
 
206
                if (maxsize==BUILDCAPS_BIG) {
 
207
                        prio=4;
 
208
                        prio-=buildings["farm"].get_total_count() * 2;
 
209
                        prio-=i->trees;
 
210
                        prio-=i->stones;
 
211
                        prio-=i->foresters*8;
 
212
                        if (total_constructionsites>4)
 
213
                                prio-=6;
 
214
                
 
215
                        if (prio>proposed_priority) {
 
216
                                proposed_building=buildings["farm"].id;
 
217
                                proposed_priority=prio;
 
218
                                proposed_coords=*i;
 
219
                        }
 
220
                }
 
221
                
 
222
                // mill
 
223
                if (maxsize>=BUILDCAPS_MEDIUM) {
 
224
                        prio=buildings["farm"].get_total_count() * 8;
 
225
                        prio-=buildings["mill"].get_total_count() * 8;
 
226
                        if (total_constructionsites>4)
 
227
                                prio-=6;
 
228
                
 
229
                        if (prio>proposed_priority) {
 
230
                                proposed_building=buildings["mill"].id;
 
231
                                proposed_priority=prio;
 
232
                                proposed_coords=*i;
 
233
                        }
 
234
                }
 
235
                
 
236
                // bakery
 
237
                if (maxsize>=BUILDCAPS_MEDIUM) {
 
238
                        prio=buildings["mill"].get_total_count() * 8;
 
239
                        prio-=buildings["bakery"].get_total_count() * 8;
 
240
                        if (total_constructionsites>4)
 
241
                                prio-=6;
 
242
                
 
243
                        if (prio>proposed_priority) {
 
244
                                proposed_building=buildings["bakery"].id;
 
245
                                proposed_priority=prio;
 
246
                                proposed_coords=*i;
 
247
                        }
 
248
                }
 
249
        }
 
250
        
 
251
        // if we want to construct a new building, send the command now
 
252
        if (proposed_building>=0) {
 
253
                game->send_player_build (player_number, proposed_coords, proposed_building);
 
254
                
 
255
                if (buildings["frontierhouse"].id==proposed_building)
 
256
                        delay_frontierhouse=game->get_gametime() + 10000;
 
257
                
 
258
                return;
 
259
        }
 
260
        
 
261
        // if nothing else is to do, update flags and economies
 
262
        while (!new_flags.empty()) {
 
263
                Flag* flag=new_flags.front();
 
264
                new_flags.pop_front();
 
265
                
 
266
                get_economy_observer(flag->get_economy()).flags.push_back (flag);
 
267
        }
 
268
        
 
269
        for (std::list<EconomyObserver>::iterator i=economies.begin(); i!=economies.end();) {
 
270
                // check if any flag has changed its economy
 
271
                for (std::list<Flag*>::iterator j=i->flags.begin(); j!=i->flags.end();) {
 
272
                        if (i->economy!=(*j)->get_economy()) {
 
273
                                log ("Flag at (%d,%d) changed economy\n", (*j)->get_position().x, (*j)->get_position().y);
 
274
                                
 
275
                                get_economy_observer((*j)->get_economy()).flags.push_back (*j);
 
276
                                j=i->flags.erase(j);
 
277
                                continue;
 
278
                        }
 
279
                        
 
280
                        j++;
 
281
                }
 
282
                
 
283
                // if there are no more flags in this economy, we no longer need its observer
 
284
                if (i->flags.empty()) {
 
285
                        i=economies.erase(i);
 
286
                        continue;
 
287
                }
 
288
                
 
289
                // try to connect to another economy
 
290
                if (economies.size()>1) {
 
291
                        connect_flag_to_another_economy (i->flags.front());
 
292
 
 
293
                        // cycle through flags one at a time
 
294
                        i->flags.push_back (i->flags.front());
 
295
                        i->flags.pop_front ();
 
296
                }
 
297
                
 
298
                i++;
 
299
        }
 
300
        
 
301
        // force a split on roads that are extremely long
 
302
        // note that having too many flags causes a loss of building capabilities
 
303
        if (!roads.empty()) {
 
304
                const Path& path=roads.front()->get_path();
 
305
                
 
306
                if (path.get_nsteps()>6) {
 
307
                        CoordPath cp(path);
 
308
                        int i;
 
309
                        
 
310
                        // try to split near the middle
 
311
                        for (i=0;i<cp.get_nsteps()/2-2;i++) {
 
312
                                Field* f;
 
313
                                
 
314
                                f=map->get_field(cp.get_coords()[cp.get_nsteps()/2-i]);
 
315
                                if ((f->get_caps()&BUILDCAPS_FLAG)!=0) {
 
316
                                        game->send_player_build_flag (player_number, cp.get_coords()[cp.get_nsteps()/2-i]);
 
317
                                        return;
 
318
                                }
 
319
                                
 
320
                                f=map->get_field(cp.get_coords()[cp.get_nsteps()/2+i+1]);
 
321
                                if ((f->get_caps()&BUILDCAPS_FLAG)!=0) {
 
322
                                        game->send_player_build_flag (player_number, cp.get_coords()[cp.get_nsteps()/2+i+1]);
 
323
                                        return;
 
324
                                }
 
325
                        }
 
326
                }
 
327
                
 
328
                roads.push_back (roads.front());
 
329
                roads.pop_front ();
 
330
        }
 
331
*/
 
332
}
 
333
 
 
334
struct FindFieldUnowned:FindField {
 
335
        virtual bool accept (const FCoords) const;
 
336
};
 
337
 
 
338
bool FindFieldUnowned::accept (const FCoords fc) const
 
339
{
 
340
        return fc.field->get_owned_by()==0;
 
341
}
 
342
 
 
343
void Computer_Player::update_buildable_field (BuildableField& field)
 
344
{
 
345
        // look if there is any unowned land nearby
 
346
        FindFieldUnowned find_unowned;
 
347
        
 
348
        field.unowned_land=map->find_fields(field, 8, 0, find_unowned);
 
349
        
 
350
        // collect information about resources in the area
 
351
        std::vector<ImmovableFound> immovables;
 
352
 
 
353
        const int tree_attr=Map_Object_Descr::get_attribute_id("tree");
 
354
        const int stone_attr=Map_Object_Descr::get_attribute_id("stone");
 
355
        
 
356
        map->find_immovables (field, 8, &immovables);
 
357
        
 
358
        field.reachable=false;  
 
359
        field.frontierhouses=0;
 
360
        field.lumberjacks=0;
 
361
        field.foresters=0;
 
362
        field.quarries=0;
 
363
        field.trees=0;
 
364
        field.stones=0;
 
365
        
 
366
        for (unsigned int i=0;i<immovables.size();i++) {
 
367
                if (immovables[i].object->get_type()>=BaseImmovable::BUILDING)
 
368
                        field.reachable=true;
 
369
 
 
370
                if (immovables[i].object->get_type()==BaseImmovable::BUILDING && map->calc_distance(field,immovables[i].coords)<=6) {
 
371
                        std::string name=static_cast<Building*>(immovables[i].object)->get_name();
 
372
                        
 
373
                        if (buildings[name].is_constructionsite)
 
374
                                name=static_cast<ConstructionSite*>(immovables[i].object)->get_building()->get_name();
 
375
                        
 
376
                        if (name=="frontierhouse")
 
377
                                field.frontierhouses++;
 
378
 
 
379
                        if (name=="lumberjack")
 
380
                                field.lumberjacks++;
 
381
 
 
382
                        if (name=="forrester")
 
383
                                field.foresters++;
 
384
 
 
385
                        if (name=="quarry")
 
386
                                field.quarries++;
 
387
 
 
388
                        continue;
 
389
                }
 
390
                
 
391
                if (immovables[i].object->has_attribute(tree_attr))
 
392
                        field.trees++;
 
393
 
 
394
                if (immovables[i].object->has_attribute(stone_attr))
 
395
                        field.stones++;
 
396
        }
 
397
}
 
398
 
 
399
Computer_Player::EconomyObserver& Computer_Player::get_economy_observer (Economy* economy)
 
400
{
 
401
        std::list<EconomyObserver>::iterator i;
 
402
        
 
403
        for (i=economies.begin(); i!=economies.end(); i++)
 
404
                if (i->economy==economy)
 
405
                        return *i;
 
406
        
 
407
        economies.push_front (EconomyObserver(economy));
 
408
        
 
409
        return economies.front();
 
410
}
 
411
 
 
412
void Computer_Player::gain_building (Building* b)
 
413
{
 
414
        BuildingObserver& bo=buildings[b->get_name()];
 
415
        
 
416
        if (bo.is_constructionsite) {
 
417
                buildings[static_cast<ConstructionSite*>(b)->get_building()->get_name()].cnt_under_construction++;
 
418
                total_constructionsites++;
 
419
        }
 
420
        else
 
421
                bo.cnt_built++;
 
422
}
 
423
 
 
424
void Computer_Player::lose_building (Building* b)
 
425
{
 
426
        BuildingObserver& bo=buildings[b->get_name()];
 
427
        
 
428
        if (bo.is_constructionsite) {
 
429
                buildings[static_cast<ConstructionSite*>(b)->get_building()->get_name()].cnt_under_construction--;
 
430
                total_constructionsites--;
 
431
        }
 
432
        else
 
433
                bo.cnt_built--;
 
434
}
 
435
 
 
436
// Road building
 
437
struct FindFieldWithFlagOrRoad:FindField {
 
438
        Economy* economy;
 
439
        virtual bool accept(FCoords coord) const;
 
440
};
 
441
 
 
442
bool FindFieldWithFlagOrRoad::accept (FCoords fc) const
 
443
{
 
444
        BaseImmovable* imm=fc.field->get_immovable();
 
445
        
 
446
        if (imm==0)
 
447
                return false;
 
448
        
 
449
        if (imm->get_type()>=BaseImmovable::BUILDING && static_cast<PlayerImmovable*>(imm)->get_economy()==economy)
 
450
                return false;
 
451
        
 
452
        if (imm->get_type()==BaseImmovable::FLAG)
 
453
                return true;
 
454
        
 
455
        if (imm->get_type()==BaseImmovable::ROAD && (fc.field->get_caps()&BUILDCAPS_FLAG)!=0)
 
456
                return true;
 
457
        
 
458
        return false;
 
459
}
 
460
 
 
461
void Computer_Player::connect_flag_to_another_economy (Flag* flag)
 
462
{
 
463
        FindFieldWithFlagOrRoad functor;
 
464
        CheckStepRoadAI check(player, MOVECAPS_WALK);
 
465
        std::vector<Coords> reachable;
 
466
        
 
467
        // first look for possible destinations
 
468
        functor.economy=flag->get_economy();
 
469
        map->find_reachable_fields (flag->get_position(), 16, &reachable, &check, functor);
 
470
        
 
471
        if (reachable.empty())
 
472
                return;
 
473
        
 
474
        // then choose the one closest to the originating flag
 
475
        int closest, distance;
 
476
        
 
477
        closest=0;
 
478
        distance=map->calc_distance(flag->get_position(), reachable[0]);
 
479
        for (unsigned int i=1; i<reachable.size(); i++) {
 
480
                int d=map->calc_distance(flag->get_position(), reachable[i]);
 
481
                
 
482
                if (d<distance) {
 
483
                    closest=i;
 
484
                    distance=d;
 
485
                }
 
486
        }
 
487
        
 
488
        // if we join a road and there is no flag yet, build one
 
489
        Field* field=map->get_field(reachable[closest]);
 
490
        if (field->get_immovable()->get_type()==BaseImmovable::ROAD)
 
491
                game->send_player_build_flag (player_number, reachable[closest]);
 
492
        
 
493
        // and finally build the road
 
494
        Path* path=new Path();
 
495
        if (map->findpath(flag->get_position(), reachable[closest], 0, path, &check) < 0)
 
496
                return;
 
497
        
 
498
        game->send_player_build_road (player_number, path);
 
499
}
 
500
 
 
501
// this is called whenever we gain ownership of a PlayerImmovable
 
502
void Computer_Player::gain_immovable (PlayerImmovable* pi)
 
503
{
 
504
        switch (pi->get_type()) {
 
505
            case BaseImmovable::BUILDING:
 
506
                gain_building (static_cast<Building*>(pi));
 
507
                break;
 
508
            case BaseImmovable::FLAG:
 
509
                new_flags.push_back (static_cast<Flag*>(pi));
 
510
                break;
 
511
            case BaseImmovable::ROAD:
 
512
                roads.push_front (static_cast<Road*>(pi));
 
513
                break;
 
514
        }
 
515
}
 
516
 
 
517
// this is called whenever we lose ownership of a PlayerImmovable
 
518
void Computer_Player::lose_immovable (PlayerImmovable* pi)
 
519
{
 
520
        switch (pi->get_type()) {
 
521
            case BaseImmovable::BUILDING:
 
522
                lose_building (static_cast<Building*>(pi));
 
523
                break;
 
524
            case BaseImmovable::ROAD:
 
525
                roads.remove (static_cast<Road*>(pi));
 
526
                break;
 
527
        }
 
528
}
 
529
 
 
530
// this is called whenever we gain ownership of a field on the map
 
531
void Computer_Player::gain_field (const FCoords& fc)
 
532
{
 
533
        unusable_fields.push_back (fc);
 
534
}
 
535
 
 
536
// we don't use this - instead we check or fields regularly, see think()
 
537
void Computer_Player::lose_field (const FCoords& fc)
 
538
{
 
539
}
 
540
 
 
541
 
 
542
/* CheckStepRoadAI */
 
543
bool CheckStepRoadAI::allowed(Map* map, FCoords start, FCoords end, int dir, StepId id) const
 
544
{
 
545
        uchar endcaps = m_player->get_buildcaps(end);
 
546
 
 
547
        // Calculate cost and passability
 
548
        if (!(endcaps & m_movecaps)) {
 
549
                uchar startcaps = m_player->get_buildcaps(start);
 
550
 
 
551
                if (!((endcaps & MOVECAPS_WALK) && (startcaps & m_movecaps & MOVECAPS_SWIM)))
 
552
                        return false;
 
553
        }
 
554
 
 
555
        // Check for blocking immovables
 
556
        BaseImmovable *imm = map->get_immovable(end);
 
557
        if (imm && imm->get_size() >= BaseImmovable::SMALL) {
 
558
//              if (id != stepLast)
 
559
//                      return false;
 
560
                if (imm->get_type()==Map_Object::FLAG)
 
561
                        return true;
 
562
 
 
563
                if ((imm->get_type() != Map_Object::ROAD || !(endcaps & BUILDCAPS_FLAG)))
 
564
                        return false;
 
565
        }
 
566
 
 
567
        return true;
 
568
}
 
569
 
 
570
bool CheckStepRoadAI::reachabledest(Map* map, FCoords dest) const
 
571
{
 
572
        uchar caps = dest.field->get_caps();
 
573
 
 
574
        if (!(caps & m_movecaps)) {
 
575
                if (!((m_movecaps & MOVECAPS_SWIM) && (caps & MOVECAPS_WALK)))
 
576
                        return false;
 
577
 
 
578
                if (!map->can_reach_by_water(dest))
 
579
                        return false;
 
580
        }
 
581
 
 
582
        return true;
 
583
}
 
584
 
 
585