/// <summary> /// Performs the 3 functions which we regularly do in this order /// 1. Combine the values into a single integer /// 2. Add the probability to that stored against the integer in stateProb array /// 3. Enqueue the integer state (unless already queued) /// </summary> static void combineQueueUpdate(ref double[] stateProb, ref distinctIntQueue Q, double prob, int t_elapsed, int T_R, int t_M, int t_K, compStage compStg) { int S = combineState(t_elapsed, T_R, t_M, t_K, compStg); // ADD the probability. stateProb[S] += prob; Q.Enqueue(S); }
// Gets the decompressed stage - see pdf. static stage getFullStage(compStage compStg, int t_M, int t_K) { switch (compStg) { case compStage.Skedar1: // If we aren't killing we're awaiting. if (t_K == 0) { return(stage.Skedar1Await); } else { return(stage.Skedar1Kill); } case compStage.JustJoannaMoving: return(stage.JustJoannaMoving); case compStage.BothMoving: // If the movement timer has elapsed, we're killing, // Else one of us is still moving (or spawning). if (t_M == 0) { return(stage.Skedar2Kill); } else { return(stage.BothMoving); } case compStage.Skedar3: // Movement timer set to 1 indicates success state, see pdf. if (t_M != 0) { return(stage.Success); } // Otherwise it's the standard kill timer distinction if (t_K != 0) { return(stage.Skedar3Kill); } else { return(stage.Skedar3Await); } default: // Cheer up compiler! return((stage)(-1)); } }
// ============================== /// <summary> /// Combines all the values into a single integer /// </summary> static int combineState(int t_elapsed, int T_R, int t_M, int t_K, compStage compStg) { int res = t_elapsed; res *= (100 + 1); res += T_R; // Note the +1 as ever. res *= (t_open + 2); res += t_M + 1; res *= (t_kill + 1); res += t_K; res *= 4; res += (int)compStg; return(res); }
/// <summary> /// Extracts the state from the single integer into the 5 items. Inverse of the above. /// </summary> static void recoverState(int entireState, out int t_elapsed, out int T_R, out int t_M, out int t_K, out compStage compStg) { compStg = (compStage)(entireState % 4); entireState /= 4; t_K = entireState % (t_kill + 1); entireState /= (t_kill + 1); // Corresponding -1 t_M = entireState % (t_open + 2) - 1; entireState /= (t_open + 2); T_R = entireState % (100 + 1); entireState /= (100 + 1); t_elapsed = entireState; }
/// <summary> /// Gets one or two (normally two) states from one by applying the Right Timer transitions. /// Adds these to the Queue for continuing the breadth first search. /// Where the right timer is no longer relevant (for Skedar3Kill) this just queues the single state. /// </summary> /// <param name="basePr">The base probability for the stage we are considering Right Timer transitions from</param> /// <param name="compStg">The compressed stage</param> static void doRightTimerTransitionsAndQueue(ref double[] stateProb, ref distinctIntQueue Q, double basePr, int t_elapsed, int T_R, int t_M, int t_K, compStage compStg) { // If already 0, we've stopped (Skedar #3 is spawned), so just make the call if (T_R == 0) { combineQueueUpdate(ref stateProb, ref Q, basePr, t_elapsed, T_R, t_M, t_K, compStg); } else { // If the timer is not 1, do the event that we don't finish the timer (just timer changes) // Also adjust base probability for 1/256 of success next if (T_R != 1) { combineQueueUpdate(ref stateProb, ref Q, basePr * q, t_elapsed, T_R - 1, t_M, t_K, compStg); basePr /= 256; } // Now consider the reset event. Set timer back to 100. // Determine full stage to determine flow on T_R = 100; switch (compStg) { // More interesting stages, set the movement time to t_open when Joanna is still at Skedar #1. // But only set it once - there was a bug here where we kept reseting. case compStage.Skedar1: // NTS: Awkward case where we used Parent's full stage was here, but being able to use current compressed is ideal. // Indeed it also would effect the bottom two - it was a bad idea. if (t_M == -1) { t_M = t_open; } break; case compStage.JustJoannaMoving: // If Joanna is already moving, update timer to max of time for Joanna and time for Skedar #2 // Notice here we actually change stage, preventing running this twice. if (t_open > t_M) { t_M = t_open; } compStg = compStage.BothMoving; break; case compStage.Skedar3: // Set to 0 to show we're done with all events, stopping the timer. // This is slightly cleaner, since the right timer would otherwise run while we're killing Skedar #3. // Also observe we must be in Skedar3Await, since timer is running, so set kill timer T_R = 0; t_K = t_kill; break; // In full states BothMoving and Skedar2Kill Skedar #2 is spawned and not killed, so we only reset the timer (above the switch). } // Finally we queue this reset-timer state. combineQueueUpdate(ref stateProb, ref Q, basePr, t_elapsed, T_R, t_M, t_K, compStg); } }