/* Stepper module: Math / Modulus Visual type: remainder-bar TEMPLATE NOTE: no em dashes anywhere -- use plain hyphens or rewrite the sentence. */ STEPPER_REGISTRY.register("math/modulus", { label: 'Modulus', panelConfig: { visual: { title: 'Remainder diagram' }, stack: false, heap: false, custom: false, editableInputs: [ { id: 'dividend', label: 'a', type: 'integer', defaultVal: 17, min: 0, max: 999 }, { id: 'divisor', label: 'b', type: 'integer', defaultVal: 5, min: 1, max: 99 }, ], legend: [ { color:'#095e40', border:'#90d4b8', label:'Complete group' }, { color:'#a0540a', border:'#e8c070', label:'Remainder (left over)' }, { color:'#d4d1cc', border:'#b8b4ae', label:'Not yet reached' }, ] }, // Returns updated code lines when the user edits values (scenario 0 only) getCodeLines(scenIdx, params) { if (scenIdx !== 0 || !params) return null; return [ { code: [['tok-op','a = '],['tok-num', String(params.dividend)]] }, { code: [['tok-op','b = '],['tok-num', String(params.divisor)]] }, { code: [['tok-op','r = a % b']] }, ]; }, scenarios: [ // ---------------------------------------------------------------- // Scenario 1 -- 17 % 5 // Lines (0-indexed, blanks excluded from count): // 0: a = 17 // 1: b = 5 // 2: r = a % b // ---------------------------------------------------------------- { label: '17 % 5', lines: [ { code: [['tok-op','a = '],['tok-num','17']] }, { code: [['tok-op','b = '],['tok-num','5']] }, { code: [['tok-op','r = a % b']] }, ], steps: [ { line: 0, visual: { type:'remainder-bar', dividend:17, divisor:5, groupsVisible:0, remainderVisible:0, showSummary:false, highlightStep:'equation' }, expl: { label:'The dividend', text:'a = 17 is the dividend -- the number we are dividing up. We want to split it into equal groups of 5.' } }, { line: 1, visual: { type:'remainder-bar', dividend:17, divisor:5, groupsVisible:0, remainderVisible:0, showSummary:false, highlightStep:'groups' }, expl: { label:'The divisor', text:'b = 5 is the divisor -- the size of each group. The question % asks: after making as many groups of 5 as possible, what is left?' } }, { line: 2, visual: { type:'remainder-bar', dividend:17, divisor:5, groupsVisible:1, remainderVisible:0, showSummary:false, highlightStep:'groups' }, expl: { label:'First group', text:'Can we pull out one group of 5 from 17? Yes -- that accounts for 5, leaving 12 behind.' } }, { line: 2, visual: { type:'remainder-bar', dividend:17, divisor:5, groupsVisible:2, remainderVisible:0, showSummary:false, highlightStep:'groups' }, expl: { label:'Second group', text:'Can we pull out another group of 5? Yes -- 10 accounted for, 7 remaining.' } }, { line: 2, visual: { type:'remainder-bar', dividend:17, divisor:5, groupsVisible:3, remainderVisible:0, showSummary:false, highlightStep:'groups' }, expl: { label:'Third group', text:'One more group of 5. That is 15 accounted for, 2 remaining. Can we make a fourth group? No -- 2 is less than 5.' } }, { line: 2, visual: { type:'remainder-bar', dividend:17, divisor:5, groupsVisible:3, remainderVisible:2, showSummary:false, highlightStep:'remainder' }, expl: { label:'The remainder', text:'We cannot make another full group. The 2 cells left over are the remainder. That is what % gives us.' } }, { line: 2, visual: { type:'remainder-bar', dividend:17, divisor:5, groupsVisible:3, remainderVisible:2, showSummary:true, highlightStep:'equation' }, expl: { label:'17 % 5 = 2', text:'17 % 5 = 2. Three complete groups of 5 (= 15) plus 2 left over. The remainder is always less than the divisor -- here, less than 5.' } }, ] }, // ---------------------------------------------------------------- // Scenario 2 -- even/odd with 8 % 2 and 9 % 2 // Lines: // 0: n = 8 // 1: r = n % 2 // 2: // r == 0, so n is even // (blank) // 3: n = 9 // 4: r = n % 2 // 5: // r == 1, so n is odd // ---------------------------------------------------------------- { label: 'Even or odd', lines: [ { code: [['tok-op','n = '],['tok-num','8']] }, { code: [['tok-op','r = n % '],['tok-num','2']] }, { code: [['tok-cmt','// r == 0, so n is even']] }, { blank: true }, { code: [['tok-op','n = '],['tok-num','9']] }, { code: [['tok-op','r = n % '],['tok-num','2']] }, { code: [['tok-cmt','// r == 1, so n is odd']] }, ], steps: [ { line: 0, visual: { type:'remainder-bar', dividend:8, divisor:2, groupsVisible:0, remainderVisible:0, showSummary:false, highlightStep:'equation' }, expl: { label:'n = 8', text:'Start with n = 8. We divide by 2 to check if it splits into pairs with nothing left over.' } }, { line: 1, visual: { type:'remainder-bar', dividend:8, divisor:2, groupsVisible:4, remainderVisible:0, showSummary:false, highlightStep:'groups' }, expl: { label:'Dividing into pairs', text:'8 breaks into exactly 4 groups of 2. Every element has a pair. There is nothing left over.' } }, { line: 2, visual: { type:'remainder-bar', dividend:8, divisor:2, groupsVisible:4, remainderVisible:0, showSummary:true, highlightStep:'equation' }, expl: { label:'r = 0, so even', text:'8 % 2 = 0. A remainder of zero means the number divides perfectly into pairs -- it is even. The rule: n % 2 == 0 is even.' } }, { line: 3, visual: { type:'remainder-bar', dividend:9, divisor:2, groupsVisible:0, remainderVisible:0, showSummary:false, highlightStep:'equation' }, expl: { label:'n = 9', text:'Now try n = 9. Same question: do we run out of pairs, or is one left?' } }, { line: 4, visual: { type:'remainder-bar', dividend:9, divisor:2, groupsVisible:4, remainderVisible:0, showSummary:false, highlightStep:'groups' }, expl: { label:'Four pairs...', text:'We can make 4 pairs (8 accounted for). But there is one more element sitting outside any pair.' } }, { line: 4, visual: { type:'remainder-bar', dividend:9, divisor:2, groupsVisible:4, remainderVisible:1, showSummary:false, highlightStep:'remainder' }, expl: { label:'...and one left over', text:'That lone cell is the remainder. It cannot pair up. That is what makes 9 odd.' } }, { line: 5, visual: { type:'remainder-bar', dividend:9, divisor:2, groupsVisible:4, remainderVisible:1, showSummary:true, highlightStep:'equation' }, expl: { label:'r = 1, so odd', text:'9 % 2 = 1. Any non-zero remainder means odd. Pattern: n % 2 == 0 is even, n % 2 == 1 is odd. Works for every integer.' } }, ] }, // ---------------------------------------------------------------- // Scenario 3 -- wrap-around index: (4 + 1) % 5 // Lines: // 0: size = 5 // 1: i = 4 // 2: next = (i + 1) % size // ---------------------------------------------------------------- { label: 'Wrap-around', lines: [ { code: [['tok-op','size = '],['tok-num','5']] }, { code: [['tok-op','i = '],['tok-num','4']] }, { code: [['tok-op','next = (i + '],['tok-num','1'],['tok-op',') % size']] }, ], steps: [ { line: 0, visual: { type:'remainder-bar', dividend:5, divisor:5, groupsVisible:0, remainderVisible:0, showSummary:false, highlightStep:'equation' }, expl: { label:'size = 5', text:'We have a list with 5 slots. Valid indices are 0 through 4.' } }, { line: 1, visual: { type:'remainder-bar', dividend:5, divisor:5, groupsVisible:0, remainderVisible:0, showSummary:false, highlightStep:'equation' }, expl: { label:'i = 4 (last slot)', text:'i = 4 is the last valid index. Adding 1 gives 5, which is out of bounds. We need to wrap around to 0.' } }, { line: 2, visual: { type:'remainder-bar', dividend:5, divisor:5, groupsVisible:0, remainderVisible:0, showSummary:false, highlightStep:'equation' }, expl: { label:'Evaluating i + 1', text:'i + 1 = 5. Now compute 5 % 5. How many complete groups of 5 fit into 5?' } }, { line: 2, visual: { type:'remainder-bar', dividend:5, divisor:5, groupsVisible:1, remainderVisible:0, showSummary:false, highlightStep:'groups' }, expl: { label:'Exactly one group', text:'5 fits into 5 exactly once -- one complete group with nothing left over.' } }, { line: 2, visual: { type:'remainder-bar', dividend:5, divisor:5, groupsVisible:1, remainderVisible:0, showSummary:true, highlightStep:'equation' }, expl: { label:'next = 0', text:'5 % 5 = 0. The remainder is 0, so next wraps back to the start of the list. The cycle: 0, 1, 2, 3, 4, 0, 1, 2... never out of bounds.' } }, ] }, ] });