当前位置: 首页 > article >正文

项目实战--网页五子棋(对战功能)(9)

上期我们完成了websocket建立连接后的数据初始化,今天我们完成落子交互的具体代码:
这里我们先复习一下,之前约定好的落子请求与响应包含的字段:

 1. 发送落子请求

 我们在script.js文件中找到落子的相关方法,增加发送请求的代码:
 

    chess.onclick = function (e) {
        if (over) {
            return;
        }
        if (!me) {
            return;
        }
        let x = e.offsetX;
        let y = e.offsetY;
        // 注意, 横坐标是列, 纵坐标是行
        let col = Math.floor(x / 30);
        let row = Math.floor(y / 30);
        if (chessBoard[row][col] == 0) {
            // TODO 发送坐标给服务器, 服务器要返回结果
            webSocket.send(JSON.stringify({
                message: 'putChess',
                userId: gameInfo.userId1,
                row: row,
                col: col
            }));
            oneStep(col, row, gameInfo.isBlack);
            chessBoard[row][col] = 1;
        }
    }

2. 处理请求发送响应

    @Override
    protected void handleTextMessage(WebSocketSession session, TextMessage message) throws Exception {
        //1. 获取用户信息
        User user = (User)session.getAttributes().get("user");
        //2. 获取请求信息
        GameRequest request = objectMapper.readValue(message.getPayload(),GameRequest.class);
        //3. 调用游戏房间中的putChess方法实现落子
        Room room = roomManager.getRoomByUserId(user.getUserId());
        room.putChess(request);
    }

实现putChess:

    private static int ROW = 15;
    private static int COL = 15;
    //棋盘, 0表示未落子,1表示玩家1的子,2表示玩家2的子
    private int[][] board = new int[ROW][COL];
    //处理落子请求
    public void putChess(GameRequest request) throws IOException {
        //1. 判断落子玩家
        int chess = request.getUserId() == user1.getUserId() ? 1 : 2;
        int row = request.getRow();
        int col = request.getCol();
        //2. 落子
        if(board[row][col] != 0) {
            System.out.println("[" + row + "," + col + "]已经有子了");
            return;
        }
        board[row][col] = chess;

        //3. 判断是否获胜
        int winnerId = checkWinner(row, col) ? request.getUserId() : -1;

        //4. 给房间中的玩家返回响应
        GameResponse response = new GameResponse();
        response.setMessage("putChess");
        response.setUserId(request.getUserId());
        response.setRow(row);
        response.setCol(col);
        response.setWinnerId(winnerId);
        //通过OnlineUserManager获取房间中的玩家
        WebSocketSession session1 = onlineUserManager.getFromRoom(user1.getUserId());
        WebSocketSession session2 = onlineUserManager.getFromRoom(user2.getUserId());
        //判断是否有玩家下线
        if(session1 == null) {
            //玩家1下线,玩家2获胜
            response.setWinnerId(user2.getUserId());
            System.out.println("玩家1掉线");
        }
        if(session1 == null) {
            //玩家2下线,玩家1获胜
            response.setWinnerId(user1.getUserId());
            System.out.println("玩家2掉线");
        }
        String resp = objectMapper.writeValueAsString(response);
        if(session1 != null) {
            session1.sendMessage(new TextMessage(resp));
        }
        if(session2 != null) {
            session2.sendMessage(new TextMessage(resp));
        }

        if(response.getWinnerId() != -1) {
            System.out.println("分出胜负, 游戏房间:" + roomId + "即将销毁");
            roomManager.remove(roomId, user1.getUserId(), user2.getUserId());
        }
    }

注意:我们并没有把Room注册为Spring组件,进行依赖注入时,需要在构造方法中手动注入:

    public Room() {
        roomId = UUID.randomUUID().toString();
        onlineUserManager = J20250110GoBangApplication.context.getBean(OnlineUserManager.class);
        objectMapper = J20250110GoBangApplication.context.getBean(ObjectMapper.class);
        roomManager = J20250110GoBangApplication.context.getBean(RoomManager.class);
    }

 实现checkWinner方法检测是否获胜:
 

    private boolean checkWinner(int row, int col) {
        int count = 1;
        //判断行是否五子连珠
        for(int i = col + 1; i < COL; i++) {
            if(board[row][i] == board[row][col]) {
                count++;
            }else{
                break;
            }
        }
        for(int i = col - 1; i >= 0; i--) {
            if(board[row][i] == board[row][col]) {
                count++;
            }else{
                break;
            }
        }
        if(count >= 5) {
            return true;
        }

        //判断列是否五子连珠
        count = 1;
        for(int i = row + 1; i < ROW; i++) {
            if(board[i][col] == board[row][col]) {
                count++;
            }else{
                break;
            }
        }
        for(int i = row - 1; i >= 0; i--) {
            if(board[i][col] == board[row][col]) {
                count++;
            }else{
                break;
            }
        }
        if(count >= 5) {
            return true;
        }

        //判断左上到右下斜线是否五子连珠
        count = 1;
        for(int i = row + 1, j = col + 1; i < ROW && j < COL; i++, j++) {
            if(board[i][j] == board[row][col]) {
                count++;
            }else{
                break;
            }
        }
        for(int i = row - 1, j = col - 1; i >= 0 && j >= 0; i--, j--) {
            if(board[i][j] == board[row][col]) {
                count++;
            }else{
                break;
            }
        }
        if(count >= 5) {
            return true;
        }

        //判断右上到左下斜线是否五子连珠
        count = 1;
        for(int i = row - 1, j = col + 1; i >= 0 && j < COL; i--, j++) {
            if(board[i][j] == board[row][col]) {
                count++;
            }else{
                break;
            }
        }
        for(int i = row + 1, j = col - 1; i < ROW && j >= 0; i++, j--) {
            if(board[i][j] == board[row][col]) {
                count++;
            }else{
                break;
            }
        }
        if(count >= 5) {
            return true;
        }

        return false;
    }

3. 处理落子响应

在之前初始化游戏的代码中,我们在游戏初始化完成时会调用initGame()方法:

于是我们可以在initGame方法末尾中修改onmessages使之变为处理落子响应的方法:

    webSocket.onmessage = function (e) {
        let resp = JSON.parse(e.data);
        console.log(resp);
        if (resp.message != 'putChess') {
            console.log("响应类型错误");
            return;
        }
        //判断是谁落子
        if (resp.userId == gameInfo.userId1) {
            //根据对应棋子颜色绘制棋子
            oneStep(resp.col, resp.row, gameInfo.isBlack);
        } else if (resp.userId == gameInfo.userId2) {
            //根据对应棋子颜色绘制棋子
            oneStep(resp.col, resp.row, !gameInfo.isBlack);
        } else {
            console.log("响应出错 userId:" + resp.userId);
            return;
        }
        // 给对应的位置设置为1,表示有子
        chessBoard[resp.row][resp.col] = 1;
        //交互落子方
        me = !me;
        setScreenText(me);

        //判断游戏是否结束
        if (resp.winnerId == gameInfo.userId1) {
            over = true;
            alert("你赢了!!!");
            location.href = "/hall.html";
        }
        if (resp.winnerId == gameInfo.userId2) {
            over = true;
            alert("你输了");
            location.href = "/hall.html";
        }
    }


http://www.kler.cn/a/577560.html

相关文章:

  • 面试基础---分布式事务深度解析:TCC、SAGA、2PC、XA 原理、实践与源码实现
  • 小程序 wxml 语法 —— 41列表渲染 - 进阶用法
  • 支持向量机的深度解析:从理论到C++实现
  • 77.ObservableCollection使用介绍1 C#例子 WPF例子
  • 虚幻基础:动画层接口
  • 最小栈 _ _
  • 【Ant Design X Vue】Vue 首个 AI 组件库发布!
  • HJ C++11 Day2
  • LeetCode - 神经网络的 反向传播(Sigmoid + MSE) 教程
  • SpringBoot过滤器(Filter)的使用:Filter接口、FilterRegistrationBean类配置、@WebFilter注释
  • 深入浅出解析 FreeRTOS 软件定时器 定时器服务任务:机制、API 详解及实践应用
  • Selenium遇到Exception自动截图
  • 刷题记录(LeetCode452 用最少数量的箭引爆气球)
  • DeepSeek×博云AIOS:突破算力桎梏,开启AI普惠新纪元
  • 【docker远程响应】
  • 解决电脑问题(8)——网络问题
  • 【竞技宝】LOL:Kanavi备战全球先锋赛苦练新打野?
  • 【音视频】RTP封包H265信息
  • VS2022安装Framework 4.0和.NET Framework 4.5
  • XMall商城listSearch存在SQL注入漏洞(DVB-2025-8924)