Files
doodle-mini/miniprogram/mathPages/borrowTen/borrowTen.ts
T
2025-12-25 14:59:57 +08:00

196 lines
6.6 KiB
TypeScript

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<string, any>,
) => {
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();
},
});