js井子棋

js (vue)如何实现井字琪

下载链接 添加链接描述
游戏规则我想不用我多说了,

本次dome仅仅是作者太无趣了, 写着玩的,不喜勿喷。

先给大家看看样子吧。
在这里插入图片描述

dome介绍:

这里实现了 井字棋的博弈与胜负。

可以一个人玩。 (自己是X 同时也是 O)
不过这样难免显得无趣。
我又加了个人机跟你下棋

这里面的人机比较笨, 我就不优化了。 (可不要欺负人家呀)

话不多说先上源代码。

<template>
  <div class="pages">
    <h2>井字棋</h2>
    <h2>
      <el-input v-model="Xname" placeholder="请输X的名字"></el-input> VS <el-input v-model="Oname" placeholder="请输O的名字"></el-input>
    </h2>
    <div class="body">
      <!-- 棋盘 -->
      <div class="qihe-box" :class="{gameNo: isOver}">
        <el-tooltip v-for="(item, index) in qiziArrShow" :key="index" :disabled="true" effect="dark" :content="isOver ? '请点击开始游戏' : rivalTxt" placement="top">
          <div class="item" @click="playChessClick({rival,rivalPush: rival == 1 ? 2 : 1, index})">
            <span v-if="item.v == 1" class="el-icon-close"></span>
            <span v-if="item.v == 2" class="el-icon-check"></span>
          </div>
        </el-tooltip>
      </div>
      <!-- 菜单 -->
      <div class="menus">
        <div class="t t1">
          <el-button v-if="isOver" @click="statusGame" type="warning">go game</el-button>
          <el-button v-else @click="isOver = true" type="info"> restart </el-button>
        </div>
        <div class="t">
          <el-button v-if="isOver" @click="statusGameAi" type="warning">Ai game</el-button>
          <el-button v-else @click="isOver = true" type="info"> Ai restart </el-button>
        </div>
        <div class="t t2">
          <el-switch v-model="rivalSAI" :disabled="!isOver" active-text="AI先行" inactive-text="AI后行" active-color="#ff4949" inactive-color="#13ce66">
          </el-switch>
        </div>
        <!-- <div class="t t2">
          <el-switch v-model="rival" :active-value="1" :inactive-value="2" :active-text="Xname + '下'" :inactive-text="Oname + '下'" active-color="#ff4949" inactive-color="#13ce66">
          </el-switch>
        </div> -->
        <div class="t">请棋手 <el-tag :type="rival == 1 ? 'danger' : 'success'">{{rival == 1 ? (aiName ? 'ai电脑' : '' ) + Xname : Oname}}</el-tag> 落子</div>
        <div class="t t4">游戏已进行 <span>{{gameTime}}s</span></div>
      </div>
    </div>

  </div>
</template>

<script>
var gameTimeIndex;

export default {
  components: {},
  data() {
    return {
      // 游戏双方姓名
      Xname: "X",
      Oname: "O",
      // 游戏进行时间 秒
      gameTime: 0,
      // 游戏是否结束
      isOver: true,
      // 落子方 1 X | 2 O
      rival: 2,
      // 落子方提示
      rivalTxt: "你确定下这里嘛",
      // v 0 未落子 | 1 落子x | 2 落子o
      qiziArrShow: [
        { id: 0, v: 0 },
        { id: 1, v: 0 },
        { id: 2, v: 0 },
        { id: 3, v: 0 },
        { id: 4, v: 0 },
        { id: 5, v: 0 },
        { id: 6, v: 0 },
        { id: 7, v: 0 },
        { id: 8, v: 0 },
      ],

      // ai
      // 是否启用ai
      isStatusAi: false,
      // ai的角色
      aiName: false,
      // ai 是否给ai下
      isAiPlay: true,
      // ai 先行?
      rivalSAI: true,
      // ai是否在思考中?
      aiHold: false,
    };
  },
  computed: {},
  watch: {
    rival(val) {
      if (val == 1) {
        this.rivalTxt =
          "你确定下这里嘛" + (this.aiName ? "ai电脑" : "") + this.Xname;
      } else {
        this.rivalTxt = "你确定下这里嘛" + this.Oname;
      }
    },
    isOver(val) {
      if (!val) {
        clearInterval(gameTimeIndex);
        gameTimeIndex = setInterval(() => {
          this.gameTime++;
        }, 1000);
      } else {
        clearInterval(gameTimeIndex);
      }
    },

    // 存名字
    Xname(val) {
      localStorage.setItem("Xname", val);
    },
    Oname(val) {
      localStorage.setItem("Oname", val);
    },
  },
  methods: {
    /**
     * 点击落子
     * 角色 rival
     * 下一个角色 rivalPush
     * 位置 index
     */
    playChessClick(obj) {
      if (this.aiHold && this.isStatusAi) {
        return this.$message.warning("ai落子中, 请等等它");
      }
      if (this.isOver) return;
      if (this.qiziArrShow[obj.index].v != 0)
        return this.$message.warning("不可以重复落子哦");
      // 落子ok
      this.playChess(obj);
      if (this.isStatusAi && this.isAiPlay) {
        // 是否是和ai在下 并且ai是否落子
        this.ai();
      } else {
        this.isAiPlay = true;
      }
    },
    /**
     * 落子
     *
     * 角色 rival
     * 下一个角色 rivalPush
     * 位置 index
     *
     */
    playChess(obj) {
      // 落子
      this.qiziArrShow[obj.index].v = obj.rival;
      this.victory(this.qiziArrShow);
      // 换人
      this.rival = obj.rivalPush;
    },
    /**
     *判断输赢
     *
     *
     */
    victory(arr, simulate = false) {
      // 节流
      let qiziNum = 0;
      this.qiziArrShow.forEach((el) => {
        if (el.v != 0) {
          qiziNum++;
        }
      });
      if (qiziNum < 4) return false;
      if (qiziNum == this.qiziArrShow.length && !simulate) return this.draw(); // 和
      // 计算输赢
      let boo = false;
      for (let i = 0; i < this.qiziArrShow.length - 1; i++) {
        // 横
        if (i == 0 || i == 3 || i == 6) {
          if (this.computHWX(i, i + 1, i + 2, { arr })) {
            if (simulate) {
              boo = true;
            } else {
              this.end(this.qiziArrShow[i].v);
            }
          }
        }
        // 竖
        if (i == 0 || i == 1 || i == 2) {
          if (this.computHWX(i, i + 3, i + 6, { arr }) && !simulate) {
            if (simulate) {
              boo = true;
            } else {
              this.end(this.qiziArrShow[i].v);
            }
          }
        }
        // x
        if (i == 0 || i == 2) {
          if (this.computHWX(i, 4, 8 - i, { arr }) && !simulate) {
            if (simulate) {
              boo = true;
            } else {
              this.end(this.qiziArrShow[i].v);
            }
          }
        }
      }
      return boo;
    },
    /**
     * 计算横竖X
     *
     */
    computHWX(num1, num2, num3, obj) {
      let arr = obj.arr;
      if (
        arr[num1].v != 0 &&
        arr[num2].v != 0 &&
        arr[num3].v != 0 &&
        arr[num1].v == arr[num2].v &&
        arr[num1].v == arr[num3].v &&
        arr[num2].v == arr[num3].v
      ) {
        return true;
      } else {
        return false;
      }
    },
    aiPlay(i) {
      // 关闭 ai 落子
      this.isAiPlay = false;
      // 落子
      this.aiHold = false; // ai思考end
      this.playChessClick({
        rival: this.rival,
        rivalPush: this.rival == 1 ? 2 : 1,
        index: i,
      });
    },
    /**
     * ai
     *
     */
    ai() {
      if (!this.isAiPlay || !this.isStatusAi) return;
      this.$message.warning("ai电脑思考中...");
      this.aiHold = true; // ai思考status
      setTimeout(() => {
        // 中心优先
        if (this.qiziArrShow[4].v == 0) {
          this.aiPlay(4);
          // console.log("落子ok, 固定 1.0");
          return;
        }
        // 是否能赢
        let Parr = this.qiziArrShow.filter((item) => {
          return item.v == 0;
        });
        // 模拟棋手
        let boo = false;
        let Carr = JSON.parse(JSON.stringify(this.qiziArrShow));
        for (let K = 0; K < Parr.length; K++) {
          const item = Parr[K];
          Carr[item.id].v = this.rival;
          if (this.victory(Carr, true)) {
            this.aiPlay(item.id);
            // console.log("落子ok, 固定 1.2");
            boo = true;
            break;
          }
        }
        if (boo) return;

        for (let i = 0; i < this.qiziArrShow.length; i++) {
          let el = this.qiziArrShow[i];
          if (el.v == 0) {
            this.aiPlay(i);
            // console.log("落子ok, 固定");
            break;
          }
        }
      }, 400);
    },
    /**
     * 一方获胜
     */
    end(v) {
      this.isOver = true;
      this.$alert(
        "获胜者:" +
          (v == 1 ? (this.aiName ? "ai电脑" : "") + this.Xname : this.Oname),
        "胜负以分",
        {
          confirmButtonText: "再来",
          callback: (action) => {},
        }
      );
    },
    /**
     * 和棋
     */
    draw() {
      this.isOver = true;
      this.$alert("和棋", "胜负难分", {
        confirmButtonText: "再来",
        callback: (action) => {},
      });
      return true;
    },
    /**
     * 重开
     */
    statusGame() {
      this.isStatusAi = false;
      this.isOver = false;
      this.aiName = false;
      this.rival = 2;
      this.qiziArrShow = [
        { id: 0, v: 0 },
        { id: 1, v: 0 },
        { id: 2, v: 0 },
        { id: 3, v: 0 },
        { id: 4, v: 0 },
        { id: 5, v: 0 },
        { id: 6, v: 0 },
        { id: 7, v: 0 },
        { id: 8, v: 0 },
      ];
    },
    /**
     * ai 重开
     */
    statusGameAi() {
      this.isStatusAi = true;
      this.isOver = false;
      this.isAiPlay = true;
      this.qiziArrShow = [
        { id: 0, v: 0 },
        { id: 1, v: 0 },
        { id: 2, v: 0 },
        { id: 3, v: 0 },
        { id: 4, v: 0 },
        { id: 5, v: 0 },
        { id: 6, v: 0 },
        { id: 7, v: 0 },
        { id: 8, v: 0 },
      ];

      // ai 先行?
      if (this.rivalSAI) {
        this.aiName = true;
        this.rival = 1;
      } else {
        this.aiName = true;
        this.rival = 2;
      }
      // 启动ai
      if (this.rivalSAI) {
        this.ai();
      } else {
        // 开启ai落子
        this.isAiPlay = true;
      }
    },
  },
  created() {
    this.Xname = localStorage.getItem("Xname") || "X";
    this.Oname = localStorage.getItem("Oname") || "O";
  },
  mounted() {},
};
</script>
<style lang='less' scoped>
h2 {
  .el-input {
    width: 100px;
  }
}
.body {
  margin: 100px auto;
  width: 600px;
  display: flex;
}
// 菜单
.menus {
  margin-left: 100px;
  .t {
    margin: 20px 0;
  }
  .t4 {
    span {
      font-size: 1.1em;
      color: #42b3e3;
    }
  }
}

// 棋盘
.qihe-box {
  padding-top: 5px;
  width: 315px;
  height: 315px;
  border: solid #8896ee 1px;
  border-radius: 5px;
  background-color: #909399;
  display: flex;
  justify-content: space-around;
  flex-wrap: wrap;

  .item {
    cursor: pointer;
    width: 100px;
    height: 100px;
    background: #606266;
    span {
      font-size: 60px;
      line-height: 100px;
    }
    .el-icon-close {
      color: #f56c6c;
    }
    .el-icon-check {
      color: #67c23a;
    }
  }
  .item:hover {
    box-shadow: 0px 0px 9px rgba(64, 158, 255, 0.8);
  }
}
.gameNo {
  opacity: 0.3;
}
</style>

结尾:

1、这是vue项目, 里面使用了element的ui
element的ui

2、如何跑项目呢? 搭建一个vue环境 这个dome就是个页面。 记得引入element 的 ui

3、欢迎大家一起学习交流

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

厚渡

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值