196 lines
6.6 KiB
TypeScript
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();
|
|
},
|
|
});
|