/* * Copyright (c) 2010 Daniel Hartmeier * All rights reserved. * */ #include #include #include #include #include #include "board.h" inline int max(int a, int b) { return a > b ? a : b; } Board::Board(const char *s) { int id = 0; while (*s) { if (s[0] == 'P' && s[1] == ' ') { double x, y; int owner, ships, growth; if (sscanf(s + 2, "%lf %lf %d %d %d", &x, &y, &owner, &ships, &growth) != 5) { debug("Board::Board: sscanf: P\n"); } else planets.insert(planets.end(), Planet(id++, owner, ships, growth, x, y)); } else if (s[0] == 'F' && s[1] == ' ') { int owner, ships, src, dst, len, remain; if (sscanf(s + 2, "%d %d %d %d %d %d", &owner, &ships, &src, &dst, &len, &remain) != 6) { debug("Board::Board: sscanf: F\n"); } else fleets.insert(fleets.end(), Fleet(owner, ships, src, dst, len, remain)); } else { debug("Board::Board: invalid line\n"); } while (*s && *s != '\n') ++s; if (*s == '\n') ++s; } } int Board::distance(int src, int dst) const { if (src < 0 || src >= (int)planets.size() || dst < 0 || dst >= (int)planets.size()) return 0; const Planet &psrc = planets[src], &pdst = planets[dst]; double dx = psrc.getX() - pdst.getX(); double dy = psrc.getY() - pdst.getY(); return (int)ceil(sqrt(dx * dx + dy * dy)); } bool Board::issueOrder(int player, int src, int dst, int ships) { if (player < 1) { debug("Board::issueOrder: invalid player %d\n", player); return true; } if (src < 0 || src >= (int)planets.size()) { debug("Board::issueOrder: invalid src %d\n", src); return true; } if (dst < 0 || dst >= (int)planets.size() || src == dst) { debug("Board::issueOrder: invalid dst %d\n", dst); return true; } Planet &p = planets[src]; if (player != p.getOwner()) { debug("Board::issueOrder: player %d not owner of planet %d " "(owner is %d)\n", player, src, p.getOwner()); return true; } if (ships < 1 || ships > p.getShips()) { debug("Board::issueOrder: invalid number of ships %d\n", ships); return true; } int len = distance(src, dst); if (len < 1) { debug("Board::issueOrder: len %d < 1\n", len); return true; } p.setShips(p.getShips() - ships); for (vector::iterator i = fleets.begin(); i != fleets.end(); ++i) { if (i->getOwner() == player && i->getSrc() == src && i->getDst() == dst && i->getLen() == len && i->getRemain() == len) { i->setShips(i->getShips() + ships); return false; } } fleets.insert(fleets.end(), Fleet(player, ships, src, dst, len, len)); return false; } void Board::nextTurn() { // growth happens before battle for (vector::iterator p = planets.begin(); p != planets.end(); ++p) if (p->getOwner()) p->setShips(p->getShips() + p->getGrowth()); // advance fleets, for fleets arriving at their destination: // merge fleets of each player map > m; vector::iterator f = fleets.begin(); while (f != fleets.end()) { if (f->decrementRemain() > 0) { ++f; continue; } if (f->getOwner() == 1) m[f->getDst()].first += f->getShips(); else m[f->getDst()].second += f->getShips(); f = fleets.erase(f); } // process arriving (merged) fleets for (map >::iterator i = m.begin(); i != m.end(); ++i) { Planet &p = planets[i->first]; vector n(3); n[0] = 0; n[1] = i->second.first; n[2] = i->second.second; n[p.getOwner()] += p.getShips(); if (n[1] > n[2] && n[1] > n[0]) { p.setOwner(1); p.setShips(n[1] - max(n[2], n[0])); } else if (n[2] > n[1] && n[2] > n[0]) { p.setOwner(2); p.setShips(n[2] - max(n[1], n[0])); } else { sort(n.begin(), n.end()); p.setShips(n[2] - n[1]); } } } /* WIN=p1 wins, LOSS=p2 wins */ RESULT Board::rate() const { unsigned p[2] = { 0, 0 }, s[2] = { 0, 0 }; for (vector::const_iterator i = planets.begin(); i != planets.end(); ++i) { if (i->getOwner()) { p[i->getOwner() - 1]++; s[i->getOwner() - 1] += i->getShips(); } } for (vector::const_iterator i = fleets.begin(); i != fleets.end(); ++i) { s[i->getOwner() - 1] += i->getShips(); } /* XXX // all planets are owned by one player -> win if (p[0] == planets.size()) return WIN; if (p[1] == planets.size()) return LOSS; */ // a player doesn't have any ships anymore -> loss if (!s[0] && !s[1]) return DRAW; if (!s[1]) return WIN; if (!s[0]) return LOSS; return UNDECIDED; }