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(); }, });