/// Outcome of evaluating a user's numeric answer against pipeline rules. enum BranchOutcome { /// Answer matched the expected value (within tolerance when applicable). match, /// Answer was on the positive side of the scale (e.g. preference toward +10). preferHigh, /// Answer was on the negative side of the scale. preferLow, /// Numeric answer was close but not exact. close, /// Answer was far from the target. miss, } class BranchDecision { const BranchDecision._(); /// Exact match for discrete choices encoded as integers. static BranchOutcome discreteChoice({ required num userResponse, required num correctAnswer, }) { if (userResponse.round() == correctAnswer.round()) { return BranchOutcome.match; } return userResponse.sign >= 0 ? BranchOutcome.preferHigh : BranchOutcome.preferLow; } /// Compares a population or temperature estimate with tolerance. static BranchOutcome numericEstimate({ required num userResponse, required num correctAnswer, int tolerance = 2, }) { final int delta = (userResponse.round() - correctAnswer.round()).abs(); if (delta == 0) { return BranchOutcome.match; } if (delta <= tolerance) { return BranchOutcome.close; } return BranchOutcome.miss; } /// Yes/no questions encoded as +10 (yes) vs -10 (no) on the slider. static BranchOutcome yesNo({ required num userResponse, required num correctAnswer, }) { final bool userYes = userResponse > 0; final bool correctYes = correctAnswer > 0; if (userYes == correctYes) { return BranchOutcome.match; } return BranchOutcome.miss; } /// Interprets slider position as a preference (geography vs weather track). static BranchOutcome trackPreference(num userResponse) { if (userResponse >= 3) { return BranchOutcome.preferHigh; } if (userResponse <= -3) { return BranchOutcome.preferLow; } return BranchOutcome.close; } }