基于 Spring Boot 的井字棋游戲開發與實現

目錄

引言

項目概述

項目搭建

1. 環境準備

2. 創建 Spring Boot 項目

3. 項目結構

代碼實現

1.?DemoApplication.java

2.?TicTacToeController.java

3.?pom.xml

電腦落子策略 - Minimax 算法

findBestMove?方法

minimax?方法

運行游戲

總結


引言

????????在軟件開發領域,通過構建簡單的游戲項目來學習和實踐新的技術框架是一種高效且有趣的方式。本文將詳細介紹如何使用 Spring Boot 和 Maven 框架開發一個簡單的井字棋(Tic - Tac - Toe)游戲。這個項目不僅能幫助你熟悉 Spring Boot 的基本使用,還能讓你了解如何構建一個基于 RESTful 接口的交互式應用。

項目概述

????????我們要開發的井字棋游戲是一個基于 Web 的應用,玩家可以通過瀏覽器或工具(如 Postman)發送請求來與電腦進行游戲。游戲規則遵循傳統的井字棋規則,玩家和電腦輪流在 3x3 的棋盤上落子,先在橫、豎、斜方向連成一線的一方獲勝,如果棋盤填滿且沒有一方獲勝,則為平局。

項目搭建

1. 環境準備

確保你已經安裝了 Java 和 Maven。Java 是運行 Spring Boot 應用的基礎,而 Maven 則用于管理項目的依賴和構建。

2. 創建 Spring Boot 項目

可以使用 Spring Initializr(https://start.spring.io/)來快速創建一個 Spring Boot 項目,選擇以下配置:

  • Project: Maven Project
  • Language: Java
  • Spring Boot: 2.7.5
  • Dependencies: Spring Web

3. 項目結構

項目的主要結構如下:

src
├── main
│   ├── java
│   │   └── com
│   │       └── example
│   │           └── demo
│   │               ├── DemoApplication.java
│   │               └── controller
│   │                   └── TicTacToeController.java
│   └── resources
│       └── application.properties
└── pom.xml

代碼實現

1.?DemoApplication.java

package com.example.demo;import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;@SpringBootApplication
public class DemoApplication {public static void main(String[] args) {SpringApplication.run(DemoApplication.class, args);}}

這是 Spring Boot 的主應用類,包含?main?方法,用于啟動 Spring Boot 應用。@SpringBootApplication?注解是一個組合注解,它包含了?@Configuration@EnableAutoConfiguration?和?@ComponentScan?注解,用于自動配置 Spring Boot 應用。

2.?TicTacToeController.java

package com.example.demo.controller;import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;import java.util.ArrayList;
import java.util.List;
import java.util.Random;@RestController
public class TicTacToeController {private static final int BOARD_SIZE = 3;private char[][] board = new char[BOARD_SIZE][BOARD_SIZE];private boolean isPlayerTurn = true;private boolean gameOver = false;private char winner = ' ';public TicTacToeController() {initializeBoard();}private void initializeBoard() {for (int i = 0; i < BOARD_SIZE; i++) {for (int j = 0; j < BOARD_SIZE; j++) {board[i][j] = ' ';}}isPlayerTurn = true;gameOver = false;winner = ' ';}@GetMapping("/start")public String startGame() {initializeBoard();return "新游戲開始!你先手,使用 /move?row=x&col=y 落子(x 和 y 范圍 0 - 2)。";}@GetMapping("/move")public String makeMove(@RequestParam int row, @RequestParam int col) {if (gameOver) {return "游戲已結束,請使用 /start 開始新游戲。";}if (!isPlayerTurn) {return "現在是電腦回合,請等待。";}if (!isValidMove(row, col)) {return "無效的落子位置,請重新選擇。";}board[row][col] = 'X';checkGameStatus();if (!gameOver) {computerMove();checkGameStatus();}return getBoardStatus();}private boolean isValidMove(int row, int col) {return row >= 0 && row < BOARD_SIZE && col >= 0 && col < BOARD_SIZE && board[row][col] == ' ';}private void computerMove() {List<int[]> availableMoves = getAvailableMoves();if (availableMoves.isEmpty()) {return;}int[] bestMove = findBestMove();board[bestMove[0]][bestMove[1]] = 'O';isPlayerTurn = true;}private List<int[]> getAvailableMoves() {List<int[]> moves = new ArrayList<>();for (int i = 0; i < BOARD_SIZE; i++) {for (int j = 0; j < BOARD_SIZE; j++) {if (board[i][j] == ' ') {moves.add(new int[]{i, j});}}}return moves;}private int[] findBestMove() {int bestScore = Integer.MIN_VALUE;int[] bestMove = null;for (int[] move : getAvailableMoves()) {board[move[0]][move[1]] = 'O';int score = minimax(board, 0, false);board[move[0]][move[1]] = ' ';if (score > bestScore) {bestScore = score;bestMove = move;}}return bestMove;}private int minimax(char[][] board, int depth, boolean isMaximizing) {if (hasWon('O')) {return 1;} else if (hasWon('X')) {return -1;} else if (getAvailableMoves().isEmpty()) {return 0;}if (isMaximizing) {int bestScore = Integer.MIN_VALUE;for (int[] move : getAvailableMoves()) {board[move[0]][move[1]] = 'O';int score = minimax(board, depth + 1, false);board[move[0]][move[1]] = ' ';bestScore = Math.max(score, bestScore);}return bestScore;} else {int bestScore = Integer.MAX_VALUE;for (int[] move : getAvailableMoves()) {board[move[0]][move[1]] = 'X';int score = minimax(board, depth + 1, true);board[move[0]][move[1]] = ' ';bestScore = Math.min(score, bestScore);}return bestScore;}}private boolean hasWon(char player) {// 檢查行for (int i = 0; i < BOARD_SIZE; i++) {if (board[i][0] == player && board[i][0] == board[i][1] && board[i][1] == board[i][2]) {return true;}}// 檢查列for (int j = 0; j < BOARD_SIZE; j++) {if (board[0][j] == player && board[0][j] == board[1][j] && board[1][j] == board[2][j]) {return true;}}// 檢查對角線if (board[0][0] == player && board[0][0] == board[1][1] && board[1][1] == board[2][2]) {return true;}if (board[0][2] == player && board[0][2] == board[1][1] && board[1][1] == board[2][0]) {return true;}return false;}private void checkGameStatus() {if (hasWon('X')) {winner = 'X';gameOver = true;return;}if (hasWon('O')) {winner = 'O';gameOver = true;return;}// 檢查平局if (getAvailableMoves().isEmpty()) {gameOver = true;winner = ' ';}}private String getBoardStatus() {StringBuilder sb = new StringBuilder();for (int i = 0; i < BOARD_SIZE; i++) {for (int j = 0; j < BOARD_SIZE; j++) {sb.append(board[i][j]);if (j < BOARD_SIZE - 1) {sb.append(" | ");}}sb.append("\n");if (i < BOARD_SIZE - 1) {sb.append("---------\n");}}if (gameOver) {if (winner == 'X') {sb.append("你贏了!使用 /start 開始新游戲。");} else if (winner == 'O') {sb.append("電腦贏了!使用 /start 開始新游戲。");} else {sb.append("平局!使用 /start 開始新游戲。");}} else {sb.append("輪到你落子,使用 /move?row=x&col=y。");}return sb.toString();}
}

這是一個 RESTful 控制器,包含兩個主要的端點:

  • /start:用于開始新游戲,調用?initializeBoard?方法初始化棋盤,并返回提示信息。
  • /move:用于玩家落子,接收玩家的落子位置,驗證其有效性,更新棋盤狀態,檢查游戲是否結束,如果未結束則調用?computerMove?方法讓電腦落子,最后返回當前棋盤狀態。

3.?pom.xml

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd"><modelVersion>4.0.0</modelVersion><groupId>com.example</groupId><artifactId>demo</artifactId><version>0.0.1-SNAPSHOT</version><packaging>jar</packaging><name>demo</name><description>Demo project for Spring Boot</description><parent><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-parent</artifactId><version>2.7.5</version><relativePath/> <!-- lookup parent from repository --></parent><properties><java.version>1.8</java.version></properties><dependencies><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-test</artifactId><scope>test</scope></dependency></dependencies><build><plugins><plugin><groupId>org.springframework.boot</groupId><artifactId>spring-boot-maven-plugin</artifactId></plugin></plugins></build></project>

????????這是 Maven 項目的配置文件,包含了項目的依賴和構建配置。spring-boot-starter-web?依賴用于支持 Spring Web 開發,spring-boot-starter-test?依賴用于測試。

電腦落子策略 - Minimax 算法

????????電腦落子使用了 Minimax 算法來尋找最優落子位置。Minimax 算法是一種遞歸算法,用于在零和博弈中尋找最優策略。在井字棋游戲中,電腦會模擬所有可能的落子情況,通過遞歸調用?minimax?方法計算每個落子的得分,然后選擇得分最高的落子位置。

findBestMove?方法

????????該方法遍歷所有可用的落子位置,對每個位置調用?minimax?方法計算得分,最終選擇得分最高的位置作為最佳落子位置。

minimax?方法

  • 如果電腦獲勝,返回 1。
  • 如果玩家獲勝,返回 -1。
  • 如果平局,返回 0。
  • 如果是電腦回合(isMaximizing?為?true),選擇得分最高的落子。
  • 如果是玩家回合(isMaximizing?為?false),選擇得分最低的落子。

運行游戲

  1. 打開終端,進入項目根目錄,運行以下命令啟動應用:
mvn spring-boot:run
  1. 打開瀏覽器或使用工具(如 Postman)訪問以下 URL 來玩游戲:
  2. 開始游戲:http://localhost:8080/start
  3. 落子:http://localhost:8080/move?row=0&col=0(將?0?替換為你想要的落子位置)

總結

通過這個項目,我們學習了如何使用 Spring Boot 和 Maven 框架開發一個簡單的井字棋游戲。同時,我們還了解了 Minimax 算法在游戲開發中的應用,通過該算法可以讓電腦做出更智能的決策。這個項目不僅可以作為學習 Spring Boot 的入門示例,還可以進一步擴展,例如添加用戶界面、支持多人游戲等。

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/diannao/80912.shtml
繁體地址,請注明出處:http://hk.pswp.cn/diannao/80912.shtml
英文地址,請注明出處:http://en.pswp.cn/diannao/80912.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

【算法筆記】貪心算法

一、什么是貪心算法&#xff1f; 貪心算法是一種在每一步選擇中都采取當前看起來最優&#xff08;最“貪心”&#xff09;的策略&#xff0c;從而希望得到全局最優解的算法設計思想。 核心思想&#xff1a;每一步都做出局部最優選擇&#xff0c;不回退。適用場景&#xff1a;…

現代c++獲取linux所有的網絡接口名稱

現代c獲取linux所有的網絡接口名稱 前言一、在linux中查看網絡接口名稱二、使用c代碼獲取三、驗證四、完整代碼如下五、總結 前言 本文介紹一種使用c獲取本地所有網絡接口名稱的方法。 一、在linux中查看網絡接口名稱 在linux系統中可以使用ifconfig -a命令列舉出本機所有網絡…

打印及判斷回文數組、打印N階數組、蛇形矩陣

打印回文數組 1 1 1 1 1 1 2 2 2 1 1 2 3 2 1 1 2 2 2 1 1 1 1 1 1方法1&#xff1a; 對角線對稱 左上和右下是對稱的。 所以先考慮左上打印&#xff0c; m i n ( i 1 , j 1 ) \text min(i1,j1) min(i1,j1)&#xff0c;打印出來&#xff1a; 1 1 1 1 1 2 2 2 1 2 3 3 1 2 …

詳解UnityWebRequest類

什么是UnityWebRequest類 UnityWebRequest 是 Unity 引擎中用于處理網絡請求的一個強大類&#xff0c;它可以讓你在 Unity 項目里方便地與網絡資源進行交互&#xff0c;像發送 HTTP 請求、下載文件等操作都能實現。下面會詳細介紹 UnityWebRequest 的相關內容。 UnityWebRequ…

UE5 在旋轉A的基礎上執行旋轉B

用徑向slider實現模型旋轉時&#xff0c;得到的結果與ue編輯器里面的結果有很大出入。 問題應該是 兩個FRotator&#xff08;0&#xff0c;10&#xff0c;0&#xff09;和&#xff08;10&#xff0c;20&#xff0c;30&#xff09;&#xff0c; 兩個FRotator的加法結果為&…

4.2 Prompt工程與任務建模:高效提示詞設計與任務拆解方法

提示詞工程&#xff08;Prompt Engineering&#xff09;和任務建模&#xff08;Task Modeling&#xff09;已成為構建高效智能代理&#xff08;Agent&#xff09;系統的核心技術。提示詞工程通過精心設計的自然語言提示詞&#xff08;Prompts&#xff09;&#xff0c;引導大型語…

MySQL 索引的最左前綴匹配原則是什么?

MySQL 索引的最左前綴匹配原則詳解 最左前綴匹配原則&#xff08;Leftmost Prefix Principle&#xff09;是 MySQL 復合索引&#xff08;聯合索引&#xff09;查詢優化中的核心規則&#xff0c;理解這一原則對于高效使用索引至關重要。 核心概念 定義&#xff1a;當查詢條件…

SQL命令

一、控制臺中查詢命令 默認端口號&#xff1a;3306 查看服務器版本: mysql –version 啟動MySQL服務&#xff1a;net start mysql 登錄數據庫&#xff1a;mysql -u root -p 查看當前系統下的數據庫&#xff1a;show databases&#xff1b; 創建數據庫&#xff1a;create…

新增 29 個專業,科技成為關鍵賽道!

近日&#xff0c;教育部正式發布《普通高等學校本科專業目錄&#xff08;2025年&#xff09;》&#xff0c;新增 29 個本科專業&#xff0c;包括區域國別學、碳中和科學與工程、海洋科學與技術、健康與醫療保障、智能分子工程、醫療器械與裝備工程、時空信息工程、國際郵輪管理…

零基礎上手Python數據分析 (23):NumPy 數值計算基礎 - 數據分析的加速“引擎”

寫在前面 —— 超越原生 Python 列表,解鎖高性能數值計算,深入理解 Pandas 的底層依賴 在前面一系列關于 Pandas 的學習中,我們已經領略了其在數據處理和分析方面的強大威力。我們學會了使用 DataFrame 和 Series 來高效地操作表格數據。但是,你是否好奇,Pandas 為何能夠…

Android 13.0 MTK Camera2 設置默認拍照尺寸功能實現

Android 13.0 MTK Camera2 設置默認拍照尺寸功能實現 文章目錄 需求&#xff1a;參考資料架構圖了解Camera相關專欄零散知識了解部分相機源碼參考&#xff0c;學習API使用&#xff0c;梳理流程&#xff0c;偏應用層Camera2 系統相關 修改文件-修改方案修改文件&#xff1a;修改…

HarmonyOS 框架基礎知識

參考文檔&#xff1a;HarmonyOS開發者文檔 第三方庫&#xff1a;OpenHarmony三方庫中心倉 基礎特性 Entry&#xff1a;關鍵裝飾器 Components&#xff1a;組件 特性EntryComponent??作用范圍僅用于頁面入口可定義任意可復用組件??數量限制??每個頁面有且僅有一個無數量…

前端分頁與瀑布流最佳實踐筆記 - React Antd 版

前端分頁與瀑布流最佳實踐筆記 - React Antd 版 1. 分頁與瀑布流對比 分頁&#xff08;Pagination&#xff09;瀑布流&#xff08;Infinite Scroll&#xff09;展示方式按頁分批加載&#xff0c;有明確頁碼控件滾動到底部時自動加載更多內容&#xff0c;無明顯分頁用戶控制用…

Linux網絡編程:TCP多進程/多線程并發服務器詳解

Linux網絡編程&#xff1a;TCP多進程/多線程并發服務器詳解 TCP并發服務器概述 在Linux網絡編程中&#xff0c;TCP服務器主要有三種并發模型&#xff1a; 多進程模型&#xff1a;為每個客戶端連接創建新進程多線程模型&#xff1a;為每個客戶端連接創建新線程I/O多路復用&am…

詳解springcloudalibaba采用prometheus+grafana實現服務監控

文章目錄 1.官網下載安裝 prometheus和grafana1.promethus2.grafana 2. 搭建springcloudalibaba集成prometheus、grafana1. 引入依賴,springboot3.2之后引入如下2. 在yml文件配置監控端點暴露配置3. 在當前啟動的應用代碼中添加&#xff0c;在prometheus顯示的時候附加當前應用…

數據分析1

一、常用數據處理模塊Numpy Numpy常用于高性能計算&#xff0c;在機器學習常常作為傳遞數據的容器。提供了兩種基本對象&#xff1a;ndarray、ufunc。 ndarray具有矢量算術運算和復雜廣播能力的快速且節省空間的多維數組。 ufunc提供了對數組快速運算的標準數學函數。 ndar…

DeepSeek智能時空數據分析(六):大模型NL2SQL繪制城市之間連線

序言&#xff1a;時空數據分析很有用&#xff0c;但是GIS/時空數據庫技術門檻太高 時空數據分析在優化業務運營中至關重要&#xff0c;然而&#xff0c;三大挑戰仍制約其發展&#xff1a;技術門檻高&#xff0c;需融合GIS理論、SQL開發與時空數據庫等多領域知識&#xff1b;空…

2023ICPC合肥題解

文章目錄 F. Colorful Balloons(簽到)E. Matrix Distances(思維小結論)J. Takeout Delivering(最短路)G. Streak Manipulation(二分dp)C. Cyclic Substrings(回文自動機) 題目鏈接 F. Colorful Balloons(簽到) int n;cin>>n;for(int i1;i<n;i) cin>>s[i];map<…

數字技術驅動下教育生態重構:從信息化整合到數字化轉型的路徑探究

一、引言 &#xff08;一&#xff09;研究背景與問題提出 在當今時代&#xff0c;數字技術正以前所未有的速度和深度滲透到社會的各個領域&#xff0c;教育領域也不例外。從早期的教育信息化整合到如今的數字化轉型&#xff0c;教育系統正經歷著一場深刻的范式變革。 回顧教…

terraform 動態塊(Dynamic Blocks)詳解與實踐

在 Terraform 中&#xff0c;動態塊&#xff08;Dynamic Blocks&#xff09; 是一種強大的機制&#xff0c;允許你根據變量或表達式動態生成配置塊&#xff0c;避免重復編寫相似的代碼。這在處理需要重復定義的結構&#xff08;如資源參數、嵌套配置&#xff09;時特別有用。以…