diff --git a/js/common/model/CAVSceneModel.ts b/js/common/model/CAVSceneModel.ts index 118b5e48..980c2759 100644 --- a/js/common/model/CAVSceneModel.ts +++ b/js/common/model/CAVSceneModel.ts @@ -40,7 +40,7 @@ import CAVQueryParameters from '../CAVQueryParameters.js'; // constants const TIME_BETWEEN_RAPID_KICKS = 0.5; // in seconds -export default class CAVSceneModel extends PhetioObject implements TModel { +export default abstract class CAVSceneModel extends PhetioObject implements TModel { public readonly soccerBalls: SoccerBall[]; // The number of active soccer balls (includes soccer balls created but not yet kicked) @@ -96,7 +96,12 @@ export default class CAVSceneModel extends PhetioObject implements TModel { parameters: [ { isValidValue: element => Array.isArray( element ) } ] } ); - public constructor( public readonly maxKicksProperty: TReadOnlyProperty, maxKicksChoices: number[], initialDistribution: ReadonlyArray, options: { tandem: Tandem } ) { + public constructor( + public readonly maxKicksProperty: TReadOnlyProperty, + maxKicksChoices: number[], + initialDistribution: ReadonlyArray, + options: { tandem: Tandem } + ) { super( { phetioState: false, @@ -371,8 +376,7 @@ export default class CAVSceneModel extends PhetioObject implements TModel { */ public reset(): void { - // TODO: This should only be in MedianSceneModel and MeanAndMedianSceneModel, see https://github.com/phetsims/center-and-variability/issues/153 - this.distributionProperty.value = CAVSceneModel.chooseDistribution(); + this.resetScene(); this.clearData(); @@ -563,6 +567,8 @@ export default class CAVSceneModel extends PhetioObject implements TModel { } return nextBallFromPool; } + + public abstract resetScene(): void; } centerAndVariability.register( 'CAVSceneModel', CAVSceneModel ); \ No newline at end of file diff --git a/js/common/model/MeanAndOrMedianSceneModel.ts b/js/common/model/MeanAndOrMedianSceneModel.ts new file mode 100644 index 00000000..a09c6cac --- /dev/null +++ b/js/common/model/MeanAndOrMedianSceneModel.ts @@ -0,0 +1,19 @@ +// Copyright 2023, University of Colorado Boulder + +/** + * + * @author Chris Klusendorf (PhET Interactive Simulations) + * @author Sam Reid (PhET Interactive Simulations) + */ + +import centerAndVariability from '../../centerAndVariability.js'; +import CAVSceneModel from './CAVSceneModel.js'; + +export default class MeanAndOrMedianSceneModel extends CAVSceneModel { + + public resetScene(): void { + this.distributionProperty.value = CAVSceneModel.chooseDistribution(); + } +} + +centerAndVariability.register( 'MeanAndOrMedianSceneModel', MeanAndOrMedianSceneModel ); \ No newline at end of file diff --git a/js/mean-and-median/model/MeanAndMedianModel.ts b/js/mean-and-median/model/MeanAndMedianModel.ts index 002ad998..b1c3f091 100644 --- a/js/mean-and-median/model/MeanAndMedianModel.ts +++ b/js/mean-and-median/model/MeanAndMedianModel.ts @@ -14,6 +14,7 @@ import CAVModel from '../../common/model/CAVModel.js'; import Tandem from '../../../../tandem/js/Tandem.js'; import NumberProperty from '../../../../axon/js/NumberProperty.js'; import CAVConstants from '../../common/CAVConstants.js'; +import MeanAndOrMedianSceneModel from '../../common/model/MeanAndOrMedianSceneModel.js'; // constants const HIGHLIGHT_ANIMATION_TIME_STEP = 0.25; // in seconds @@ -38,8 +39,8 @@ export default class MeanAndMedianModel extends CAVModel { tandem: options.tandem.createTandem( 'maxKicksProperty' ) } ); - const scene = new CAVSceneModel( maxKicksProperty, CAVConstants.MAX_KICKS_VALUES, CAVSceneModel.chooseDistribution(), { tandem: options.tandem.createTandem( 'sceneModel' ) } ); - super( maxKicksProperty, [ scene ], { + const sceneModel = new MeanAndOrMedianSceneModel( maxKicksProperty, CAVConstants.MAX_KICKS_VALUES, CAVSceneModel.chooseDistribution(), { tandem: options.tandem.createTandem( 'sceneModel' ) } ); + super( maxKicksProperty, [ sceneModel ], { ...options, instrumentMeanPredictionProperty: true } ); @@ -57,7 +58,7 @@ export default class MeanAndMedianModel extends CAVModel { if ( !phet.joist.sim.isSettingPhetioStateProperty.value ) { this.highlightAnimationIndex = 0; - this.lastHighlightAnimationStepTime = scene.timeProperty.value; + this.lastHighlightAnimationStepTime = sceneModel.timeProperty.value; } else { @@ -79,7 +80,7 @@ export default class MeanAndMedianModel extends CAVModel { tandem: options.tandem.createTandem( 'isShowingMeanPredictionProperty' ) } ); - scene.objectValueBecameNonNullEmitter.addListener( () => this.updateAnimation() ); + sceneModel.objectValueBecameNonNullEmitter.addListener( () => this.updateAnimation() ); } public override reset(): void { diff --git a/js/median/model/MedianModel.ts b/js/median/model/MedianModel.ts index f4b4a976..764f0a6f 100644 --- a/js/median/model/MedianModel.ts +++ b/js/median/model/MedianModel.ts @@ -14,6 +14,7 @@ import CAVSceneModel from '../../common/model/CAVSceneModel.js'; import CAVModel from '../../common/model/CAVModel.js'; import Tandem from '../../../../tandem/js/Tandem.js'; import NumberProperty from '../../../../axon/js/NumberProperty.js'; +import MeanAndOrMedianSceneModel from '../../common/model/MeanAndOrMedianSceneModel.js'; export default class MedianModel extends CAVModel { @@ -28,7 +29,7 @@ export default class MedianModel extends CAVModel { tandem: options.tandem.createTandem( 'maxKicksProperty' ) } ); - const scene = new CAVSceneModel( maxKicksProperty, [ 15 ], CAVSceneModel.chooseDistribution(), { tandem: options.tandem.createTandem( 'sceneModel' ) } ); + const scene = new MeanAndOrMedianSceneModel( maxKicksProperty, [ 15 ], CAVSceneModel.chooseDistribution(), { tandem: options.tandem.createTandem( 'sceneModel' ) } ); super( maxKicksProperty, [ scene ], { ...options, instrumentMeanPredictionProperty: false diff --git a/js/variability/model/VariabilitySceneModel.ts b/js/variability/model/VariabilitySceneModel.ts index 80bcda0f..63109ae3 100644 --- a/js/variability/model/VariabilitySceneModel.ts +++ b/js/variability/model/VariabilitySceneModel.ts @@ -26,6 +26,11 @@ export default class VariabilitySceneModel extends CAVSceneModel { this.initialized = true; } + public resetScene(): void { + + // Nothing to do here, the distribution is set in the constructor (and not re-randomized like in the other screens) + } + protected override updateDataMeasures(): void { super.updateDataMeasures();