import DotConnectDraw from '../shared/service/dotConnectDraw'; import { createFocusPage } from '../shared/common/focusPageMixin'; import { DotConnectData } from '../shared/service/dotConnectDraw'; import { getRandomUniqueNumberColors } from '../../constants/colors'; createFocusPage({ canvas: null as Canvas | null, ctx: null as RenderingContext | null, boxHeight: 0, boxWidth: 0, drawService: null as DotConnectDraw | null, dotConnectData: null as DotConnectData | null, data: { pageTitle: '数字点连线', functionId: '', hasContent: false, showShareDialog: false, }, onLoad(options: { id?: string }) { const functionId = options.id || 'dot-connect'; this.setData({ functionId, }); this.initPageInfo(functionId, '数字点连线'); }, onReady() { this.initCanvas({ createDrawService: ( canvas: Canvas, ctx: RenderingContext, options?: Record, ) => { return new DotConnectDraw(canvas, ctx, options); }, drawServiceOptions: { title: this.data.pageTitle, functionId: this.data.functionId, }, onCanvasReady: () => { // 初始随机生成 this.onRandom(); }, }); }, /** * 绘制Canvas内容 */ async drawCanvas() { if (!this.ctx || !this.drawService || !this.dotConnectData) { return; } try { await this.drawService.draw(this.dotConnectData); this.setData({ hasContent: true }); } catch (error) { console.error('绘制失败:', error); this.setData({ hasContent: false }); } }, /** * 生成不走回头路的数字序列 * @param length 序列长度 * @returns 数字序列数组 */ generateNonBacktrackingSequence(length: number): number[] { // 3x3 网格中数字的位置映射 // 1: (0,0), 2: (1,0), 3: (2,0) // 4: (0,1), 5: (1,1), 6: (2,1) // 7: (0,2), 8: (1,2), 9: (2,2) const getPosition = (num: number): [number, number] => { const row = Math.floor((num - 1) / 3); const col = (num - 1) % 3; return [row, col]; }; // 检查从位置A到位置B再到位置C是否走回头路 const isBacktrack = ( posA: [number, number], posB: [number, number], posC: [number, number], ): boolean => { // 如果C等于A,说明走回头路了 return posC[0] === posA[0] && posC[1] === posA[1]; }; const sequence: number[] = []; const used = new Set(); // 随机选择起始数字 const startNum = Math.floor(Math.random() * 9) + 1; sequence.push(startNum); used.add(startNum); let prevPos = getPosition(startNum); let prevPrevPos: [number, number] | null = null; // 生成剩余的数字 while (sequence.length < length) { const candidates: number[] = []; for (let num = 1; num <= 9; num++) { if (used.has(num)) continue; const currentPos = getPosition(num); // 如果有前前一个位置,检查是否走回头路 if (prevPrevPos) { if (isBacktrack(prevPrevPos, prevPos, currentPos)) { continue; } } candidates.push(num); } if (candidates.length === 0) { // 如果没有候选数字,随机选择一个未使用的数字 const remaining = Array.from( { length: 9 }, (_, i) => i + 1, ).filter((n) => !used.has(n)); if (remaining.length === 0) break; const nextNum = remaining[Math.floor(Math.random() * remaining.length)]; sequence.push(nextNum); used.add(nextNum); prevPrevPos = prevPos; prevPos = getPosition(nextNum); } else { // 随机选择一个候选数字 const nextNum = candidates[Math.floor(Math.random() * candidates.length)]; sequence.push(nextNum); used.add(nextNum); prevPrevPos = prevPos; prevPos = getPosition(nextNum); } } return sequence; }, /** * 随机生成 */ onRandom() { // 生成1-9的数字颜色映射(每个数字使用随机颜色) const numbers = [1, 2, 3, 4, 5, 6, 7, 8, 9]; const colors = getRandomUniqueNumberColors(9); const colorMap = numbers.map((number, index) => ({ number, color: colors[index], })); // 生成9个组的题目 const groups: Array<{ sequence: number[]; }> = []; for (let i = 0; i < 9; i++) { // 生成不走回头路的数字序列,长度在4-6之间 const sequenceLength = Math.floor(Math.random() * 3) + 4; // 4, 5, 或 6 const sequence = this.generateNonBacktrackingSequence(sequenceLength); groups.push({ sequence, }); } this.dotConnectData = { colorMap, groups, }; this.drawCanvas(); }, });