Dir KihimeNext::decideDir(){ std::array<unsigned int, 4> cnt, scores; cnt.fill(0); scores.fill(0); std::array<double, 4> aves; aves.fill(0); Dir max = Dir::Up; double maxAve = 0.0; bool flg = true; label:; for(int i(0); i < ITERATION; ++i){ Dir dir = allDirs[mt()%4]; while(! Board::movable(grid, dir)) dir = allDirs[mt()%4]; auto moved = Board::moved(grid, dir); unsigned score = toDead(moved, 0); scores[dirToInt(dir)] += score; ++cnt[dirToInt(dir)]; } for(int i(0); i < 4; ++i){ if(cnt[i] == 0){ aves[i] = 0; continue; } aves[i] = scores[i] / (cnt[i] * 1.0); } for(int i(0); i < 4; ++i){ if(aves[i] > maxAve){ max = allDirs[i]; maxAve = aves[i]; } } if(flg && maxAve < DANGER){ flg = false; maxAve = 0; goto label; } return max; }
Dir UCT::decideDir(){ std::array<int, 4> counts; std::array<double, 4> sums; int count(4 * ITERATION_BOOT); sums.fill(0); for(auto dir: allDirs){ for(int i(0); i < ITERATION_BOOT; ++i){ sums[dirToInt(dir)] += staticEval(playout(Board::moved(grid, dir), PLAYOUT_DEPTH)); ++counts[dirToInt(dir)]; } } for(int i(0); i < ITERATION; ++i){ std::array<double, 4> ucb1s; for(auto dir: allDirs){ ucb1s[dirToInt(dir)] = (sums[dirToInt(dir)] / counts[dirToInt(dir)]) + std::sqrt(2 * std::log2(count) / counts[dirToInt(dir)]); } Dir bestDir = Dir::Up; double maxUcb1 = 0.0; for(auto dir: allDirs){ if(maxUcb1 < ucb1s[dirToInt(dir)]){ bestDir = dir; maxUcb1 = ucb1s[dirToInt(dir)]; } } sums[dirToInt(bestDir)] += staticEval(playout(Board::moved(grid, bestDir), PLAYOUT_DEPTH)); } Dir bestDir = Dir::Up; double maxAve = 0.0; for(auto dir: allDirs){ if(maxAve < sums[dirToInt(dir)] / counts[dirToInt(dir)]){ bestDir = dir; maxAve = sums[dirToInt(dir)] / counts[dirToInt(dir)]; } } std::cout << maxAve << std::endl; return bestDir; }
void Enemy::onUpdate() { if(invisibility) invisibility--; Vec2i facing = intToDir(dir); if(level.getAIFlags(position) & 2) { // Vergiftung contamination--; } if(contamination <= 0) burst(); if(!thinkCounter--) { // den nächsten Spieler suchen, der für den Gegner sichtbar ist Player* p_closestPlayer = 0; int closestDist = 0; const std::list<Player*>& players = Player::getInstances(); for(std::list<Player*>::const_iterator i = players.begin(); i != players.end(); ++i) { if(!(*i)->isTeleporting()) { int dist = (position - (*i)->getPosition()).lengthSq(); if(dist < closestDist || !p_closestPlayer) { if(canSee((*i)->getPosition())) { p_closestPlayer = *i; closestDist = dist; } } } } if(p_closestPlayer) { targetPosition = p_closestPlayer->getPosition(); interest += 2225 - closestDist; } thinkCounter = random(2, 5); } if(subType == 0) { int oldDir = dir; if(moveCounter-- <= 0 && fabs(shownDir - dir) < 0.4) { int r = random(0, 8); if(interest >= 10000) r = random(0, 40); if(contamination < 50) { if(random() % 2) r = 0; } interest /= 2; switch(r) { case 0: { int d = random(-22, 22) / 10; if(d) dir += d, anim += 16; } break; case 1: case 2: case 3: if(!tryToMove(facing)) dir += random(-22, 22) / 10; anim += 16; break; default: if(r >= 6 && targetPosition.x != -1) { // zum Ziel laufen Vec2i toTarget = targetPosition - position; if(toTarget.x && toTarget.y) toTarget.value[random(0, 1)] = 0; int d = dirToInt(toTarget); toTarget = intToDir(d); if(tryToMove(toTarget)) { dir = d; anim += 16; interest *= 2; } } break; } if(position == targetPosition || interest < 10) { targetPosition = Vec2i(-1, -1); interest = 0; } while(dir < 0) dir += 4, shownDir += 4.0; dir %= 4; moveCounter = random(4, 7); } if(anim) anim--; double dd = static_cast<double>(dir) - shownDir; if(dd > 2.0) shownDir += 4.0; else if(dd < -2.0) shownDir -= 4.0; shownDir = 0.125 * dir + 0.875 * shownDir; if(!soundCounter) { if(oldDir != dir) { // Kratz-Sound abspielen Engine::inst().playSound("enemy1_turn.ogg", false, 0.1, -100); soundCounter = random(15, 55); } } else soundCounter--; if(burpCounter) { burpCounter--; if(!burpCounter) { int s = random(0, 1); std::string sound; if(s == 0) sound = "enemy1_burp1.ogg"; else if(s == 1) sound = "enemy1_burp2.ogg"; Engine::inst().playSound(sound, false, 0.1); // Rülpspartikel erzeugen ParticleSystem* p_particleSystem = level.getParticleSystem(); ParticleSystem::Particle p; for(int i = 0; i < 10; i++) { p.lifetime = random(50, 75); p.damping = 0.99f; p.gravity = random(-0.005f, -0.02f); p.positionOnTexture = Vec2b(96, 32); p.sizeOnTexture = Vec2b(16, 16); p.position = position * 16 + Vec2i(8 + random(-4, 4), 6); p.velocity = Vec2d(random(-0.5, 0.5), random(-1.0, -0.5)); p.color = Vec4d(random(0.8, 1.0), random(0.8, 1.0), random(0.8, 1.0), 0.25); p.deltaColor = Vec4d(0.0, 0.0, 0.0, -p.color.a / p.lifetime); p.rotation = random(-0.5f, 0.5f); p.deltaRotation = random(-0.05f, 0.05f); p.size = random(0.2f, 1.0f); p.deltaSize = random(0.0f, 0.01f); p_particleSystem->addParticle(p); } } } } else if(subType == 1) { if(random() % 2) anim++; if(moveCounter-- <= 0) { int r = random(0, 1); if(interest > 6000) r = random(0, 50); if(contamination < 50) { if(random() % 2) r = 0; } interest /= 2; switch(r) { case 0: tryToMove(intToDir(random(0, 4))); break; default: if(targetPosition.x != -1) { // zum Ziel laufen Vec2i toTarget = targetPosition - position; if(toTarget.x && toTarget.y) toTarget.value[random(0, 1)] = 0; int d = dirToInt(toTarget); toTarget = intToDir(d); if(tryToMove(toTarget)) interest *= 2; } else { // Wo ist die Spur am heißesten? int bestDir = 0; uint bestTrace = 0; for(int dir = 0; dir < 4; dir++) { uint trace = level.getAITrace(position + intToDir(dir)); if(trace > bestTrace) { bestTrace = trace; bestDir = dir; } } if(bestTrace) { Vec2i bestDirV = intToDir(bestDir); if(!tryToMove(bestDirV)) { // Das ging nicht. Ist da ein anderer Gegner? bool reduceTrace = true; Object* p_obj = level.getFrontObjectAt(position + bestDirV); if(p_obj) { // Wenn da ein anderer Gegner ist, ist es egal. if(p_obj->getType() == "Enemy") reduceTrace = false; } if(reduceTrace) { // Die Spur dort etwas uninteressanter machen! level.setAITrace(position + bestDirV, bestTrace / 2); } } else { if(bestTrace > 850) interest = 160000; else if(bestTrace > 100) interest = 20000; } } } break; } if(position == targetPosition || interest < 10) { targetPosition = Vec2i(-1, -1); interest = 0; } moveCounter = random(4, 7); } if(height == 0.0) { if(!(random() % 25)) { vy = random(40.0, 80.0); height = 0.5; } } else { height += 0.02 * vy; vy -= 0.02 * 400.0; if(height < 0.5) { height = 0.0; vy = 0.0; } } int pr = 700; if(interest >= 10000) pr = 350; if(!(random() % pr)) { // Lachen abspielen Engine::inst().playSound("enemy2_laugh.ogg", false, 0.15, -100); } if(interest >= 40000) { if(!(random() % 200)) { // Knurren abspielen Engine::inst().playSound("enemy2_growl.ogg", false, 0.15, -100); } } if(interest >= 10000) { // Feuer ParticleSystem* p_particleSystem = level.getParticleSystem(); ParticleSystem* p_fireParticleSystem = level.getFireParticleSystem(); ParticleSystem::Particle p; p.lifetime = random(40, 50); p.damping = 0.9f; p.gravity = -0.04f; p.positionOnTexture = Vec2b(32, 0); p.sizeOnTexture = Vec2b(16, 16); const double r = random(0.0, 6.283); const Vec2d vr(sin(r), cos(r)); p.position = position * 16 + Vec2d(7.5, 7.5 - height) + 7.5 * vr; p.velocity = vr; p.color = Vec4d(random(0.5, 1.0), random(0.8, 1.0), random(0.0, 0.25), random(0.2, 0.4)); const double dc = -1.5 / (p.lifetime + random(-25, 25)); p.deltaColor = Vec4d(dc, dc, dc, -p.color.a / p.lifetime); p.rotation = random(0.0f, 10.0f); p.deltaRotation = random(-0.1f, 0.1f); p.size = random(0.5f, 0.9f); p.deltaSize = random(0.0075f, 0.015f); if(random() % 2) p_particleSystem->addParticle(p); else p_fireParticleSystem->addParticle(p); } } if(eatCounter) eatCounter--; }