ObjectTransition RecallDatabase::computeObjectTransitionSingleton(const vector<Game::StateInst> &states, int baseFrameIndex, const string &objectName) { const Game::StateInst &curState = states[baseFrameIndex]; const Game::StateInst &nextState = states[baseFrameIndex + 1]; const Game::ObjectInst *mostRecentInst = nullptr; for (int frame = baseFrameIndex; !mostRecentInst && frame >= 0; frame--) { const auto &instances = states[frame].objects.find(objectName)->second; if (instances.size() > 0) mostRecentInst = &instances[0]; } const vector<Game::ObjectInst> &nextInstances = nextState.objects.find(objectName)->second; ObjectTransition result; result.nextReward = nextState.reward; if (nextInstances.size() == 0) { result.nextAnimation = mostRecentInst ? mostRecentInst->segmentHash : 0; result.nextAlive = 0; result.velocity = vec2s(0, 0); } else //if (nextInstances.size() >= 1) { result.nextAnimation = nextInstances[0].segmentHash; result.nextAlive = 1; if (mostRecentInst == nullptr) result.velocity = vec2s(0, 0); else result.velocity = nextInstances[0].origin - mostRecentInst->origin; } return result; }
Counter(Scene2::Texture &tex, const vec2f &at, const f32 &scale, const u32 &val) : Tex({ Scene2::Texture( tex, rectf(0,164, Stride, 164), vec2s(496,329) ), Scene2::Texture( tex, rectf(Stride,164, Stride, 164), vec2s(496,329) ), Scene2::Texture( tex, rectf(Stride*2,164, Stride, 164), vec2s(496,329) ), Scene2::Texture( tex, rectf(Stride*3,164, Stride, 164), vec2s(496,329) ), Scene2::Texture( tex, rectf(Stride*4,164, Stride, 164), vec2s(496,329) ), Scene2::Texture( tex, rectf(0,0, Stride, 164), vec2s(496,329) ), Scene2::Texture( tex, rectf(Stride,0, Stride, 164), vec2s(496,329) ), Scene2::Texture( tex, rectf(Stride*2,0, Stride, 164), vec2s(496,329) ), Scene2::Texture( tex, rectf(Stride*3,0, Stride, 164), vec2s(496,329) ), Scene2::Texture( tex, rectf(Stride*4,0, Stride, 164), vec2s(496,329) ) }), Value(val) { for( int i = 3; i--; ) { Spr[i].Size = vec2f(99, 164)*scale; Spr[i].Pos = at + vec2f(Spr[i].Size.x,0)*(f32)i; Spr[i].Tex = &Tex[0]; Spr[i].Rotation = 0; } }
ObjectTransition ObjectSampleDataset::predictTransitionSingleton(AppState &state, const ReplayDatabase &replays, int testReplayIndex, const vector<Game::StateInst> &states, int baseFrameIndex, int action, const HistoryMetricWeights &metric) const { if (objectName == "unnamed") return ObjectTransition(); HistorySlotInfo slotInfo; for (auto &it : state.model.stateSpec.objects) slotInfo.objectNames.push_back(it.name); slotInfo.lines = HistoryMetricWeights().lines; ObjectHistory history = RecallDatabase::computeObjectHistorySingleton(state, states, baseFrameIndex, objectName, slotInfo); vector<ObjectSample*> candidates = getTransitionCandidates(history); if (state.dumpAllTransitions) { candidates = allSamples; } //cout << objectName << " candidates: " << candidates.size() << endl; /*if (candidates.size() == 1) { cout << "Singular candidate -- get more training data" << endl; candidates = allSamples; }*/ ObjectTransition blankTransition; blankTransition.nextAlive = true; blankTransition.nextAnimation = 0; blankTransition.nextReward = 0; blankTransition.velocity = vec2s(0, 0); if (candidates.size() == 0) { cout << "No candidates found for " << objectName << endl; return blankTransition; } vector<ObjectSample*> bestSamples; double bestSamplesDist = std::numeric_limits<double>::max(); ofstream dumpFile; if (state.dumpAllTransitions) { dumpFile.open(learningParams().ROMDatasetDir + "dump" + objectName + ".csv", ios::out); dumpFile << "selected action: " << action << endl; for (int history = 0; history <= 10; history++) dumpFile << "action" << history << ": " << states[max(0, (int)states.size() - 1 - history)].action << endl; dumpFile << "frame,action,padBPos,ballPos,trans-vy,barrier,velDist,animDist,actionDist,positionDist,contactPadADist,offsetPadADist,contactPadBDist,offsetPadBDist,lineConstraints,dist" << endl; } for (ObjectSample *sample : candidates) { /*if (sample->frame.toString() == "r1-f185") { int a = 5; }*/ const vector<Game::StateInst> &candidateStates = replays.replays[sample->frame.replayIndex]->states; const double animationDist = AtariUtil::compareAnimationDescriptorDistSingleton(states, baseFrameIndex, candidateStates, sample->frame.frameIndex, objectName, learningParams().historyFrames); double actionDist = AtariUtil::compareActionDescriptorDist(states, baseFrameIndex, candidateStates, sample->frame.frameIndex, learningParams().historyFrames); if (sample->nextAction != action) actionDist++; const double positionDist = AtariUtil::comparePositionDescriptorDistSingleton(states, baseFrameIndex, candidateStates, sample->frame.frameIndex, objectName, learningParams().historyFrames); const double velocityDist = AtariUtil::compareVelocityDescriptorDistSingleton(states, baseFrameIndex, candidateStates, sample->frame.frameIndex, objectName, learningParams().historyFrames); const double contactPadADist = AtariUtil::compareContactDescriptorDistSingleton(state.segmentDatabase, states, baseFrameIndex, candidateStates, sample->frame.frameIndex, objectName, "padA"); const double offsetPadADist = AtariUtil::compareOffsetDescriptorDistSingleton(state.segmentDatabase, states, baseFrameIndex, candidateStates, sample->frame.frameIndex, objectName, "padA"); const double contactPadBDist = AtariUtil::compareContactDescriptorDistSingleton(state.segmentDatabase, states, baseFrameIndex, candidateStates, sample->frame.frameIndex, objectName, "padB"); const double offsetPadBDist = AtariUtil::compareOffsetDescriptorDistSingleton(state.segmentDatabase, states, baseFrameIndex, candidateStates, sample->frame.frameIndex, objectName, "padB"); const double lineConstraints = AtariUtil::compareLineConstraintsSingleton(states, baseFrameIndex, candidateStates, sample->frame.frameIndex, objectName, metric.lines); const double dist = velocityDist * metric.velocity + animationDist * metric.animation + actionDist * metric.action + positionDist * metric.position + contactPadADist * 20 + offsetPadADist + contactPadBDist * 20 + offsetPadBDist + lineConstraints; if (state.dumpAllTransitions) { dumpFile << sample->frame.toString() << ","; const Game::StateInst &stateInst = candidateStates[sample->frame.frameIndex]; dumpFile << stateInst.action << ","; if (stateInst.objects.find("padB")->second.size() == 0) dumpFile << "dead,"; else dumpFile << stateInst.objects.find("padB")->second[0].origin.toString("x") << ","; if (stateInst.objects.find("ball")->second.size() == 0) dumpFile << "dead,"; else dumpFile << stateInst.objects.find("ball")->second[0].origin.toString("x") << ","; dumpFile << sample->transition.velocity.y << ",x,"; dumpFile << velocityDist << ","; dumpFile << animationDist << ","; dumpFile << actionDist << ","; dumpFile << positionDist << ","; dumpFile << contactPadADist << ","; dumpFile << offsetPadADist << ","; dumpFile << contactPadBDist << ","; dumpFile << offsetPadBDist << ","; dumpFile << lineConstraints << ","; dumpFile << dist << endl; } if (sample->frame.replayIndex == testReplayIndex) continue; if (dist < bestSamplesDist) bestSamples.clear(); if (dist <= bestSamplesDist) { bestSamples.push_back(sample); bestSamplesDist = dist; } } if (bestSamples.size() == 0) { cout << "No non-training samples found for " << objectName << endl; return blankTransition; } if (state.dumpAllTransitions) { dumpFile << "Best samples:" << endl; for (int i = 0; i < bestSamples.size(); i++) { dumpFile << i << "," << bestSamples[i]->frame.toString() << "," << bestSamples[i]->toString() << endl; } } if (Constants::transitionDebugging) { cout << "Best samples: " << bestSamples.size() << endl; for (int sampleIndex = 0; sampleIndex < min(2, (int)bestSamples.size()); sampleIndex++) cout << bestSamples[sampleIndex]->toString() << endl; } return bestSamples[0]->transition; }