Files
doodle-mini/miniprogram/mathPages/makeTen/makeTen.ts
T
2025-12-24 18:15:01 +08:00

169 lines
5.8 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import MakeTenDraw from '../shared/service/makeTenDraw';
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 MakeTenDraw | null,
makeTenData: null as {
problems: Array<{
left: number;
right: number;
result: number;
}>;
} | null,
data: {
pageTitle: '凑十法练习',
subTitle: '通过凑十法学习20以内进位加法',
functionId: '',
hasContent: false,
showShareDialog: false,
} as CanvasDataState,
onLoad(options: { id?: string }) {
const functionId = options.id || 'make-ten';
this.initPageInfo(functionId, '凑十法练习');
},
onReady() {
this.initCanvas({
createDrawService: (
canvas: Canvas,
ctx: RenderingContext,
options?: Record<string, any>,
) => {
return new MakeTenDraw(canvas, ctx, options);
},
drawServiceOptions: {
subTitle: this.data.subTitle,
},
onCanvasReady: () => {
// 初始随机生成
this.onRandom();
},
});
},
/**
* 绘制Canvas内容
*/
async drawCanvas() {
if (!this.ctx || !this.drawService || !this.makeTenData) {
return;
}
try {
await this.drawService.draw(this.makeTenData);
this.setData({ hasContent: true });
} catch (error) {
console.error('绘制失败:', error);
this.setData({ hasContent: false });
}
},
/**
* 随机生成
*/
onRandom() {
const problems: Array<{
left: number;
right: number;
result: number;
}> = [];
// 用于记录已生成的题目,避免重复(9+2 和 2+9 视为不同)
const usedProblems = new Set<string>();
// 生成9道题目(3行3列)
let attempts = 0;
const maxAttempts = 1000; // 最大尝试次数,避免无限循环
while (problems.length < 9 && attempts < maxAttempts) {
attempts++;
// 生成两个数,确保:
// 1. 两个加数都在1-9之间(不能是10)
// 2. 和大于10且小于等于20(需要凑十法)
// 3. 大数至少是6(因为5无法满足条件:5 + 最大小数4 = 9 < 11
let left: number;
let right: number;
// 随机决定大数在前还是在后
const bigFirst = Math.random() < 0.5;
if (bigFirst) {
// 大数在前:left 在 6-9 之间,right 在 1-9 之间
// 确保 left + right >= 11 且 left + right <= 20
left = Math.floor(Math.random() * 4) + 6; // 6-9
// right 的最小值:确保 left + right >= 11,即 right >= 11 - left
const minRight = Math.max(1, 11 - left);
// right 的最大值:确保 left + right <= 20,即 right <= 20 - left,且 right <= 9
const maxRight = Math.min(9, 20 - left);
// 确保 right < left(因为 left 是大数)
const actualMaxRight = Math.min(maxRight, left - 1);
// 检查是否有有效的 right 值
if (actualMaxRight >= minRight) {
right =
Math.floor(
Math.random() * (actualMaxRight - minRight + 1),
) + minRight;
} else {
// 如果无法生成有效值,跳过本次循环
continue;
}
} else {
// 大数在后:left 在 1-9 之间,right 在 6-9 之间
// 确保 left + right >= 11 且 left + right <= 20
right = Math.floor(Math.random() * 4) + 6; // 6-9
// left 的最小值:确保 left + right >= 11,即 left >= 11 - right
const minLeft = Math.max(1, 11 - right);
// left 的最大值:确保 left + right <= 20,即 left <= 20 - right,且 left <= 9
const maxLeft = Math.min(9, 20 - right);
// 确保 left < right(因为 right 是大数)
const actualMaxLeft = Math.min(maxLeft, right - 1);
// 检查是否有有效的 left 值
if (actualMaxLeft >= minLeft) {
left =
Math.floor(
Math.random() * (actualMaxLeft - minLeft + 1),
) + minLeft;
} else {
// 如果无法生成有效值,跳过本次循环
continue;
}
}
// 检查是否重复(9+2 和 2+9 视为不同)
const problemKey = `${left},${right}`;
if (usedProblems.has(problemKey)) {
// 如果已存在,跳过本次循环,重新生成
continue;
}
// 添加到已使用集合
usedProblems.add(problemKey);
const result = left + right;
problems.push({
left,
right,
result,
});
}
// 如果尝试次数过多仍未生成足够的题目,输出警告
if (problems.length < 9) {
console.warn(
`只生成了 ${problems.length} 道题目,可能符合条件的题目组合不足`,
);
}
this.makeTenData = { problems };
this.drawCanvas();
},
});