react实现狼吃羊游戏

基础规则

https://blog.csdn.net/zslngu/article/details/115743943

效果

录屏2026-03-14 21.36.50-狼吃羊-reac

代码

ts 复制代码
import { Role } from "@/base/MyEnums.ts"
import WolfGoatRole from "@/components/WolfGoatRole.tsx"
import { useState } from "react"

export default function WolfGoatPage() {
  const row = 5
  const col = 5

  const [matrix, setMatrix] = useState([
    ["0", Role.WOLF, Role.WOLF, Role.WOLF, "0"],
    ["0", "0", "0", "0", "0"],
    [Role.GOAT, Role.GOAT, Role.GOAT, Role.GOAT, Role.GOAT],
    [Role.GOAT, Role.GOAT, Role.GOAT, Role.GOAT, Role.GOAT],
    [Role.GOAT, Role.GOAT, Role.GOAT, Role.GOAT, Role.GOAT],
  ])

  const eq = (a, b) => {
    return a[0] == b[0] && a[1] == b[1]
  }

  const hasPieceSelect = () => {
    return !eq(currClick, [-1, -1])
  }

  enum Status {
    WAIT_SELECT_PIECE,
    HAS_SELECT_PIECE,
  }

  const calStatus = () => {
    if (hasPieceSelect()) {
      return Status.HAS_SELECT_PIECE
    } else {
      return Status.WAIT_SELECT_PIECE
    }
  }

  // 选中的棋子
  const [currClick, setCurrClick] = useState([-1, -1])

  const fetchRole = ([a, b]: number[]) : Role | string => {
    return matrix[a][b]
  }

  const bgColor = (i, j) => {
    if (fetchRole([i, j]) == Role.WOLF) {
      return "bg-red-300"
    } else if (fetchRole([i, j]) == Role.GOAT) {
      return "bg-green-300"
    }
  }

  interface HistoryVO {
    targetPos: number[]
    role: Role | string,
    currentPos: number[]
    msg: string
  }

  const [history, setHistory] = useState<Array<HistoryVO>>([])

  const canNormalStep = ([i, j]: number[], [a, b]: number[]) => {
    const res =
      Math.abs(i - a) + Math.abs(j - b) == 1 && fetchRole([a, b]) == "0"
    console.log(`judge can normal return ${res} ${[i, j]} ${[a, b]} ${fetchRole([a, b])}`)
    return res
  }

  const copyMatrix = (param: Array<Array<number | Role | string>>) => {
    return matrix.map((arr, i) => {
      return arr.map((value, j) => {
        let idx = 0
        for (idx = 0; idx < param.length; idx++) {
          const p = param[idx]
          if (eq([i, j], [p[0], p[1]])) {
            return p[2].toString()
          }
        }
        return value
      })
    })
  }

  const canEat = ([i, j]: number[], [a, b]: number[]) => {
    const roleCan =
      fetchRole([i, j]) == Role.WOLF && fetchRole([a, b]) == Role.GOAT
    const postCan =
      (i == a && Math.abs(j - b) == 2) || (Math.abs(i - a) == 2 && j == b)
    return roleCan && postCan
  }

  //
  // 状态: 待选棋子  选棋子操作
  // 状体;已选棋子
  //       选一样的 取消选中
  //       走棋 同时判断规则
  const onClickCell = (i, j, e) => {
    // 待选棋子
    const status = calStatus()

    if (status == Status.WAIT_SELECT_PIECE) {
      if (fetchRole([i, j]) == '0') {
        return
      }
      setCurrClick([i, j])
      return
    }

    // 已选了棋子
    // 取消
    // 重选
    // 走路
    // 吃子
    else if (status == Status.HAS_SELECT_PIECE) {
      if (eq(currClick, [i, j])) {
        setCurrClick([-1, -1])
        return
      } else if (fetchRole(currClick) == fetchRole([i, j])) {
        setCurrClick([i, j])
        return
      }
      else if (canNormalStep(currClick, [i, j])) {
        setHistory([{
          targetPos: [i, j],
          currentPos: currClick,
          role: fetchRole(currClick),
          msg: `${fetchRole(currClick)} 从 (${currClick[0]}, ${currClick[1]}) 移动到 (${i}, ${j})`
        }, ...history])
        const a = Array<Array<number | Role | string>>([])
        a.push([i, j, fetchRole(currClick)])
        a.push([currClick[0], currClick[1], "0"])
        setMatrix(copyMatrix(a))
        setCurrClick([-1, -1])
        return
      } else if (canEat(currClick, [i, j])) {
        setHistory([
          {
            targetPos: [i, j],
            currentPos: currClick,
            role: fetchRole(currClick),
            msg: `${fetchRole(currClick)} 从 (${currClick[0]}, ${currClick[1]}) 吃掉了 (${i}, ${j}) 的 ${fetchRole([i, j])}`,
          },
          ...history,
        ])
        const a = Array<Array<number | Role | string>>([])
        a.push([i, j, fetchRole(currClick)])
        a.push([currClick[0], currClick[1], "0"])
        setMatrix(copyMatrix(a))
        setCurrClick([-1, -1])
      }
    }
  }

  return (
    <div className="flex-col items-center" style={{ paddingTop: "40px" }}>
      <div>当前选中棋子 {currClick}</div>
      <div>
        {
          history
            .map((value, idx, arr) => {
              if (idx < 3) {
                return (<p>
                  第{arr.length - idx}手 {value.msg}
                </p>)
              } else {
                return (<></>)
              }
            })
        }
      </div>
      <table className="w-full table-auto border-collapse">
        <tbody>
          {Array.from({ length: row }, (_, i) => (
            <tr key={i}>
              {Array.from({ length: col }, (_, j) => (
                <td
                  key={j}
                  className={
                    "border px-10 py-15" +
                    (i == currClick[0] && j == currClick[1]
                      ? " " + bgColor(i, j)
                      : "")
                  }
                  onClick={(e) => onClickCell(i, j, onClickCell)}
                >
                  {matrix[i][j] === Role.WOLF ? (
                    <WolfGoatRole role={Role.WOLF} />
                  ) : (
                    <></>
                  )}

                  {matrix[i][j] === Role.GOAT ? (
                    <WolfGoatRole role={Role.GOAT} />
                  ) : (
                    <></>
                  )}
                </td>
              ))}
            </tr>
          ))}
        </tbody>
      </table>
    </div>
  )
}
相关推荐
星空露珠2 小时前
迷你世界UGC3.0脚本Wiki全局函数
开发语言·数据库·算法·游戏·lua
风酥糖2 小时前
Godot游戏练习01-第11节-显示优化,游戏背景,Shader
游戏·游戏引擎·godot
小金鱼Y2 小时前
别再乱拷贝了!JS 浅拷贝 vs 深拷贝全解析
前端·javascript
英俊潇洒美少年3 小时前
React19 useActionState的注意事项
前端·javascript·react.js
发现一只大呆瓜3 小时前
性能优化:CDN 缓存加速与调度原理
前端·javascript·面试
林鸿群3 小时前
游戏客户端创建大联盟报错:[LUA-print] onSubOperateFailure 1 由于数据库操作异常,请稍后重试!解决
游戏·lua·cocos2d-x·链接服务器
Lsx-codeShare3 小时前
前端发版后页面白屏?一套解决用户停留旧页面问题的完整方案
前端·javascript·前端框架·vue·vite
心柠4 小时前
TypeScript的知识梳理
前端·javascript·typescript
IT从业者张某某4 小时前
基于EGE19.01完成恐龙跳跃游戏-V02-面向对象或结构体的版本
游戏