void TrailMod::act() { // module follows ship, constantly spawns trail atoms that block/hurt // trails disappear after a while // can be toggled on/off to save power //gm->add(/* new trail of the current type at this pos */)->initall(gm,x,y); Trail* t = new Trail(host); gm->add(t); t->initall(gm,host->x,host->y,team); t->lifedelay(200); }
void mouseDrag (const MouseEvent& e) override { Trail* t = getTrail (e.source); if (t == nullptr) { t = new Trail (e.source); t->path.startNewSubPath (e.getPosition().toFloat()); trails.add (t); } t->pushPoint (e.getPosition().toFloat(), e.mods); repaint(); }
void mouseDrag (const MouseEvent& e) override { Trail* t = getTrail (e.source); if (t == nullptr) { t = new Trail (e.source); t->path.startNewSubPath (e.position); trails.add (t); } t->pushPoint (e.position, e.mods, e.pressure); repaint(); }
void DrawTrail(const Trail& tr, const Graph& g) { if (tr.empty()) { return; } int prev = tr[0]; for (unsigned int i = 1; i < tr.size(); i++) { const GraphEdge& edge = g.GetEdge(tr[i], prev); prev = tr[i]; DrawEdge(edge, g); } }
CString OptionRow::GetRowTitle() const { CString sLineName = m_RowDef.name; CString sTitle = THEME_TITLES ? OPTION_TITLE(sLineName) : sLineName; // HACK: tack the BPM onto the name of the speed line if( sLineName.CompareNoCase("speed")==0 ) { bool bShowBpmInSpeedTitle = SHOW_BPM_IN_SPEED_TITLE; if( GAMESTATE->m_pCurCourse ) { Trail* pTrail = GAMESTATE->m_pCurTrail[GAMESTATE->m_MasterPlayerNumber]; ASSERT( pTrail != NULL ); const int iNumCourseEntries = pTrail->m_vEntries.size(); if( iNumCourseEntries > MAX_COURSE_ENTRIES_BEFORE_VARIOUS ) bShowBpmInSpeedTitle = false; } if( bShowBpmInSpeedTitle ) { DisplayBpms bpms; if( GAMESTATE->m_pCurSong ) { Song* pSong = GAMESTATE->m_pCurSong; pSong->GetDisplayBpms( bpms ); } else if( GAMESTATE->m_pCurCourse ) { Course *pCourse = GAMESTATE->m_pCurCourse; StepsType st = GAMESTATE->GetCurrentStyle()->m_StepsType; Trail* pTrail = pCourse->GetTrail( st ); ASSERT( pTrail ); pTrail->GetDisplayBpms( bpms ); } if( bpms.IsSecret() ) sTitle += ssprintf( " (??" "?)" ); /* split so gcc doesn't think this is a trigraph */ else if( bpms.BpmIsConstant() ) sTitle += ssprintf( " (%.0f)", bpms.GetMin() ); else sTitle += ssprintf( " (%.0f-%.0f)", bpms.GetMin(), bpms.GetMax() ); } } return sTitle; }
//-------------------------------------------------------------- void testApp::updateApp(){ ofPoint * pos; Trail *trail; bool bInsideLetter; vector<ofPoint> growings; for(int i=0; i<trails.size(); i++){ trail = &trails[i]; pos = &trail->position; // If trail isn't in a letter yet if(trail->letterId == -1) { trail->update(screenBounds); if(!ofInsidePoly( trail->position, screenBounds.getVertices() )){ trails.erase(trails.begin()+i); i--; continue; } // look if it has found a letter now for(int j=0; j<letters.size(); j++){ if( ofInsidePoly( *pos, letters[j].getVertices() ) ) { trail->letterId = j; } } } else { trail->update(letters[trail->letterId]); if (trails[i].bActive) { growings.push_back(trails[i].position); } } } triangle.clear(); if(growings.size()>=3) triangle.triangulate( growings, growings.size() ); }
// Fills the complement of the radius of the trail with minus infties. // The return value true means success. Failure means that during the fill, // we intersected the outside of the quasidiagonal area. // In this case, the operation is not finished. bool borderDetailedAlignMatrix( AlignMatrix& alignMatrix, const Trail& trail, int radius ) { int huBookSize = alignMatrix.size(); int enBookSize = alignMatrix.otherSize(); int huPos, enPos; for ( huPos=0; huPos<huBookSize; ++huPos ) { int rowStart = alignMatrix.rowStart(huPos); int rowEnd = alignMatrix.rowEnd(huPos); for ( enPos=rowStart; enPos<rowEnd; ++enPos ) { alignMatrix.cell(huPos,enPos) = outsideOfRadiusValue; } } // We seriously use the fact that many-to-zero segments are subdivided into one-to-zero segments. // Inside setBox, an exception is thrown if we try to write outside the quasidiagonal. // If we catch such an exception, it means that the quasidiagonal is not thick enough. // In this case, we abandon the whole align, just to be sure. try { for ( int i=0; i<trail.size(); ++i ) { setBox( alignMatrix, trail[i].first, trail[i].second, radius, insideOfRadiusValue ); } } catch ( const char* errorType ) { massert( std::string(errorType) == "out of quasidiagonal" ) return false; } bool verify = true; if (verify) { int numberOfEvaluatedItems(0); for ( huPos=0; huPos<huBookSize; ++huPos ) { int rowStart = alignMatrix.rowStart(huPos); int rowEnd = alignMatrix.rowEnd(huPos); for ( enPos=rowStart; enPos<rowEnd; ++enPos ) { if (alignMatrix[huPos][enPos]==insideOfRadiusValue) { ++numberOfEvaluatedItems; } } } std::cerr << numberOfEvaluatedItems << " items inside the border." << std::endl; } return true; }
void BPMDisplay::SetBpmFromCourse( const Course* pCourse ) { ASSERT( pCourse != NULL ); ASSERT( GAMESTATE->GetCurrentStyle(PLAYER_INVALID) != NULL ); StepsType st = GAMESTATE->GetCurrentStyle(PLAYER_INVALID)->m_StepsType; Trail *pTrail = pCourse->GetTrail( st ); // GetTranslitFullTitle because "Crashinfo.txt is garbled because of the ANSI output as usual." -f ASSERT_M( pTrail != NULL, ssprintf("Course '%s' has no trail for StepsType '%s'", pCourse->GetTranslitFullTitle().c_str(), StringConversion::ToString(st).c_str() ) ); m_fCycleTime = (float)COURSE_CYCLE_SPEED; if( (int)pTrail->m_vEntries.size() > CommonMetrics::MAX_COURSE_ENTRIES_BEFORE_VARIOUS ) { SetVarious(); return; } DisplayBpms bpms; pTrail->GetDisplayBpms( bpms ); SetBPMRange( bpms ); }
int countIntersectionOfTrails( const Trail& sx, const Trail& sy ) { int inter(0); Trail::const_iterator sxt = sx.begin(); Trail::const_iterator syt = sy.begin(); Trail::const_iterator sxe = sx.end(); Trail::const_iterator sye = sy.end(); for ( ; sxt!=sxe && syt!=sye ; ) { if ( *sxt < *syt ) ++sxt; else if ( *sxt > *syt ) ++syt; else { ++inter; ++sxt; ++syt; } } return inter; }
// A bit of an abuse of the fact that Trail and BisentenceList are typedef'd to the same structure. double scoreTrailOrBisentenceList( const Trail& trailAuto, const Trail& trailHand ) { int score = countIntersectionOfTrails( trailAuto, trailHand ); std::cerr << trailAuto.size()-score << " misaligned out of " << trailHand.size() << " correct items, " << trailAuto.size() << " bets." << std::endl; std::cerr << "Precision: " << 1.0*score/trailAuto.size() << ", Recall: " << 1.0*score/trailHand.size() << std::endl; double ratio = 1.0*(trailAuto.size()-score)/trailAuto.size(); return ratio; }
void trailToBisentenceList( const Trail& bestTrail, BisentenceList& bisentenceList ) { bisentenceList.clear(); int trailSize = bestTrail.size(); for ( int pos=0; pos<trailSize-1; ++pos ) { if ( oneToOne(bestTrail,pos) ) { bisentenceList.push_back(bestTrail [pos]); } } }
bool Course::GetTrailUnsorted( StepsType st, CourseDifficulty cd, Trail &trail ) const { trail.Init(); // XXX: Why are beginner and challenge excluded here? -Wolfman2000 // No idea, probably an obsolete design decision from ITG, removing // exclusion here, but there's some other area that prevents it too. -Kyz /* switch( cd ) { case Difficulty_Beginner: return false; case Difficulty_Challenge: return false; default: break; } */ // Construct a new Trail, add it to the cache, then return it. // Different seed for each course, but the same for the whole round: RandomGen rnd( GAMESTATE->m_iStageSeed + GetHashForString(m_sMainTitle) ); vector<CourseEntry> tmp_entries; if( m_bShuffle ) { /* Always randomize the same way per round. Otherwise, the displayed course * will change every time it's viewed, and the displayed order will have no * bearing on what you'll actually play. */ tmp_entries = m_vEntries; random_shuffle( tmp_entries.begin(), tmp_entries.end(), rnd ); } const vector<CourseEntry> &entries = m_bShuffle ? tmp_entries:m_vEntries; // This can take some time, so don't fill it out unless we need it. vector<Song*> vSongsByMostPlayed; vector<Song*> AllSongsShuffled; trail.m_StepsType = st; trail.m_CourseType = GetCourseType(); trail.m_CourseDifficulty = cd; trail.m_vEntries.reserve(entries.size()); // Set to true if CourseDifficulty is able to change something. bool bCourseDifficultyIsSignificant = (cd == Difficulty_Medium); // Resolve each entry to a Song and Steps. if( trail.m_CourseType == COURSE_TYPE_ENDLESS ) { GetTrailUnsortedEndless(entries, trail, st, cd, rnd, bCourseDifficultyIsSignificant); } else { vector<SongAndSteps> vSongAndSteps; for (auto e = entries.begin(); e != entries.end(); ++e) { SongAndSteps resolved; // fill this in SongCriteria soc = e->songCriteria; Song *pSong = e->songID.ToSong(); if( pSong ) { soc.m_bUseSongAllowedList = true; soc.m_vpSongAllowedList.push_back( pSong ); } soc.m_Tutorial = SongCriteria::Tutorial_No; soc.m_Locked = SongCriteria::Locked_Unlocked; if( !soc.m_bUseSongAllowedList ) soc.m_iMaxStagesForSong = 1; StepsCriteria stc = e->stepsCriteria; stc.m_st = st; stc.m_Locked = StepsCriteria::Locked_Unlocked; const bool bSameSongCriteria = e != entries.begin() && ( e - 1 )->songCriteria == soc; const bool bSameStepsCriteria = e != entries.begin() && ( e - 1 )->stepsCriteria == stc; if( pSong ) { StepsUtil::GetAllMatching( pSong, stc, vSongAndSteps ); } else if( vSongAndSteps.empty() || !( bSameSongCriteria && bSameStepsCriteria ) ) { vSongAndSteps.clear(); StepsUtil::GetAllMatching( soc, stc, vSongAndSteps ); } // It looks bad to have the same song 2x in a row in a randomly generated course. // Don't allow the same song to be played 2x in a row, unless there's only // one song in vpPossibleSongs. if( trail.m_vEntries.size() > 0 && vSongAndSteps.size() > 1 ) { const TrailEntry &teLast = trail.m_vEntries.back(); RemoveIf( vSongAndSteps, SongIsEqual( teLast.pSong ) ); } // if there are no songs to choose from, abort this CourseEntry if( vSongAndSteps.empty() ) continue; vector<Song*> vpSongs; typedef vector<Steps*> StepsVector; std::map<Song*, StepsVector> mapSongToSteps; for (auto &sas: vSongAndSteps) { StepsVector &v = mapSongToSteps[ sas.pSong ]; v.push_back( sas.pSteps ); if( v.size() == 1 ) vpSongs.push_back( sas.pSong ); } CourseSortSongs( e->songSort, vpSongs, rnd ); ASSERT( e->iChooseIndex >= 0 ); if( e->iChooseIndex < int( vSongAndSteps.size() ) ) { resolved.pSong = vpSongs[ e->iChooseIndex ]; const vector<Steps*> &mappedSongs = mapSongToSteps[ resolved.pSong ]; resolved.pSteps = mappedSongs[ RandomInt( mappedSongs.size() ) ]; } else { continue; } /* If we're not COURSE_DIFFICULTY_REGULAR, then we should be choosing steps that are * either easier or harder than the base difficulty. If no such steps exist, then * just use the one we already have. */ Difficulty dc = resolved.pSteps->GetDifficulty(); int iLowMeter = e->stepsCriteria.m_iLowMeter; int iHighMeter = e->stepsCriteria.m_iHighMeter; if( cd != Difficulty_Medium && !e->bNoDifficult ) { Difficulty new_dc = ( Difficulty )( dc + cd - Difficulty_Medium ); new_dc = Rage::clamp( new_dc, ( Difficulty )0, ( Difficulty )( Difficulty_Edit - 1 ) ); /* // re-edit this code to work using the metric. Difficulty new_dc; if( INCLUDE_BEGINNER_STEPS ) { // don't factor in the course difficulty if we're including // beginner steps -aj new_dc = Rage::clamp( dc, Difficulty_Beginner, (Difficulty)(Difficulty_Edit-1) ); } else { new_dc = (Difficulty)(dc + cd - Difficulty_Medium); new_dc = Rage::clamp( new_dc, (Difficulty)0, (Difficulty)(Difficulty_Edit-1) ); } */ bool bChangedDifficulty = false; if( new_dc != dc ) { Steps* pNewSteps = SongUtil::GetStepsByDifficulty( resolved.pSong, st, new_dc ); if( pNewSteps ) { dc = new_dc; resolved.pSteps = pNewSteps; bChangedDifficulty = true; bCourseDifficultyIsSignificant = true; } } /* Hack: We used to adjust low_meter/high_meter above while searching for * songs. However, that results in a different song being chosen for * difficult courses, which is bad when LockCourseDifficulties is disabled; * each player can end up with a different song. Instead, choose based * on the original range, bump the steps based on course difficulty, and * then retroactively tweak the low_meter/high_meter so course displays * line up. */ if( e->stepsCriteria.m_difficulty == Difficulty_Invalid && bChangedDifficulty ) { /* Minimum and maximum to add to make the meter range contain the actual * meter: */ int iMinDist = resolved.pSteps->GetMeter() - iHighMeter; int iMaxDist = resolved.pSteps->GetMeter() - iLowMeter; /* Clamp the possible adjustments to try to avoid going under 1 or over * MAX_BOTTOM_RANGE. */ iMinDist = std::min( std::max( iMinDist, -iLowMeter + 1 ), iMaxDist ); iMaxDist = std::max( std::min( iMaxDist, MAX_BOTTOM_RANGE - iHighMeter ), iMinDist ); int iAdd; if( iMaxDist == iMinDist ) iAdd = iMaxDist; else iAdd = rnd( iMaxDist - iMinDist ) + iMinDist; iLowMeter += iAdd; iHighMeter += iAdd; } } TrailEntry te; te.pSong = resolved.pSong; te.pSteps = resolved.pSteps; te.Modifiers = e->sModifiers; te.Attacks = e->attacks; te.bSecret = e->bSecret; te.iLowMeter = iLowMeter; te.iHighMeter = iHighMeter; /* If we chose based on meter (not difficulty), then store Difficulty_Invalid, so * other classes can tell that we used meter. */ if( e->stepsCriteria.m_difficulty == Difficulty_Invalid ) { te.dc = Difficulty_Invalid; } else { /* Otherwise, store the actual difficulty we got (post-course-difficulty). * This may or may not be the same as e.difficulty. */ te.dc = dc; } trail.m_vEntries.push_back( te ); // LOG->Trace( "Chose: %s, %d", te.pSong->GetSongDir().c_str(), te.pSteps->GetMeter() ); if( IsAnEdit() && MAX_SONGS_IN_EDIT_COURSE > 0 && int( trail.m_vEntries.size() ) >= MAX_SONGS_IN_EDIT_COURSE ) { break; } } } /* Hack: If any entry was non-FIXED, or m_bShuffle is set, then radar values * for this trail will be meaningless as they'll change every time. Pre-cache * empty data. XXX: How can we do this cleanly, without propagating lots of * otherwise unnecessary data (course entry types, m_bShuffle) to Trail, or * storing a Course pointer in Trail (yuck)? */ if( !AllSongsAreFixed() || m_bShuffle ) { trail.m_bRadarValuesCached = true; trail.m_CachedRadarValues = RadarValues(); } /* If we have a manually-entered meter for this difficulty, use it. */ if( m_iCustomMeter[cd] != -1 ) trail.m_iSpecifiedMeter = m_iCustomMeter[cd]; /* If the course difficulty never actually changed anything, then this difficulty * is equivalent to Difficulty_Medium; it doesn't exist. */ return bCourseDifficultyIsSignificant && trail.m_vEntries.size() > 0; }
void Choreo3DApp::draw() { //gl::clear( ColorA::gray( background ) ); gl::clear(ColorAf(testBK)); //THIS MAY NEED TO BE CLEANED UP vector<std::string> dataVector = {"CCL_JOINT_CCL3_00_skip10.json"}; if( CURRENT_DATA_SET != LOADED_DATA_SET){ // paused = true; // jointList = {}; jointList = ccl::loadMotionCaptureFromJson(getAssetPath(dataVector[CURRENT_DATA_SET])); FRAME_COUNT = 0; TOTAL_FRAMES = jointList[0].jointPositions.size(); //SHOULD PROBABLY PUT A TRY/CATCH HERE std::cout << "total frames: " << TOTAL_FRAMES << ", total joints:"<< jointList.size() << std::endl; gl::VboMeshRef body = gl::VboMesh::create( geom::Sphere().subdivisions( 16 ).radius(4) ); //CREATE A CONTAINER TO STORE THE INITIAL POSITIONS FOR INITIALISING THE JOINTS std::vector<glm::vec3> positions; // CREATE THE SPHERES AT THE INITIAL JOINT LOCATIONS for ( int i = 0; i < jointList.size(); ++i ) { glm::vec3 jointAt = jointList[i].jointPositions[i]; float instanceX = jointAt.x; float instanceY = jointAt.y; float instanceZ = jointAt.z; // float instanceZ = 0; positions.push_back( vec3( instanceX, instanceY, instanceZ)); } //std::cout << "positions: " << positions[0] << std::endl; // create the VBO which will contain per-instance (rather than per-vertex) data mInstanceDataVbo = gl::Vbo::create( GL_ARRAY_BUFFER, positions.size() * sizeof(vec3), positions.data(), GL_DYNAMIC_DRAW ); // we need a geom::BufferLayout to describe this data as mapping to the CUSTOM_0 semantic, and the 1 (rather than 0) as the last param indicates per-instance (rather than per-vertex) geom::BufferLayout instanceDataLayout; instanceDataLayout.append( geom::Attrib::CUSTOM_0, 3, 0, 0, 1 /* per instance */ ); //NOW ADD IT TO THE VBO MESH THAT WE INITIAL CREATED FOR THE BODY / SKELETON body->appendVbo( instanceDataLayout, mInstanceDataVbo ); //FINALLY, BUILD THE BATCH, AND MAP THE CUSTOM_0 ATTRIBUTE TO THE "vInstancePosition" GLSL VERTEX ATTRIBUTE mSphereBatch = gl::Batch::create( body, mGlsl, { { geom::Attrib::CUSTOM_0, "vInstancePosition" } } ); LOADED_DATA_SET = CURRENT_DATA_SET; } gl::setMatrices( mCamera ); if (showGrid)renderScene(); Color( dancerColor[0], dancerColor[1], dancerColor[2] ); //gl::ScopedModelMatrix modelScope; if(markersActive)mSphereBatch->drawInstanced( jointList.size() ); if(skeletonActive)skeleton.renderSkeleton(); if(ribbonsActive)drawRibbons(); if(trailsActive)handTrail.render(dancerColor); }
void Choreo3DApp::update() { setFrameRate(frameRate); //DISABLE CAMERA INTERACTION IF MOUSE IS OVER UI REGION if (getMousePos().x > 3 * getWindowWidth()/4. && camActive) { camActive = false; mCamUi.disconnect(); mCamUi.disable(); cout << "disabling camera UI" << endl; } else { if (!camActive) { mCamUi.connect(getWindow()); mCamUi.enable(); } camActive = true; cout << "enabling camera UI" << endl; } mGlsl->uniform("uColor", markerColour ); if (!paused) { //UPDATE POSITIONS //MAP INSTANCE DATA TO VBO //WRITE NEW POSITIONS //UNMAP glm::vec3 *newPositions = (glm::vec3*)mInstanceDataVbo->mapReplace(); for( int i = 0; i < jointList.size(); ++i ) { float instanceX = jointList[i].jointPositions[FRAME_COUNT].x; float instanceY = jointList[i].jointPositions[FRAME_COUNT].y; float instanceZ = jointList[i].jointPositions[FRAME_COUNT].z; vec3 newPos(vec3(instanceX,instanceY, instanceZ)); //CREATE A NEW VEC3 FOR UPDATING THE VBO framePositions[i] = newPos; } //REPLACE VEC3s IN VBO BY INCREMENTING THE POINTER for (int i = 0; i < framePositions.size(); i++){ *newPositions++ = framePositions[i]; } handTrail.update(framePositions[26], dancerColor); // std::cout << framePositions[17] << std::endl; skeleton.update(framePositions); mInstanceDataVbo->unmap(); // std::cout << "position: " << positions[0] << std::endl; if (ribbonsActive)updateRibbons(); //MANUALLY INCREMENT THE FRAME, IF THE FRAME_COUNT EXCEEDS TOTAL FRAMES, RESET THE COUNTER if (FRAME_COUNT < TOTAL_FRAMES) { FRAME_COUNT += 1; } else { FRAME_COUNT = 0; } //std::cout << getAverageFps() << std:: endl; // std::cout << "frame rate: " << getAverageFps() << ", frame count: " << FRAME_COUNT << std::endl; //define changed color // Color temp = Color(dancerColor[0],dancerColor[1],dancerColor[2]); mCurrentFrame++; //MANUALLY ADVANCE THE CURRENT FRAME - WITH RESPECT TO THE DANCERS } updateGui(); }
void trelliToLadder( const TrelliMatrix& trellis, Trail& bestTrail ) { bestTrail.clear(); // The -1 is needed because the trellis matrix is one larger than the similarity matrix. // This points to its downmost rightmost element. const int huBookSize = trellis.size()-1; const int enBookSize = trellis.otherSize()-1; int huPos=huBookSize; int enPos=enBookSize; bool logging = false; if (logging) std::cerr << std::endl; bool over = false; bool hopelesslyBadTrail = false; bestTrail.push_back(std::make_pair(huPos,enPos)); while (true) { unsigned char trelli = trellis[huPos][enPos]; // std::cerr << huPos << "," << enPos << "," << (int)trelli << std::endl; if ((huPos==0) || (enPos==0)) break; switch (trelli) { case Diag : { --huPos; --enPos; break; } case HuSkip : { --huPos; break; } case EnSkip : { --enPos; break; } case HuHuEnSkip : { huPos -= 2; --enPos; break; } case HuEnEnSkip : { --huPos; enPos -= 2; break; } case Dead : { over = true; break; } default: { hopelesslyBadTrail = true; over = true; break; } } if (over) break; bestTrail.push_back(std::make_pair(huPos,enPos)); if (logging) { std::cerr << huPos << " \t" << enPos << std::endl; } } if (hopelesslyBadTrail) { bestTrail.clear(); bestTrail.push_back(std::make_pair(huBookSize,enBookSize)); bestTrail.push_back(std::make_pair(0,0)); std::cerr << "Error: hopelessly bad trail." << std::endl; } std::reverse(bestTrail.begin(), bestTrail.end() ); }
bool Course::GetTrailUnsorted( StepsType st, CourseDifficulty cd, Trail &trail ) const { trail.Init(); // XXX: Why are beginner and challenge excluded here? -Wolfman2000 switch( cd ) { case Difficulty_Beginner: return false; case Difficulty_Challenge: return false; default: break; } // Construct a new Trail, add it to the cache, then return it. // Different seed for each course, but the same for the whole round: RandomGen rnd( GAMESTATE->m_iStageSeed + GetHashForString(m_sMainTitle) ); vector<CourseEntry> tmp_entries; if( m_bShuffle ) { /* Always randomize the same way per round. Otherwise, the displayed course * will change every time it's viewed, and the displayed order will have no * bearing on what you'll actually play. */ tmp_entries = m_vEntries; random_shuffle( tmp_entries.begin(), tmp_entries.end(), rnd ); } const vector<CourseEntry> &entries = m_bShuffle ? tmp_entries:m_vEntries; // This can take some time, so don't fill it out unless we need it. vector<Song*> vSongsByMostPlayed; vector<Song*> AllSongsShuffled; trail.m_StepsType = st; trail.m_CourseType = GetCourseType(); trail.m_CourseDifficulty = cd; // Set to true if CourseDifficulty is able to change something. bool bCourseDifficultyIsSignificant = (cd == Difficulty_Medium); vector<Song*> vpAllPossibleSongs; vector<SongAndSteps> vSongAndSteps; // Resolve each entry to a Song and Steps. FOREACH_CONST( CourseEntry, entries, e ) { SongAndSteps resolved; // fill this in SongCriteria soc = e->songCriteria; Song *pSong = e->songID.ToSong(); if( pSong ) { soc.m_bUseSongAllowedList = true; soc.m_vpSongAllowedList.push_back( pSong ); } soc.m_Tutorial = SongCriteria::Tutorial_No; soc.m_Locked = SongCriteria::Locked_Unlocked; if( !soc.m_bUseSongAllowedList ) soc.m_iMaxStagesForSong = 1; StepsCriteria stc = e->stepsCriteria; stc.m_st = st; stc.m_Locked = StepsCriteria::Locked_Unlocked; const bool bSameSongCriteria = e != entries.begin() && (e-1)->songCriteria == soc; const bool bSameStepsCriteria = e != entries.begin() && (e-1)->stepsCriteria == stc; if( pSong ) { StepsUtil::GetAllMatching( pSong, stc, vSongAndSteps ); } else if( vSongAndSteps.empty() || !(bSameSongCriteria && bSameStepsCriteria) ) { vSongAndSteps.clear(); StepsUtil::GetAllMatching( soc, stc, vSongAndSteps ); } // It looks bad to have the same song 2x in a row in a randomly generated course. // Don't allow the same song to be played 2x in a row, unless there's only // one song in vpPossibleSongs. if( trail.m_vEntries.size() > 0 && vSongAndSteps.size() > 1 ) { const TrailEntry &teLast = trail.m_vEntries.back(); RemoveIf( vSongAndSteps, SongIsEqual(teLast.pSong) ); } // if there are no songs to choose from, abort this CourseEntry if( vSongAndSteps.empty() ) continue; vector<Song*> vpSongs; typedef vector<Steps*> StepsVector; map<Song*,StepsVector> mapSongToSteps; FOREACH_CONST( SongAndSteps, vSongAndSteps, sas ) { StepsVector &v = mapSongToSteps[sas->pSong]; v.push_back( sas->pSteps ); if( v.size() == 1 ) vpSongs.push_back( sas->pSong ); }
/** Example function that generates a trail from a pair of inputs. * In this example, we use the messages found by I. Dinur, O. Dunkelman * and A. Shamir to produce a collision on Keccak[r=1088, c=512] reduced * to 4 rounds. */ void generateTrailFromDinurDunkelmanShamirCollision() { const UINT8 M1[] = "\x32\x1c\xf3\xc4\x6d\xae\x59\x4c\xf4\xf0\x19\x5d\x4b\xe4\xc4\x25" "\x32\x30\x85\xd8\xf2\x12\x5e\x8d\xe2\x6e\x6e\xbb\x1e\x3b\xc3\x27" "\x58\x10\x09\x6c\xd5\x02\x90\xeb\x6f\xa0\xa4\x3b\xf1\xc7\x0c\x4a" "\x51\x5e\xb5\xcc\x83\xd9\x0d\x8d\x43\x08\x0a\x2b\xb0\xd3\x21\x9b" "\x75\x90\x67\x53\xd2\xde\x6d\x52\x44\x48\x29\x48\x2c\xed\xf4\x6f" "\x15\x2c\xce\x1a\xc7\x1d\x1c\x47\x68\x85\x09\xd4\x39\xf6\xeb\xf1" "\x57\xb2\xf7\xea\x87\xae\xfd\x09\xe6\x78\x88\x68\x30\xeb\x75\x48" "\x80\x2d\xc3\xc9\xcb\x6f\x9e\x3c\xfa\xbc\x2a\x3c\x7b\x80\xa4\xe6" "\xb8\x81\xb2\x2a\xb3\x32\x23"; const unsigned int M1len = 135; UINT8 M2[] = "\xf7\x0e\xd3\xa4\x69\x8f\xbb\x80\xdf\x48\xc0\x90\xb9\x13\x72\xeb" "\x24\x04\x65\xa6\x3e\xf6\x65\x3a\x81\x88\x26\x8c\x1f\xb8\x51\xb6" "\x3c\xfa\xda\xaa\xc3\xa5\x2c\xee\xc2\xea\x78\xdb\x79\xe7\xea\xc8" "\x35\x9c\x2f\x44\x87\xe2\x21\x32\x5a\x7a\x01\xb3\x12\x07\x79\x90" "\xdc\x8b\x1c\x1b\xa8\x10\x8b\xe0\xca\x25\x9d\x9a\xac\xaa\xe7\x1b" "\x9c\x3e\x2f\x4e\xad\x7d\x71\x73\x5a\x01\x66\x55\xb9\xcf\x98\xa1" "\xc2\xa8\x1c\x5a\x8a\x34\xe3\xa0\xb1\x0b\x6c\xae\xe4\xf9\x80\x39" "\x91\x8b\xfa\xa4\x89\xa9\x81\x6e\xaa\xbc\xa9\x89\xf1\xf1\x2b\xe1" "\x95\x95\xef\x30\x45\x8b\x2e"; const unsigned int M2len = 135; { UINT8 output[32]; ReducedRoundKeccak keccak(1088, 512, 4); keccak.absorb(M1, M1len*8); keccak.squeeze(output, 256); for(unsigned int i=0; i<32; i++) cout << hex << (int)output[i] << " "; cout << endl; } { UINT8 output[32]; ReducedRoundKeccak keccak(1088, 512, 4); keccak.absorb(M2, M2len*8); keccak.squeeze(output, 256); for(unsigned int i=0; i<32; i++) cout << hex << (int)output[i] << " "; cout << endl; } { KeccakFDCEquations keccakF(1600, 4); KeccakFPropagation DC(keccakF, KeccakFPropagation::DC); vector<LaneValue> m1lanes, m2lanes; { UINT8 temp[200]; memset(temp, 0, 200); memcpy(temp, M1, M1len); temp[M1len] = 0x81; keccakF.fromBytesToLanes(temp, m1lanes); } { UINT8 temp[200]; memset(temp, 0, 200); memcpy(temp, M2, M2len); temp[M2len] = 0x81; keccakF.fromBytesToLanes(temp, m2lanes); } vector<SliceValue> m1slices, m2slices; fromLanesToSlices(m1lanes, m1slices, 64); fromLanesToSlices(m2lanes, m2slices, 64); Trail trail; keccakF.buildDCTrailFromPair(m1slices, m2slices, trail); { ofstream fout("DinurEtAl.trail"); trail.save(fout); } Trail::produceHumanReadableFile(DC, "DinurEtAl.trail"); } }