React 实现五子棋

news2024/11/24 15:20:38

简介

         本文将会基于React 实现五子棋小游戏,游戏规则为先让5颗棋子连成1线的一方获胜。

实现效果

技术实现

页面布局

<div>
    <table style={{border: '1px solid #000', borderCollapse: 'collapse', backgroundColor: 'lightgray'}}>
      <tbody>
      {
        squares.map((row, rowIndex) => {
          return <tr key={rowIndex}>
            {
              row.map((col, colIndex) => {
                return <td key={colIndex}
                           style={{border: '1px solid #000', width: '30px', height: '30px'}}

                           onClick={(event) => {
                             const clickedElement = event.target as HTMLTableCellElement;

                             const rect = clickedElement.getBoundingClientRect();
                             const x = event.clientX - rect.left;
                             const y = event.clientY - rect.top;
                             const width = clickedElement.getBoundingClientRect().width;
                             const height = clickedElement.getBoundingClientRect().height;

                             const left = x / width;
                             const top = y / height;
                             if (left < 0.5 && top < 0.5){ // 左上
                               if (rowIndex > 0){
                                 rowIndex--;
                               }
                               if (colIndex > 0){
                                 colIndex--;
                               }
                             }
                             if (left < 0.5 && top > 0.5){ // 左下

                               if (colIndex > 0){
                                 colIndex--;
                               }
                             }
                             if (left > 0.5 && top < 0.5){ // 右上
                               if (rowIndex > 0){
                                 rowIndex--;
                               }

                             }

                             let item = squares[rowIndex][colIndex];
                             if (item !== '') {
                               return;
                             }
                             if (times % 2 === 0) {
                               item = 'black';
                             } else {
                               item = 'white';
                             }
                             const newSquares = [...squares];
                             newSquares[rowIndex][colIndex] = item;

                             setTimes(times + 1);
                             setSquares(newSquares);
                           }
                           }
                >
                  {col === 'white' ?
                    <div
                      style={{
                        width: '100%',
                        height: '100%',
                        backgroundColor: 'white',
                        borderRadius: '50%',
                        position: "relative",
                        right: "-50%",
                        bottom: "-50%"
                      }}></div>
                    : (col === 'black' ?
                      <div
                        style={{
                          width: '100%',
                          height: '100%',
                          backgroundColor: 'black',
                          borderRadius: '50%',
                          position: "relative",
                          right: "-50%",
                          bottom: "-50%"
                        }}></div> : col)}
                </td>
              })
            }
          </tr>
        })
      }
      </tbody>
    </table>

  </div>

        本文用table实现游戏布局,棋盘大小为15 * 15,背景色为浅灰,棋子为白色或黑色。

        由于棋子是位于交叉点上,需要将table cell 定位到右下角, right - 50%, bottom -50%,

下棋逻辑

onClick={(event) => {
 const clickedElement = event.target as HTMLTableCellElement;

 const rect = clickedElement.getBoundingClientRect();
 const x = event.clientX - rect.left;
 const y = event.clientY - rect.top;
 const width = clickedElement.getBoundingClientRect().width;
 const height = clickedElement.getBoundingClientRect().height;

 const left = x / width;
 const top = y / height;
 if (left < 0.5 && top < 0.5) { // 左上
   if (rowIndex > 0) {
     rowIndex--;
   }
   if (colIndex > 0) {
     colIndex--;
   }
 }
 if (left < 0.5 && top > 0.5) { // 左下

   if (colIndex > 0) {
     colIndex--;
   }
 }
 if (left > 0.5 && top < 0.5) { // 右上
   if (rowIndex > 0) {
     rowIndex--;
   }

 }

 let item = squares[rowIndex][colIndex];
 if (item !== '') {
   return;
 }
 if (times % 2 === 0) {
   item = 'black';
 } else {
   item = 'white';
 }
 const newSquares = [...squares];
 newSquares[rowIndex][colIndex] = item;

 setTimes(times + 1);
 setSquares(newSquares);
}
}

        基于times控制是白方还是黑方,然后更新squares状态,棋盘会根据squares状态进行显示。

        对于每个交叉点,棋子是以交叉点为右下角的table cell。

        计算点击位置位于table cell的哪个区域,然后计算交叉点对应的table cell。

        左上 -> r-- c--

        右上 -> r-- c

        左下 -> r c--

        右下 -> r ,c

获胜逻辑判断

    useEffect(()=>{

        // 计算dp的值
        for (let i = 0; i < 15; i++) {
            for (let j = 0; j < 15; j++) {
                if (squares[i][j] === '') {
                    continue;
                }
                // 判断左边
                if (j >= 5){
                    let num = 1;
                    for (let k = 1; k < 5; k++) {
                        if (squares[i][j - k] === squares[i][j]) {
                            num++;
                        } else {
                            break;
                        }
                    }
                    if (num >= 5) {
                        alert(squares[i][j] +'win');
                        setSquares(initSquares)
                        setTimes(0);
                        return;
                    }
                }
                // 判断上边
                if (i >= 5){
                    let num = 1;
                    for (let k = 1; k < 5; k++) {
                        if (squares[i - k][j] === squares[i][j]) {
                            num++;
                        } else {
                            break;
                        }
                    }
                    if (num >= 5) {
                        alert(squares[i][j] +'win');
                        setSquares(initSquares)
                        setTimes(0);
                        return;
                    }
                }
                // 判断右边
                if (j <= 10){
                    let num = 1;
                    for (let k = 1; k < 5; k++) {
                        if (squares[i][j + k] === squares[i][j]) {
                            num++;
                        } else {
                            break;
                        }
                    }
                    if (num >= 5) {
                        alert(squares[i][j] +'win');
                        setSquares(initSquares)
                        setTimes(0);
                        return;
                    }
                }
                // 判断下边
                if (i <= 10){
                    let num = 1;
                    for (let k = 1; k < 5; k++){
                        if (squares[i + k][j] === squares[i][j]) {
                            num++;
                        } else {
                            break;
                        }
                    }
                    console.log(i + ',' + j + ':'+ num)
                    if (num >= 5) {
                        alert(squares[i][j] +'win');
                        setSquares(initSquares)
                        setTimes(0);
                        return;
                    }
                }
                // 判断左上
                if (i >= 5 && j >= 5){
                    let num = 1;
                    for (let k = 1; k < 5; k++) {
                        if (squares[i - k][j - k] === squares[i][j]) {
                            num++;
                        } else {
                            break;
                        }
                    }
                    if (num >= 5) {
                        alert(squares[i][j] +'win');
                        setSquares(initSquares)
                        setTimes(0);
                        return;
                    }
                }
                // 判断右上
                if (i <= 10 && j >= 5){
                    let num = 1;
                    for (let k = 1; k < 5; k++) {
                        if (squares[i + k][j - k] === squares[i][j]) {
                            num++;
                        } else {
                            break;
                        }
                    }
                    if (num >= 5) {
                        alert(squares[i][j] +'win');
                        setSquares(initSquares)
                        setTimes(0);
                        return;
                    }
                }
                // 判断左下
                if (i >= 5 && j <= 10){
                    let num = 1;
                    for (let k = 1; k < 5; k++) {
                        if (squares[i - k][j + k] === squares[i][j]) {
                            num++;
                        } else {
                            break;
                        }
                    }
                    if (num >= 5) {
                        alert(squares[i][j] +'win');
                        setSquares(initSquares)
                        setTimes(0);
                        return;
                    }
                }
                // 判断右下
                if (i <= 10 && j <= 10){
                    let num = 1;
                    for (let k = 1; k < 5; k++){
                        if (squares[i + k][j + k] === squares[i][j]) {
                            num++;
                        } else {
                            break;
                        }
                    }
                    if (num >= 5) {
                        alert(squares[i][j] +'win');
                        setSquares(initSquares)
                        setTimes(0);
                        return;
                    }
                }
            }
        }

    }, [squares])

         判断每个棋子上下左右,左上,右上,左下,右下是否有连续5个棋子。

整体代码

const Board = () => {
  /**
   * 创建一个 15 * 15  的棋盘
   */
  const initSquares = Array.from({length: 15},
    () => new Array(15).fill(''));
  const [squares, setSquares] = useState(initSquares);
  const [times, setTimes] = useState(0);
  useEffect(() => {

    // 计算dp的值
    for (let i = 0; i < 15; i++) {
      for (let j = 0; j < 15; j++) {
        if (squares[i][j] === '') {
          continue;
        }
        // 判断左边
        if (j >= 5) {
          let num = 1;
          for (let k = 1; k < 5; k++) {
            if (squares[i][j - k] === squares[i][j]) {
              num++;
            } else {
              break;
            }
          }
          if (num >= 5) {
            alert(squares[i][j] + '----' + 'win');
            setSquares(initSquares)
            setTimes(0);
            return;
          }
        }
        // 判断上边
        if (i >= 5) {
          let num = 1;
          for (let k = 1; k < 5; k++) {
            if (squares[i - k][j] === squares[i][j]) {
              num++;
            } else {
              break;
            }
          }
          if (num >= 5) {
            alert(squares[i][j] + '----' + 'win');
            setSquares(initSquares)
            setTimes(0);
            return;
          }
        }
        // 判断右边
        if (j <= 10) {
          let num = 1;
          for (let k = 1; k < 5; k++) {
            if (squares[i][j + k] === squares[i][j]) {
              num++;
            } else {
              break;
            }
          }
          if (num >= 5) {
            alert(squares[i][j] + '----' + 'win');
            setSquares(initSquares)
            setTimes(0);
            return;
          }
        }
        // 判断下边
        if (i <= 10) {
          let num = 1;
          for (let k = 1; k < 5; k++) {
            if (squares[i + k][j] === squares[i][j]) {
              num++;
            } else {
              break;
            }
          }
          if (num >= 5) {
            alert(squares[i][j] + '----' + 'win');
            setSquares(initSquares)
            setTimes(0);
            return;
          }
        }
        // 判断左上
        if (i >= 5 && j >= 5) {
          let num = 1;
          for (let k = 1; k < 5; k++) {
            if (squares[i - k][j - k] === squares[i][j]) {
              num++;
            } else {
              break;
            }
          }
          if (num >= 5) {
            alert(squares[i][j] + '----' + 'win');
            setSquares(initSquares)
            setTimes(0);
            return;
          }
        }
        // 判断右上
        if (i <= 10 && j >= 5) {
          let num = 1;
          for (let k = 1; k < 5; k++) {
            if (squares[i + k][j - k] === squares[i][j]) {
              num++;
            } else {
              break;
            }
          }
          if (num >= 5) {
            alert(squares[i][j] + '----' + 'win');
            setSquares(initSquares)
            setTimes(0);
            return;
          }
        }
        // 判断左下
        if (i >= 5 && j <= 10) {
          let num = 1;
          for (let k = 1; k < 5; k++) {
            if (squares[i - k][j + k] === squares[i][j]) {
              num++;
            } else {
              break;
            }
          }
          if (num >= 5) {
            alert(squares[i][j] + '----' + 'win');
            setSquares(initSquares)
            setTimes(0);
            return;
          }
        }
        // 判断右下
        if (i <= 10 && j <= 10) {
          let num = 1;
          for (let k = 1; k < 5; k++) {
            if (squares[i + k][j + k] === squares[i][j]) {
              num++;
            } else {
              break;
            }
          }
          if (num >= 5) {
            alert(squares[i][j] + '----' + 'win');
            setSquares(initSquares)
            setTimes(0);
            return;
          }
        }
      }
    }

  }, [squares])

  return <div>
    <table style={{border: '1px solid #000', borderCollapse: 'collapse', backgroundColor: 'lightgray'}}>
      <tbody>
      {
        squares.map((row, rowIndex) => {
          return <tr key={rowIndex}>
            {
              row.map((col, colIndex) => {
                return <td key={colIndex}
                           style={{border: '1px solid #000', width: '30px', height: '30px'}}

                           onClick={(event) => {
                             const clickedElement = event.target as HTMLTableCellElement;

                             const rect = clickedElement.getBoundingClientRect();
                             const x = event.clientX - rect.left;
                             const y = event.clientY - rect.top;
                             const width = clickedElement.getBoundingClientRect().width;
                             const height = clickedElement.getBoundingClientRect().height;

                             const left = x / width;
                             const top = y / height;
                             if (left < 0.5 && top < 0.5) { // 左上
                               if (rowIndex > 0) {
                                 rowIndex--;
                               }
                               if (colIndex > 0) {
                                 colIndex--;
                               }
                             }
                             if (left < 0.5 && top > 0.5) { // 左下

                               if (colIndex > 0) {
                                 colIndex--;
                               }
                             }
                             if (left > 0.5 && top < 0.5) { // 右上
                               if (rowIndex > 0) {
                                 rowIndex--;
                               }

                             }

                             let item = squares[rowIndex][colIndex];
                             if (item !== '') {
                               return;
                             }
                             if (times % 2 === 0) {
                               item = 'black';
                             } else {
                               item = 'white';
                             }
                             const newSquares = [...squares];
                             newSquares[rowIndex][colIndex] = item;

                             setTimes(times + 1);
                             setSquares(newSquares);
                           }
                           }
                >
                  {col === 'white' ?
                    <div
                      style={{
                        width: '100%',
                        height: '100%',
                        backgroundColor: 'white',
                        borderRadius: '50%',
                        position: "relative",
                        right: "-50%",
                        bottom: "-50%"
                      }}></div>
                    : (col === 'black' ?
                      <div
                        style={{
                          width: '100%',
                          height: '100%',
                          backgroundColor: 'black',
                          borderRadius: '50%',
                          position: "relative",
                          right: "-50%",
                          bottom: "-50%"
                        }}></div> : col)}
                </td>
              })
            }
          </tr>
        })
      }
      </tbody>
    </table>

  </div>
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1930679.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

在 Windows 上运行 Linux:WSL2 完整指南(一)

系列文章目录 在 Windows 上运行 Linux&#xff1a;WSL2 完整指南&#xff08;一&#xff09;&#x1f6aa; 在 Windows 上运行 Linux&#xff1a;WSL2 完整指南&#xff08;二&#xff09; 文章目录 系列文章目录前言一、什么是 WSL&#xff1f;1.1 WSL 的主要特性1.2 WSL 的…

STM32智能工业自动化监控系统教程

目录 引言环境准备智能工业自动化监控系统基础代码实现&#xff1a;实现智能工业自动化监控系统 4.1 数据采集模块 4.2 数据处理与控制模块 4.3 通信与网络系统实现 4.4 用户界面与数据可视化应用场景&#xff1a;工业自动化与管理问题解决方案与优化收尾与总结 1. 引言 智能…

【unity笔记】十、Obi绳索插件使用

一. 创建绳索 1.1 新建蓝图 在Assets中右键选择创建->Obi->Rope Blueprint&#xff0c;其属性如图所示 1.2 Obi solver 在场景下创建一个obi solver对象&#xff0c;在该对象下再创建Obi Rope对象。 随后将蓝图拖到Obi Rope对象下的Obi Rope组件&#xff0c;即可看到…

【Web服务与Web应用开发】【C#】VS2019 创建ASP.NET Web应用程序,以使用WCF服务

目录 0.简介 1.环境 2.知识点 3.详细过程 1&#xff09;创建空项目 2&#xff09;添加Web表单 3&#xff09;使用Web表单的GUI设计 4&#xff09;添加服务引用 5&#xff09;在Web的button函数中调用服务&#xff0c;获取PI值 6&#xff09;测试 0.简介 本文属于一个…

环境配置|PyCharm——Pycharm本地项目打包上传到Github仓库的操作步骤

一、Pycharm端的设置操作 通过Ctrl+Alt+S快捷组合键的方式,打开设置,导航到版本控制一栏中的Git,在Git可执行文件路径中,输入Git.exe。 按照下图顺序,依次点击,完成测试。输出如图标④的结果,即可完成测试。 输出下图结果,配置Git成功,如本地未安装Git,需自行安装。

设计模式9-工厂模式(Factory Method)

[TOC](工厂模式(Factory Method)) 写在前面 对象创建模式 通过对象超级模式绕开。动态内存分配&#xff08;new)&#xff0c;来避免对象创建过程中所导致的紧耦合(依赖具体类)&#xff0c;从而支持对象创建的稳定&#xff0c;它是结构抽象之后的第一步工作。 典型模式&…

新版本安卓更换下载源解决gradle时间太久问题

老版本android studio 解决方法如下 : android studio gradle:build model执行时间太久 最近又做到安卓的任务了,下载的安卓studio最新版 这个版本的android studio 不能用上面那种老版本的方法了,需要更新方法 新版本需要跟换两个地方 gradle/wrapper/gradle-wrapper.proper…

JAVA 异步编程(异步,线程,线程池)一

目录 1.概念 1.1 线程和进程的区别 1.2 线程的五种状态 1.3 单线程,多线程,线程池 1.4 异步与多线程的概念 2. 实现异步的方式 2.1 方式1 裸线程&#xff08;Thread&#xff09; 2.1 方式2 线程池&#xff08;Executor&#xff09; 2.1.1 源码分析 2.1.2 线程池创建…

三丰云评测:免费虚拟主机与免费云服务器体验

今天我来为大家分享一下我对三丰云的评测。作为一家知名的云服务提供商&#xff0c;三丰云一直以来备受用户好评。他们提供免费虚拟主机和免费云服务器服务&#xff0c;深受网站建设者和开发者的喜爱。 首先谈谈免费虚拟主机服务。三丰云的免费虚拟主机方案性价比非常高&#x…

代码随想录算法训练营第33天|LeetCode 509. 斐波那契数、70. 爬楼梯、746. 使用最小花费爬楼梯

1. LeetCode 509. 斐波那契数 题目链接&#xff1a;https://leetcode.cn/problems/fibonacci-number/ 文章链接&#xff1a;https://programmercarl.com/0509.斐波那契数.html 视频链接&#xff1a;https://www.bilibili.com/video/BV1f5411K7mo 思路&#xff1a; 动态规划步骤…

django-ckeditor富文本编辑器

一.安装django-ckeditor 1.安装 pip install django-ckeditor2.注册应用 INSTALLED_APPS [...ckeditor&#xff0c; ]3.配置model from ckeditor.fields import RichTextFieldcontent RichTextField()4.在项目中manage.py文件下重新执行迁移&#xff0c;生成迁移文件 py…

jvm优化

1.jvm组成 什么是jvm&#xff0c;java是跨平台语言&#xff0c;对不同的平台&#xff08;windos&#xff0c;linux&#xff09;&#xff0c;有不同的jvm版本。jvm屏蔽了平台的不同&#xff0c;提供了统一的运行环境&#xff0c;让java代码无需考虑平台的差异。 jdk包含jre包含…

ValueError和KeyError: ‘bluegrass’的问题解决

项目场景&#xff1a; 项目相关背景&#xff1a; 问题描述 遇到的问题1&#xff1a; KeyError: ‘bluegrass’ 不能识别某标签 遇到的问题2&#xff1a; xml etree.fromstring(xml_str) ValueError: Unicode strings with encoding declaration are not supported. Please …

K8S POD控制器:从基础到高级实战技巧

一、引言 在当今的云计算时代&#xff0c;Kubernetes&#xff08;K8s&#xff09;已成为最受欢迎的容器编排工具&#xff0c;它的核心组成部分之一——K8s POD控制器&#xff0c;扮演着至关重要的角色。这篇文章旨在深入探讨K8s POD控制器的内部工作原理、不同类型及其应用场景…

【数据结构】树和二叉树及堆的深入理解

【数据结构】树和二叉树及堆的深入理解 &#x1f525;个人主页&#xff1a;大白的编程日记 &#x1f525;专栏&#xff1a;数据结构 文章目录 【数据结构】树和二叉树及堆的深入理解前言一.树1.1 树的概念1.2 树的相关概念1.3 树的表示1.4 树的应用 二.二叉树2.1 二叉树概念及…

clion中建立c文件工程,读取或创建sqlite3数据库文件

1.首先前往SQLite官网下载sqlite3所需文件 SQLite Download Page 2.解压文件&#xff0c;将其中的sqlite3.c和sqlite3.h拷贝到你对应的文件工程中 3.修改CMakeLists.txt文件&#xff0c;添加编译选项及连接文件 4.运行代码及查询数据库文件

实战:SpringBoot 15个功能强大Bean

下面这15个bean&#xff0c;可以很方便的帮我们获取当前环境信息&#xff0c;运行信息&#xff0c;参数信息等等 1. 应用程序参数Environment和ApplicationArguments SpringBoot程序在启动时&#xff0c;可以通过如下方式设置启动参数&#xff1a; java -jar app.jar --pack…

单链表算法 - 链表分割

链表分割_牛客题霸_牛客网现有一链表的头指针 ListNode* pHead&#xff0c;给一定值x&#xff0c;编写一段代码将所有小于x的。题目来自【牛客题霸】https://www.nowcoder.com/practice/0e27e0b064de4eacac178676ef9c9d70思路: 代码: /* struct ListNode {int val;struct List…

iterator(迭代器模式)

引入 在想显示数组当中所有元素时&#xff0c;我们往往会使用下面的for循环语句来遍历数组 #include <iostream> #include <vector>int main() {std::vector<int> v({ 1, 2, 3 });for (int i 0; i < v.size(); i){std::cout << v[i] << &q…

正则表达式(Ⅲ)——分组匹配

简介 为了给表达式分组&#xff0c;我们需要将文本包裹在 () 中 有点类似于匹配子串&#xff0c;只不过是找出所有的子串&#xff0c;并且拼成一组 分组之间需要有分割符&#xff0c;,或者-或者_都可以 直接分组 引用分组 这个比较难以理解 \1和\2的作用有两个&#xff1a…