+++ date = '2025-12-09T23:46:30+08:00' draft = false license = 'MIT Licence' title = '计算概论A 2025年秋 大作业' slug = '001' tags = ['计算概论'] +++ ## 文件下载 [package.zip](package.zip) ## 基本信息 - 程序名称:oasa25; - 编写语言:Swift 5; - 编译环境: - IDE:Xcode Version 26.0.1 (17A400); - macOS:Tahoe 26.0.1 (25A362); - 设备:MacBook Air (13英寸, M3, 2024年); - 借助AI:DeepSeek; - 主要用途: - 在原来代码的基础上进行优化; - 讲解Swift语法; - 修复语法错误; - 协助给程序取名; - "oasa"(“おアサ”)是“大きいアサインメント”(“大作业”)的缩略; - "25"是我的数分I期中考试成绩。 - 程序特色: - 使用上: - 友好的GUI界面; - 包含分栏显示; - 很多图标; - 二次确认,防止误操作; - 完善的存档保存/另存为/读取功能; - 清晰的状态显示; - 支持历史记录查看; - 合法路径绿色高亮显示,被阻挡的路径红色高亮显示; - 支持自由调节蒙特卡洛算法评分参数; - 终端输出蒙特卡洛方法日志; - 利用⌘+N进行多窗口同时操作。 - 技术上: - 使用SwiftUI的现成控件实现GUI界面,减少所需代码; - 使用多个状态变量,状态划分清晰; - 代码分成不同`struct`,分工实现不同功能; - 变量名、函数名等清晰易读(感谢DeepSeek); - 并行处理,提高运行效率; - 实现蒙特卡洛算法; - 缺点:不管怎么调,算法都有点傻傻的,只比随机算法好一点点,在Botzone上被打得毫无还手之力(期末了😭难debug)。 ## 文件组成 - `Assets.xcassets`:存储程序的图标; - 来自教学网上“我的成绩”界面的截图; - `ContentView.swift`:存储程序的主要源代码; - `oasa25样本(若无法运行,则在本机编译).app`:macOS的应用程序包; - `oasa25App.swift`:程序主结构(实际代码较少,仅调用`ContentView()`,不涉及具体实现); - `oasa25_README.md`:程序说明(本文件)。 - `oasa25.xcodeproj`:Xcode项目文件。 - `自动移植版.cpp`:使用DeepSeek帮忙移植的C++版本,用于Botzone对局(期末周😭救命)。 下面重点解说`ContentView.swift`的有关内容: ## 程序结构 - `import`部分: - `Combine`:用于实现`ObservableObject`类型的`GameState`; - `SwiftUI`:提供程序的UI控件; - `UniformTypeIdentifiers`:用于存取文件时对文件类型的规定; - `enum GamePhase:`:设定三个游戏阶段的值; - 选择棋子阶段`selectPiece`; - 移动棋子阶段`movePiece`; - 放置障碍物阶段`placeArrow`; - `struct HistoryEntry`:历史记录数据结构; - id+字符串; - `struct gameData`:规定游戏存档的结构; - 棋盘数据`chessBoard`(二维数组); - 回合数据`blackRound`(Bool值); - 历史记录数据`history`(HistoryEntry数组); - 选中棋子位置`selectedPieceRow`和`selectedPieceCol`(整数); - 阶段数据`gamePhase`; - 上次计算的可用路径`availableMoves`(二维数组); - 读档后无需再次计算; - 游戏结束状态`isGameOver`(Bool值); - 自动下棋选项`blackStrategy`和`whiteStrategy`(字符串); - 当前回合数`roundNum`(整数); - 蒙特卡洛方法计算结果`mcList`(数组); - 控制面板参数值`blackControlFactor`、`blackSafetyFactor`、`blackSurroundFactor`、`blackCenterFactor`、`whiteControlFactor`、`whiteSafetyFactor`、`whiteSurroundFactor`和`whiteCenterFactor`(均为双精度浮点类型); - `class GameState`:游戏状态环境对象 - 声明并初始化各个状态变量(详细列表如上); - `struct GameManager`:游戏逻辑管理器; - `func saveGame`:借助Swift的`NSSavePanel()`功能进行存档的保存(同时会调用自定义的`saveChessBoardToJSON()`); - `func loadGame`:借助Swift的`NSOpenPanel()`功能进行存档的读取(同时会调用自定义的`loadChessBoardFromJSON()`); - `func saveChessBoardToJSON`:借助Swift的`JSONEncoder()`,保存当前棋局为`.json`存档; - `func loadChessBoardFromJSON`:借助Swift的`JSONDecoder()`,从`.json`存档中读取各个变量,还原棋局; - `func initializeChessBoard`:新建游戏时的棋盘初始化; - `func addHistory`:将最近一步操作插入到`history`字符串组的索引`0`位置的一个简单函数; - `func calculateAvailableMoves`:计算可移动的位置,用于给设定按钮状态和染色提供数据; - `func getAllAvailablePieces`:获取所有可用的棋子位置,用于设定按钮状态; - `func getAllCounterPieces`:除了参数相反,和上面函数功能相同; - `func getAllAvailableMoves`:获取所有可移动/可放置障碍物的位置,染色; - `func checkWinCondition`和`func checkAndHandleWinCondition`:检查胜利; - `func handleSquareTap`:处理格子点击; - 蒙特卡洛算法实现部分 - `private func generateMcListForCurrentTurn`:更新`mcList`状态变量 - `private func findBestMoveWithMonteCarlo`:通过给定第一行动回合+往下随机8个回合(并重走30次)计算平均得分,为上述函数提供计算结果; - `private func getAllPossibleMoves`:模拟完整的一个回合的可行操作方案; - `private func simulateRandomGame`:模拟完整一个回合的随机下棋过程; - `private func getRandomMove`:随机选取一个回合的下棋方案(返回值:`piece: (Int, Int), target: (Int, Int), arrow: (Int, Int)`) - `private func isGameOver`:检查游戏是否结束(模拟下棋版); - `private func calculateFinalScore`: - 若中途获胜:返回`1.0`或`-1.0`; - 否则使用下面函数的返回值; - `private func generateRandomMcList`:生成随机走法列表(备用); - 因为Swift要防止使用空值,所以需要一个这样的函数来保证每种情况都有值,实际上不会被调用; - `private func evaluateBoard`:3项评估分数求和+归一化到[-1,1]; - `private func calculateSimuMoves`:计算可以移动的方案(不修改GameState版); - `private func mcSelect`:基于已生成的`mcList`执行选择; - `private func mcMove`:基于已生成的`mcList`执行移动; - `private func mcPlace`:基于已生成的`mcList`放置障碍物; - 综合的自动下棋:`func autoOperate` - 随机下棋: - `private func randomSelect`; - `private func randomMove`; - `private func randomPlace`; - 局势评估算法: - `private func controlScore`:控制分=倍率*所有棋子可移动格子数目之和; - `private func safetyScore`:安全分=每个棋子求和: - +倍率*距离边界的最小距离; - 若被完全包围:-包围惩罚; - 否则:+倍率*所有棋子可移动格子数目之和;(怎么感觉和上面控制分有点重复) - `private func centerScore`:中心分=每个棋子求和: - 若在中心:+倍率*5; - +(10-离中心点距离); - `struct ChessSquareView`:棋盘格子视图; - 实现单个棋盘格子的显示; - `func getSquareColor`:染色; - `func isInteractive`:设定按钮状态; - `struct ChessBoardRowView`:棋盘行视图; - 实现棋盘单行的显示; - 调用`struct ChessSquareView`; - `struct ChessBoardView`:棋盘视图; - 实现棋盘的完整显示; - 调用`struct ChessBoardRowView`; - `struct MenuButtonView`:菜单按钮视图; - 作为定义主菜单按钮的模板,避免代码的大量重复; - `struct SidebarView`:左侧栏视图; - `var gameInfoView`:显示当前存档路径、当前回合、当前阶段、历史操作; - `var phaseDescription`:把阶段的代号转换成文字描述; - `var welcomeView`:显示第一局游戏开始前的引导信息; - `struct ParameterSliderView`:负责单一滑块组件; - `struct ParameterSettingsView`:生成完整滑块界面; - `struct RightView`:右侧栏视图; - 自动下棋控制面板,支持调节参数; - `struct MainMenuView`:主菜单视图; - 实现主菜单的显示; - 多次调用`struct MenuButtonView`,实现各个菜单按钮; - 依据状态变量的不同,显示不同的按钮; - `struct ContentView`:主视图。 - 划分窗口结构: - 调用`SidebarView`,实现左侧栏的状态显示; - 调用`MainMenuView`,实现左下角的菜单控制; - 调用`ChessBoardView`,实现右侧的棋盘显示。 - 调用`RightView`; - 定义函数`private func setWindowTitle` - 使用`.onAppear`在程序启动时设置窗口标题。