diff --git a/miniprogram/app.json b/miniprogram/app.json index b64f564..75b0adc 100644 --- a/miniprogram/app.json +++ b/miniprogram/app.json @@ -20,7 +20,10 @@ "numberDecompose/numberDecompose", "numberSort/numberSort", "numberObjectMatch/numberObjectMatch", - "makeTen/makeTen" + "makeTen/makeTen", + "breakTen/breakTen", + "flatTen/flatTen", + "borrowTen/borrowTen" ], "independent": false }, diff --git a/miniprogram/assets/mathEntrance/borrow-ten.png b/miniprogram/assets/mathEntrance/borrow-ten.png new file mode 100644 index 0000000..76a8fd7 Binary files /dev/null and b/miniprogram/assets/mathEntrance/borrow-ten.png differ diff --git a/miniprogram/assets/mathEntrance/break-ten.png b/miniprogram/assets/mathEntrance/break-ten.png new file mode 100644 index 0000000..5d822d9 Binary files /dev/null and b/miniprogram/assets/mathEntrance/break-ten.png differ diff --git a/miniprogram/assets/mathEntrance/flat-ten.png b/miniprogram/assets/mathEntrance/flat-ten.png new file mode 100644 index 0000000..357b189 Binary files /dev/null and b/miniprogram/assets/mathEntrance/flat-ten.png differ diff --git a/miniprogram/constants/mathFunctions.ts b/miniprogram/constants/mathFunctions.ts index 9301c7a..a64ff54 100644 --- a/miniprogram/constants/mathFunctions.ts +++ b/miniprogram/constants/mathFunctions.ts @@ -8,6 +8,54 @@ export interface MathFunctionType { } export const MATH_FUNCTION_TYPES: MathFunctionType[] = [ + { + id: 'make-ten', + page: 'makeTen', + title: '凑十法练习', + desc: '通过凑十法学习20以内进位加法', + icon: '➕', + img: '/assets/mathEntrance/make-ten.png', + }, + { + id: 'break-ten', + page: 'breakTen', + title: '破十法练习', + desc: '通过破十法学习20以内退位减法', + icon: '➖', + img: '/assets/mathEntrance/break-ten.png', + }, + { + id: 'flat-ten', + page: 'flatTen', + title: '平十法练习', + desc: '通过平十法学习20以内退位减法', + icon: '➖', + img: '/assets/mathEntrance/flat-ten.png', + }, + { + id: 'borrow-ten', + page: 'borrowTen', + title: '借十法练习', + desc: '通过借十法学习20以上退位减法', + icon: '➖', + img: '/assets/mathEntrance/borrow-ten.png', + }, + { + id: 'number-decompose-20', + page: 'numberDecompose', + title: '20以内数的分与合', + desc: '把数字分一分,合一合', + icon: '🔢', + img: '/assets/mathEntrance/number-decompose-20.png', + }, + { + id: 'number-decompose', + page: 'numberDecompose', + title: '10以内数的分与合', + desc: '把数字分一分,合一合', + icon: '🔢', + img: '/assets/mathEntrance/number-decompose.png', + }, // 第一阶段:认识数字(最基础) { id: 'number-find', @@ -100,14 +148,7 @@ export const MATH_FUNCTION_TYPES: MathFunctionType[] = [ icon: '🔢', img: '/assets/mathEntrance/number-sort.png', }, - { - id: 'number-decompose', - page: 'numberDecompose', - title: '10以内数的分与合', - desc: '把数字分一分,合一合', - icon: '🔢', - img: '/assets/mathEntrance/number-decompose.png', - }, + // 第四阶段:简单运算(从易到难) { id: 'addition-5', @@ -141,20 +182,4 @@ export const MATH_FUNCTION_TYPES: MathFunctionType[] = [ icon: '±', img: '/assets/mathEntrance/addition-subtraction-10.png', }, - { - id: 'number-decompose-20', - page: 'numberDecompose', - title: '20以内数的分与合', - desc: '把数字分一分,合一合', - icon: '🔢', - img: '/assets/mathEntrance/number-decompose-20.png', - }, - { - id: 'make-ten', - page: 'makeTen', - title: '凑十法练习', - desc: '通过凑十法学习20以内进位加法', - icon: '➕', - img: '/assets/mathEntrance/make-ten.png', - }, ]; diff --git a/miniprogram/mathPages/borrowTen/borrowTen.json b/miniprogram/mathPages/borrowTen/borrowTen.json new file mode 100644 index 0000000..0cf7577 --- /dev/null +++ b/miniprogram/mathPages/borrowTen/borrowTen.json @@ -0,0 +1,13 @@ +{ + "navigationBarTitleText": "借十法练习", + "navigationBarBackgroundColor": "#FFD719", + "homeButton": true, + "backgroundColor": "#F6F6F6", + "enablePullDownRefresh": false, + "usingComponents": { + "share-guide-popup": "../../components/share-guide-popup/share-guide-popup", + "math-type-selector": "../../components/math-type-selector/math-type-selector", + "math-bottom-buttons": "../../components/math-bottom-buttons/math-bottom-buttons", + "draw-ad": "../../components/draw-ad/draw-ad" + } +} diff --git a/miniprogram/mathPages/borrowTen/borrowTen.less b/miniprogram/mathPages/borrowTen/borrowTen.less new file mode 100644 index 0000000..5a66059 --- /dev/null +++ b/miniprogram/mathPages/borrowTen/borrowTen.less @@ -0,0 +1,2 @@ +// 借十法练习页面样式 +@import '../../base/baseDrawPage.wxss'; \ No newline at end of file diff --git a/miniprogram/mathPages/borrowTen/borrowTen.ts b/miniprogram/mathPages/borrowTen/borrowTen.ts new file mode 100644 index 0000000..eeb5da9 --- /dev/null +++ b/miniprogram/mathPages/borrowTen/borrowTen.ts @@ -0,0 +1,195 @@ +import BreakTenDraw from '../shared/service/breakTenDraw'; +import { + createMathPage, + CanvasDataState, +} from '../shared/common/mathPageMixin'; + +createMathPage({ + canvas: null as Canvas | null, + ctx: null as RenderingContext | null, + boxHeight: 0, + boxWidth: 0, + drawService: null as BreakTenDraw | null, + borrowTenData: null as { + problems: Array<{ + minuend: number; // 被减数 + subtrahend: number; // 减数 + result: number; + }>; + } | null, + + data: { + pageTitle: '借十法练习', + functionId: '', + hasContent: false, + showShareDialog: false, + currentMode: 'within-50', // 'within-30', 'within-50', 'within-100' + currentModeName: '50以内', + typeActions: [ + { name: '30以内', value: 'within-30' }, + { name: '50以内', value: 'within-50' }, + { name: '100以内', value: 'within-100' }, + ], + } as CanvasDataState & { + currentMode: string; + currentModeName: string; + typeActions: Array<{ name: string; value: string }>; + }, + + onLoad(options: { id?: string }) { + const functionId = options.id || 'borrow-ten'; + this.initPageInfo(functionId, '借十法练习'); + }, + + onReady() { + this.initCanvas({ + createDrawService: ( + canvas: Canvas, + ctx: RenderingContext, + options?: Record, + ) => { + return new BreakTenDraw(canvas, ctx, options); + }, + drawServiceOptions: { + mnemonic: '拆大数,借出10,减小数,加剩数', // 自定义口诀 + }, + onCanvasReady: () => { + // 初始随机生成 + this.onRandom(); + }, + }); + }, + + /** + * 绘制Canvas内容 + */ + async drawCanvas() { + if (!this.ctx || !this.drawService || !this.borrowTenData) { + return; + } + + try { + await this.drawService.draw(this.borrowTenData); + this.setData({ hasContent: true }); + } catch (error) { + console.error('绘制失败:', error); + this.setData({ hasContent: false }); + } + }, + + /** + * 随机生成 + */ + onRandom() { + // 根据当前模式确定被减数的最大值 + let maxMinuend = 30; // 默认30以内 + if (this.data.currentMode === 'within-50') { + maxMinuend = 50; + } else if (this.data.currentMode === 'within-100') { + maxMinuend = 100; + } + + // 按被减数分组,列出每个被减数对应的所有符合条件的减数组合 + const problemsByMinuend: Map< + number, + Array<{ + minuend: number; + subtrahend: number; + result: number; + }> + > = new Map(); + + // 遍历所有可能的被减数(20到maxMinuend)和减数(1-10)组合 + for (let minuend = 20; minuend <= maxMinuend; minuend++) { + const minuendOnes = minuend % 10; // 被减数的个位数 + + for (let subtrahend = 1; subtrahend <= 10; subtrahend++) { + // 检查条件: + // 1. 被减数的个位 < 减数(借十法的关键要求:减数要大于被减数的个位数) + // 2. 被减数 > 减数(确保结果大于0) + if (minuendOnes < subtrahend && minuend > subtrahend) { + if (!problemsByMinuend.has(minuend)) { + problemsByMinuend.set(minuend, []); + } + problemsByMinuend.get(minuend)!.push({ + minuend, + subtrahend, + result: minuend - subtrahend, + }); + } + } + } + + // 从每个被减数组中选择题目,确保每个被减数都有代表 + const problems: Array<{ + minuend: number; + subtrahend: number; + result: number; + }> = []; + + // 获取所有被减数列表并打乱 + const minuends = Array.from(problemsByMinuend.keys()); + for (let i = minuends.length - 1; i > 0; i--) { + const j = Math.floor(Math.random() * (i + 1)); + [minuends[i], minuends[j]] = [minuends[j], minuends[i]]; + } + + // 从每个被减数组中随机选择,确保分布均匀 + // 如果被减数数量 >= 9,每个被减数至少选1个;如果 < 9,尽量均匀分配 + const targetCount = 9; + const minuendCount = minuends.length; + + if (minuendCount >= targetCount) { + // 被减数数量足够,从每个被减数组中随机选择1个 + for (let i = 0; i < targetCount; i++) { + const minuend = minuends[i]; + const problemsForMinuend = problemsByMinuend.get(minuend)!; + const randomIndex = Math.floor( + Math.random() * problemsForMinuend.length, + ); + problems.push(problemsForMinuend[randomIndex]); + } + } else { + // 被减数数量不足,尽量均匀分配 + const perMinuend = Math.floor(targetCount / minuendCount); + const remainder = targetCount % minuendCount; + + for (let i = 0; i < minuendCount; i++) { + const minuend = minuends[i]; + const problemsForMinuend = problemsByMinuend.get(minuend)!; + const count = perMinuend + (i < remainder ? 1 : 0); // 前remainder个多选1个 + + // 从该被减数组中随机选择count个(不重复) + const shuffled = [...problemsForMinuend]; + for (let j = shuffled.length - 1; j > 0; j--) { + const k = Math.floor(Math.random() * (j + 1)); + [shuffled[j], shuffled[k]] = [shuffled[k], shuffled[j]]; + } + + for (let j = 0; j < Math.min(count, shuffled.length); j++) { + problems.push(shuffled[j]); + } + } + } + + // 最后打乱所有题目顺序 + for (let i = problems.length - 1; i > 0; i--) { + const j = Math.floor(Math.random() * (i + 1)); + [problems[i], problems[j]] = [problems[j], problems[i]]; + } + + this.borrowTenData = { problems }; + this.drawCanvas(); + }, + + /** 选择类型 */ + onSelectType(event: any) { + const { name, value } = event.detail; + this.setData({ + currentMode: value, + currentModeName: name, + }); + // 重新生成数据 + this.onRandom(); + }, +}); diff --git a/miniprogram/mathPages/borrowTen/borrowTen.wxml b/miniprogram/mathPages/borrowTen/borrowTen.wxml new file mode 100644 index 0000000..fbf44f9 --- /dev/null +++ b/miniprogram/mathPages/borrowTen/borrowTen.wxml @@ -0,0 +1,6 @@ + + + +