summaryrefslogtreecommitdiffstats
path: root/pacman-c++
diff options
context:
space:
mode:
authormanuel <manuel@mausz.at>2011-04-18 19:47:34 +0200
committermanuel <manuel@mausz.at>2011-04-18 19:47:34 +0200
commit85b09864f6d489e8c998e9f172d25079d572c602 (patch)
treea6e38da5dc828810b21045d0ac1e4babcf198825 /pacman-c++
parente373442901064d07791c9739daa380acb1dfbb8c (diff)
downloadfoop-85b09864f6d489e8c998e9f172d25079d572c602.tar.gz
foop-85b09864f6d489e8c998e9f172d25079d572c602.tar.bz2
foop-85b09864f6d489e8c998e9f172d25079d572c602.zip
- add actor.canEat(other) to check if actor can eat other (note: that doesn't mean that other can eat actor!!)
- server now generated and sends the colorlist to the server in the first map update packet - add a better AI
Diffstat (limited to 'pacman-c++')
-rw-r--r--pacman-c++/actor.cpp9
-rw-r--r--pacman-c++/actor.h1
-rw-r--r--pacman-c++/constants.h11
-rw-r--r--pacman-c++/mainwidget.cpp12
-rw-r--r--pacman-c++/pacman.proto5
-rw-r--r--pacman-c++/sceneholder.cpp10
-rw-r--r--pacman-c++/sceneholder.h9
-rw-r--r--pacman-c++/server.cpp145
-rw-r--r--pacman-c++/server.h2
9 files changed, 170 insertions, 34 deletions
diff --git a/pacman-c++/actor.cpp b/pacman-c++/actor.cpp
index 9ff51f3..cf3fc13 100644
--- a/pacman-c++/actor.cpp
+++ b/pacman-c++/actor.cpp
@@ -193,6 +193,15 @@ bool Actor::isMoving()
193 return (m_moving->state() == QAbstractAnimation::Running); 193 return (m_moving->state() == QAbstractAnimation::Running);
194} 194}
195 195
196bool Actor::canEat(Actor *other, const QList<Color::Color> &order)
197{
198 if (other == NULL || order.empty() || m_color == other->color())
199 return false;
200
201 int idx = order.indexOf(m_color);
202 return (order.at(idx + 1) == other->color());
203}
204
196void Actor::die() 205void Actor::die()
197{ 206{
198 if (!m_local) 207 if (!m_local)
diff --git a/pacman-c++/actor.h b/pacman-c++/actor.h
index 902951b..41ad232 100644
--- a/pacman-c++/actor.h
+++ b/pacman-c++/actor.h
@@ -42,6 +42,7 @@ public:
42 void eatingPacman(); 42 void eatingPacman();
43 void startEating(); 43 void startEating();
44 void stopEating(); 44 void stopEating();
45 bool canEat(Actor *other, const QList<Color::Color> &order);
45 46
46 unsigned int getRoundPoints(); 47 unsigned int getRoundPoints();
47 unsigned int getGamePoints(); 48 unsigned int getGamePoints();
diff --git a/pacman-c++/constants.h b/pacman-c++/constants.h
index dc72611..20a0e15 100644
--- a/pacman-c++/constants.h
+++ b/pacman-c++/constants.h
@@ -41,6 +41,17 @@ namespace Constants {
41 const unsigned int colorize_block_tickcount_min = 50; 41 const unsigned int colorize_block_tickcount_min = 50;
42 const unsigned int colorize_block_tickcount_max = 100; 42 const unsigned int colorize_block_tickcount_max = 100;
43 } 43 }
44
45 namespace AI
46 {
47 /* bots minimum manhatten distance before other players will be recognized */
48 const unsigned int player_minimum_distance = 4;
49 /* weight values used to determine new direction of bot */
50 const unsigned int weight_afraid = 50;
51 const unsigned int weight_hunt = 10;
52 const unsigned int weight_bonus_point = 3;
53 const unsigned int weight_point = 1;
54 }
44} 55}
45 56
46namespace Color 57namespace Color
diff --git a/pacman-c++/mainwidget.cpp b/pacman-c++/mainwidget.cpp
index c674c55..42abd01 100644
--- a/pacman-c++/mainwidget.cpp
+++ b/pacman-c++/mainwidget.cpp
@@ -6,7 +6,8 @@
6#include "pacman.pb.h" 6#include "pacman.pb.h"
7 7
8MainWidget::MainWidget(QWidget *parent) 8MainWidget::MainWidget(QWidget *parent)
9 : QWidget(parent), m_currentKey(Transmission::none), m_running(false), m_maxplayers(0) 9 : QWidget(parent), m_currentKey(Transmission::none), m_running(false), m_scene(NULL),
10 m_maxplayers(0)
10{ 11{
11 /* create audio player */ 12 /* create audio player */
12 m_ambientPlayer = new GaplessAudioPlayer(Sound::Ambient, 100, this); 13 m_ambientPlayer = new GaplessAudioPlayer(Sound::Ambient, 100, this);
@@ -146,6 +147,15 @@ void MainWidget::tick()
146 bool worked = m_updatepacket.ParseFromArray(data->data(), data->size()); 147 bool worked = m_updatepacket.ParseFromArray(data->data(), data->size());
147 Q_ASSERT(worked); 148 Q_ASSERT(worked);
148 Q_UNUSED(worked); 149 Q_UNUSED(worked);
150
151 if (m_updatepacket.eating_order_size() > 0)
152 {
153 Q_ASSERT(m_scene != NULL);
154 QList<Color::Color> order;
155 for(int i = 0; i < m_updatepacket.eating_order_size(); ++i)
156 order.append(static_cast<Color::Color>(m_updatepacket.eating_order(i) & Transmission::color_mask));
157 }
158
149 Transmission::map_t map = Util::createUninitialisedMap(); 159 Transmission::map_t map = Util::createUninitialisedMap();
150 Q_ASSERT(m_updatepacket.field_size() == (int) (Constants::map_size.width * Constants::map_size.height)); 160 Q_ASSERT(m_updatepacket.field_size() == (int) (Constants::map_size.width * Constants::map_size.height));
151 int i = 0; 161 int i = 0;
diff --git a/pacman-c++/pacman.proto b/pacman-c++/pacman.proto
index 51bb239..8e088e8 100644
--- a/pacman-c++/pacman.proto
+++ b/pacman-c++/pacman.proto
@@ -9,13 +9,10 @@ message Init {
9 required uint32 maxplayers = 2; 9 required uint32 maxplayers = 2;
10} 10}
11 11
12message MapInit {
13 repeated uint32 field = 1 [packed=true];
14}
15
16message MapUpdate { 12message MapUpdate {
17 repeated uint32 field = 1 [packed=true]; 13 repeated uint32 field = 1 [packed=true];
18 repeated uint32 round_points = 2; 14 repeated uint32 round_points = 2;
19 repeated uint32 game_points = 3; 15 repeated uint32 game_points = 3;
16 repeated uint32 eating_order = 4;
20} 17}
21 18
diff --git a/pacman-c++/sceneholder.cpp b/pacman-c++/sceneholder.cpp
index 578b0df..dace711 100644
--- a/pacman-c++/sceneholder.cpp
+++ b/pacman-c++/sceneholder.cpp
@@ -197,6 +197,16 @@ void SceneHolder::decrementPoints()
197 --m_pointsLeft; 197 --m_pointsLeft;
198} 198}
199 199
200void SceneHolder::setEatingOrder(QList<Color::Color> &order)
201{
202 m_eatingorder = order;
203}
204
205QList<Color::Color> &SceneHolder::eatingOrder()
206{
207 return m_eatingorder;
208}
209
200QPoint SceneHolder::mapPositionToCoord(unsigned int x, unsigned int y) 210QPoint SceneHolder::mapPositionToCoord(unsigned int x, unsigned int y)
201{ 211{
202 return QPoint(x * Constants::field_size.width, y * Constants::field_size.height); 212 return QPoint(x * Constants::field_size.width, y * Constants::field_size.height);
diff --git a/pacman-c++/sceneholder.h b/pacman-c++/sceneholder.h
index 418f16b..69ee598 100644
--- a/pacman-c++/sceneholder.h
+++ b/pacman-c++/sceneholder.h
@@ -21,6 +21,8 @@ public:
21 void updateMap(const Transmission::map_t& map, const unsigned int x, const unsigned int y); 21 void updateMap(const Transmission::map_t& map, const unsigned int x, const unsigned int y);
22 void setColor(Color::Color color = Color::none); 22 void setColor(Color::Color color = Color::none);
23 Color::Color color(); 23 Color::Color color();
24 void setEatingOrder(QList<Color::Color> &order);
25 QList<Color::Color> &eatingOrder();
24 26
25private slots: 27private slots:
26 void decrementPoints(); 28 void decrementPoints();
@@ -46,6 +48,13 @@ protected:
46 /* my local color */ 48 /* my local color */
47 Color::Color m_color; 49 Color::Color m_color;
48 50
51 /* a actor can only eat his upper neighbour
52 * the order of the neighbours is determined by the colors order (sent from server)
53 * please note that !pl1.canEat(pl2, ...) doesn't necessarily mean that pl2 can eat pl1
54 * order MUST be in this format: [col1, [col2, ..., colN], col1]
55 */
56 QList<Color::Color> m_eatingorder;
57
49 /* points left before round ends */ 58 /* points left before round ends */
50 unsigned int m_pointsLeft; 59 unsigned int m_pointsLeft;
51}; 60};
diff --git a/pacman-c++/server.cpp b/pacman-c++/server.cpp
index 65a8f8b..4219a43 100644
--- a/pacman-c++/server.cpp
+++ b/pacman-c++/server.cpp
@@ -19,6 +19,11 @@ Server::Server(QWidget *parent)
19 19
20bool Server::run() 20bool Server::run()
21{ 21{
22 /* create eating order list first - this can also be created dynamically per round (theoretically) */
23 for(unsigned i = 0; i < m_maxplayers; ++i)
24 m_eatingorder.append(Color::order[i]);
25 m_eatingorder.append(Color::order[0]);
26
22 qDebug() << "[Server] Running server..."; 27 qDebug() << "[Server] Running server...";
23 qDebug() << "[Server] Max players:" << m_maxplayers; 28 qDebug() << "[Server] Max players:" << m_maxplayers;
24 qDebug() << "[Server] Number of bots:" << m_numbots; 29 qDebug() << "[Server] Number of bots:" << m_numbots;
@@ -42,7 +47,7 @@ bool Server::run()
42 } 47 }
43 48
44 updateMap(map); 49 updateMap(map);
45 sendUpdate(map); 50 sendUpdate(map, true);
46 Util::deleteMap(map); 51 Util::deleteMap(map);
47 map = NULL; 52 map = NULL;
48 53
@@ -55,7 +60,7 @@ bool Server::run()
55void Server::tick() 60void Server::tick()
56{ 61{
57 //qDebug() << "[Tick] Doing server update"; 62 //qDebug() << "[Tick] Doing server update";
58 foreach(Color::Color color, m_bots) 63 foreach (Color::Color color, m_bots)
59 botCalculate(m_actors[color]); 64 botCalculate(m_actors[color]);
60 Transmission::map_t map = calculateUpdates(); 65 Transmission::map_t map = calculateUpdates();
61 updateMap(map); 66 updateMap(map);
@@ -218,7 +223,7 @@ void Server::colorizeBlocks(Transmission::map_t map)
218 { 223 {
219 /* check for actor collision */ 224 /* check for actor collision */
220 bool skip = false; 225 bool skip = false;
221 foreach(Actor *actor, m_actors) 226 foreach (Actor *actor, m_actors)
222 { 227 {
223 if (CoordToMapPosition(actor->pos().toPoint()) == i.key()) 228 if (CoordToMapPosition(actor->pos().toPoint()) == i.key())
224 skip = true; 229 skip = true;
@@ -272,6 +277,7 @@ bool Server::waitForClientConnections()
272 277
273 qDebug() << "[Server] Waiting for clients"; 278 qDebug() << "[Server] Waiting for clients";
274 ProtoBuf::Init packet; 279 ProtoBuf::Init packet;
280 packet.set_maxplayers(m_maxplayers);
275 for (unsigned int i = 0; i < (m_maxplayers - m_numbots); ++i) 281 for (unsigned int i = 0; i < (m_maxplayers - m_numbots); ++i)
276 { 282 {
277 bool connectionAvailable = tcpSrv->waitForNewConnection(-1); 283 bool connectionAvailable = tcpSrv->waitForNewConnection(-1);
@@ -284,7 +290,6 @@ bool Server::waitForClientConnections()
284 Color::Color color = Color::order[i]; 290 Color::Color color = Color::order[i];
285 m_clientConnections[color] = socket; 291 m_clientConnections[color] = socket;
286 packet.set_color(color); 292 packet.set_color(color);
287 packet.set_maxplayers(m_maxplayers);
288 Util::sendPacket(packet, socket); 293 Util::sendPacket(packet, socket);
289 qDebug() << "[Connect] New Player: color=" << color; 294 qDebug() << "[Connect] New Player: color=" << color;
290 } 295 }
@@ -299,7 +304,7 @@ bool Server::waitForClientConnections()
299 return true; 304 return true;
300} 305}
301 306
302void Server::sendUpdate(Transmission::map_t map) 307void Server::sendUpdate(Transmission::map_t map, bool firstPacket)
303{ 308{
304 m_updatepacket.Clear(); 309 m_updatepacket.Clear();
305 310
@@ -315,6 +320,13 @@ void Server::sendUpdate(Transmission::map_t map)
315 m_updatepacket.add_game_points(m_actors.value(Color::order[i])->getGamePoints()); 320 m_updatepacket.add_game_points(m_actors.value(Color::order[i])->getGamePoints());
316 } 321 }
317 322
323 /* we send the eating_order inside the first packet */
324 if (firstPacket)
325 {
326 foreach(Color::Color color, m_eatingorder)
327 m_updatepacket.add_eating_order(color);
328 }
329
318 QSharedPointer<QByteArray> data = Util::createPacket(m_updatepacket); 330 QSharedPointer<QByteArray> data = Util::createPacket(m_updatepacket);
319 QMutableMapIterator<Color::Color, QTcpSocket *> i(m_clientConnections); 331 QMutableMapIterator<Color::Color, QTcpSocket *> i(m_clientConnections);
320 while(i.hasNext()) 332 while(i.hasNext())
@@ -349,53 +361,125 @@ void Server::botCalculate(Actor *actor)
349 QPoint actorpos = CoordToMapPosition(actor->pos().toPoint()); 361 QPoint actorpos = CoordToMapPosition(actor->pos().toPoint());
350 362
351 /* first make list of possible directions based on current actor position */ 363 /* first make list of possible directions based on current actor position */
352 QList<Actor::Movement> directions; 364 QHash<Actor::Movement, unsigned int> directions;
353 if (actorpos.x() > 0) 365 if (actorpos.x() > 0)
354 directions.append(Actor::Left); 366 directions.insert(Actor::Left, 0);
355 if (actorpos.x() < visualMap.size() - 1) 367 if (actorpos.x() < visualMap.size() - 1)
356 directions.append(Actor::Right); 368 directions.insert(Actor::Right, 0);
357 if (actorpos.y() > 0) 369 if (actorpos.y() > 0)
358 directions.append(Actor::Up); 370 directions.insert(Actor::Up, 0);
359 if (actorpos.y() < visualMap[actorpos.x()].size() - 1) 371 if (actorpos.y() < visualMap[actorpos.x()].size() - 1)
360 directions.append(Actor::Down); 372 directions.insert(Actor::Down, 0);
361 373
362 /* copy of directions: used if there's no good direction based on rules */ 374 /* check neighbours for blocks first */
363 QList<Actor::Movement> directions2(directions); 375 QMutableHashIterator<Actor::Movement, unsigned int> i(directions);
364
365 QMutableListIterator<Actor::Movement> i(directions);
366 while(i.hasNext()) 376 while(i.hasNext())
367 { 377 {
368 i.next(); 378 i.next();
369 Actor::Movement direction = i.value(); 379 QPoint newpos = actorpos + Actor::movementToPoint(i.key());
370 QPoint pos = actorpos + Actor::movementToPoint(direction); 380 if (newpos.x() < 0 || newpos.x() >= visualMap.size())
371 if (pos.x() < 0 || pos.x() >= visualMap.size())
372 continue; 381 continue;
373 if (pos.y() < 0 || pos.y() >= visualMap[pos.x()].size()) 382 if (newpos.y() < 0 || newpos.y() >= visualMap[newpos.x()].size())
374 continue; 383 continue;
375 GameEntity *item = visualMap[pos.x()][pos.y()]; 384 GameEntity *item = visualMap[newpos.x()][newpos.y()];
376 385
377 /* check if neighbour is a block */ 386 /* check if neighbour is a block */
378 Block *block = qgraphicsitem_cast<Block *>(item); 387 Block *block = qgraphicsitem_cast<Block *>(item);
379 if (block != NULL && block->color() != actor->color()) 388 if (block != NULL && block->color() != actor->color())
380 { 389 {
381 i.remove(); 390 i.remove();
382 directions2.removeAll(direction);
383 continue; 391 continue;
384 } 392 }
393 }
394
395 /* we're enclosed by blocks */
396 if (directions.empty())
397 return;
398
399 /* determine if other actors are in range to afraid/hunt*/
400 int mindistance = Constants::AI::player_minimum_distance;
401 QList<QPoint> pos_afraid;
402 QList<QPoint> pos_hunt;
403 foreach (Actor *other, m_actors)
404 {
405 if (actor == other)
406 continue;
407
408 QList<QPoint> *ptr = NULL;
409 if (other->canEat(actor, m_eatingorder))
410 ptr = &pos_afraid;
411 else if (actor->canEat(other, m_eatingorder))
412 ptr = &pos_hunt;
413 if (ptr == NULL)
414 continue;
415
416 QPoint otherpos = CoordToMapPosition(other->pos().toPoint());
417 QPoint distance = actorpos - otherpos;
418 if (distance.manhattanLength() < mindistance)
419 ptr->append(otherpos);
420 }
385 421
386 /* if neighbour is not a point */ 422 /* check new directions and change direction-weight */
423 i = directions;
424 while(i.hasNext())
425 {
426 i.next();
427 QPoint newpos = actorpos + Actor::movementToPoint(i.key());
428
429 /* check for new positions in afraid list */
430 foreach(QPoint otherpos, pos_afraid)
431 {
432 int olddistance = (actorpos - otherpos).manhattanLength();
433 int newdistance = (newpos - otherpos).manhattanLength();
434 if (newdistance >= olddistance)
435 i.setValue(i.value() += Constants::AI::weight_afraid);
436 }
437
438 /* check for new positions in hunt list */
439 foreach(QPoint otherpos, pos_hunt)
440 {
441 int olddistance = (actorpos - otherpos).manhattanLength();
442
443 int newdistance = (newpos - otherpos).manhattanLength();
444 if (newdistance <= olddistance)
445 i.setValue(i.value() += Constants::AI::weight_hunt);
446 }
447
448 /* check for bonuspoint */
449 GameEntity *item = visualMap[newpos.x()][newpos.y()];
387 BonusPoint *bpoint = qgraphicsitem_cast<BonusPoint *>(item); 450 BonusPoint *bpoint = qgraphicsitem_cast<BonusPoint *>(item);
451 if (bpoint != NULL)
452 i.setValue(i.value() + Constants::AI::weight_bonus_point);
453
454 /* check for normal point */
388 Point *point = qgraphicsitem_cast<Point *>(item); 455 Point *point = qgraphicsitem_cast<Point *>(item);
389 if (bpoint == NULL && point == NULL) 456 if (point != NULL)
390 { 457 i.setValue(i.value() + Constants::AI::weight_point);
458 }
459
460 /* sort directions */
461 QList<unsigned int> weightlist = directions.values();
462 qSort(weightlist.begin(), weightlist.end(), qGreater<unsigned int>());
463
464 /* remove directions with lesser weight */
465 unsigned int max = weightlist.at(0);
466 i = directions;
467 while(i.hasNext())
468 {
469 i.next();
470 if (i.value() < max)
391 i.remove(); 471 i.remove();
392 continue;
393 }
394 } 472 }
395 473
396 QList<Actor::Movement> *ptr = (!directions.empty()) ? &directions : &directions2; 474 QList<Actor::Movement> list = directions.keys();
397 int rand = (int) (ptr->size() * (qrand() / (RAND_MAX + 1.0))); 475
398 m_actorMovements[actor->color()] = ptr->at(rand); 476 /* default is no direction change */
477 if (list.contains(actor->direction()))
478 return;
479
480 /* random direction */
481 int rand = (int) (list.size() * (qrand() / (RAND_MAX + 1.0)));
482 m_actorMovements[actor->color()] = list.at(rand);
399} 483}
400 484
401void Server::keyPressUpdate() 485void Server::keyPressUpdate()
@@ -504,6 +588,11 @@ bool Server::parseCommandline()
504 return false; 588 return false;
505 } 589 }
506 m_maxplayers = maxplayers; 590 m_maxplayers = maxplayers;
591 if (m_maxplayers == 2)
592 {
593 qCritical() << "2 player game is not supported (who wins if a player gets eaten?)";
594 return false;
595 }
507 } 596 }
508 597
509 if (opt.getValue("bots") != NULL) 598 if (opt.getValue("bots") != NULL)
diff --git a/pacman-c++/server.h b/pacman-c++/server.h
index 8d40f27..826c701 100644
--- a/pacman-c++/server.h
+++ b/pacman-c++/server.h
@@ -32,7 +32,7 @@ protected:
32 Transmission::map_t calculateUpdates(); 32 Transmission::map_t calculateUpdates();
33 33
34 /* update client maps */ 34 /* update client maps */
35 void sendUpdate(Transmission::map_t map); 35 void sendUpdate(Transmission::map_t map, bool firstPacket = false);
36 36
37 QPoint addRandomPoint(Transmission::map_t map, Transmission::field_t type = Transmission::bonuspoint); 37 QPoint addRandomPoint(Transmission::map_t map, Transmission::field_t type = Transmission::bonuspoint);
38 void colorizeBlocks(Transmission::map_t map); 38 void colorizeBlocks(Transmission::map_t map);