如何在Racket中设计支持点击交互的数独游戏网格?
DrRacket 数独交互网格实现方案
你可以直接基于DrRacket自带的2htdp/universe(大爆炸交互框架)和2htdp/image(绘图库)实现需求,完全兼容你现有的SudokuNumber数据结构和check-answer校验逻辑,核心实现步骤如下:
1 前置状态定义
首先补充定义世界状态结构体,用来存储运行时的所有交互状态:
; 世界状态定义:sudoku-list是你现有的SudokuNumber列表,active-pos是当前激活的单元格坐标,fixed-positions是初始固定不可修改的提示数坐标列表 (define-struct world [sudoku-list active-pos fixed-positions])
fixed-positions可以在你随机生成数独的时候同步生成,把初始有数字的坐标都存进去,用来限制用户不能修改提示格。
2 核心辅助函数
先写一个用来更新数独列表的通用函数,用户修改单元格的时候直接调用,完全兼容你现有的数据结构:
; 输入:原始SudokuNumber列表、要修改的单元格坐标、新数字 ; 输出:更新后的SudokuNumber列表,可直接传给你现有的check-answer函数使用 (define (update-sudoku sudoku-list target-pos new-num) (map (lambda (sn) (if (equal? (SudokuNumber-position sn) target-pos) (make-SudokuNumber new-num target-pos) sn)) sudoku-list))
3 交互事件处理
3.1 鼠标点击事件(激活单元格)
实现点击单元格激活的逻辑,同时自动过滤不可编辑的固定格:
(define (handle-mouse current-world x y event) (if (mouse=? event "button-down") ; 以下像素转坐标的参数可根据你自己的网格绘制尺寸调整,示例中假设每个单元格边长40px,网格整体左上角偏移(20,20) (let* ([grid-x (- (quotient (- x 20) 40) 4)] [grid-y (- 4 (quotient (- y 20) 40))] ; 这里做y轴翻转适配,和你(-4,-4)到(4,4)的坐标体系对齐 [clicked-pos (list grid-x grid-y)]) (if (and (>= grid-x -4) (<= grid-x 4) ; 点击在网格范围内 (>= grid-y -4) (<= grid-y 4) (not (member clicked-pos (world-fixed-positions current-world)))) ; 不是固定不可编辑格 (make-world (world-sudoku-list current-world) clicked-pos (world-fixed-positions current-world)) current-world)) current-world))
3.2 键盘输入事件(修改/删除数字)
实现激活单元格后的输入逻辑,仅支持1-9数字输入和删除操作:
(define (handle-key current-world key) ; 没有激活单元格时直接忽略所有按键 (if (not (world-active-pos current-world)) current-world (cond ; 按1-9更新单元格数字 [(member key '("1" "2" "3" "4" "5" "6" "7" "8" "9")) (make-world (update-sudoku (world-sudoku-list current-world) (world-active-pos current-world) (string->number key)) (world-active-pos current-world) (world-fixed-positions current-world))] ; 按退格/删除键清空单元格 [(or (key=? key "\b") (key=? key "delete")) (make-world (update-sudoku (world-sudoku-list current-world) (world-active-pos current-world) 0) ; 如果你用#f或者其他值表示空单元格,替换此处的0即可 (world-active-pos current-world) (world-fixed-positions current-world))] [else current-world])))
4 网格绘制
你只需要补充绘制函数即可,核心逻辑是:
- 遍历所有
SudokuNumber元素,每个元素绘制为一个方格 - 当前激活的方格用不同颜色的边框高亮
- 固定提示格的数字用黑色绘制,用户输入的数字用蓝色绘制
- 如果需要校验输入合法性,可直接调用你现有的校验逻辑,把非法数字标红即可
绘制完成后,用大爆炸函数启动程序即可:
(big-bang (make-world 你的初始SudokuNumber列表 #f 你的固定格坐标列表) [on-draw 你写的绘制函数] [on-mouse handle-mouse] [on-key handle-key])
内容的提问来源于stack exchange,提问作者Carson_He
相关产品推荐
相关产品推荐

