基于VUE实现的的数独界面

最近用css+vue实现了这样一款数独界面,可以说除了侯选数其他的功能还算完善。

实现效果

前端代码

一共三个文件

index.html

<!doctype html>
<html>

<head>
  <title>数独</title>
  <meta charset="utf-8" />
  <link rel="stylesheet" href="index.css">
  <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
  <script src="https://unpkg.com/axios/dist/axios.min.js"></script>
</head>

<body>
  <div id="app">
    <div class="container cf" @keydown="move($event)">
      <div v-for="Row,index in allnums" class="row">
        <div tabindex="-1" v-for="num1,indexSub in Row" :class="{
          'Hlight':index==nowPos.x||indexSub==nowPos.y||getBlock(index,indexSub)==nowBlock,
          'no':num1==0&&index==nowPos.x&&indexSub==nowPos.y,
          'num':num1!=0&&index==nowPos.x&&indexSub==nowPos.y,
          'newnums':oldnums[index][indexSub]==0,
          'other-num':num1==nowClickNum,
          'error':num1==nowNum&&(index == optionPos.x||indexSub == optionPos.y||getBlock(index,indexSub)==nowClickBlock)&&(index != optionPos.x||indexSub != optionPos.y),
          'err':num1 != answer[index][indexSub]&&num1!=0
        }" @keydown="fillnum($event,index,indexSub)" @click="hitNum(index,indexSub)">
          {{num1==0?'':num1}}
        </div>
      </div>
    </div>
    <div class="container newcontainer">
      <div v-for="index in 9" class="block"></div>
    </div>
    <div class="header">
      <button @click="getSodoku">换一题</button>
      <button @click="getAnswer">获取答案</button>
    </div>

  </div>
  <script src="index.js"></script>
</body>

</html>

index.js

new Vue({
  el: '#app',
  data: {
    oldnums: [], //保存初始题目
    allnums: [],
    answer: [],
    nowPos: {}, //当前鼠标移入位置
    optionPos: {}, //当前填入数字的位置
    nowClickBlock: -1, //当前鼠标点击宫
    nowBlock: -1, //当前鼠标移入宫
    nowNum: 0, //当前填入的数值
    gameover: false, //游戏是否结束
    nowClickNum: -1,
    clickPos: {
      x: 0,
      y: 0
    }, //鼠标点击位置
  },
  created() {
    this.getSodoku();
  },
  methods: {
    reset() {
      this.nowNum = -1;
    },
    getSodoku() {
      axios.get('http://localhost:8888/getsodoku')
        .then((res) => {
          this.allnums = res.data;
          this.answer = JSON.parse(JSON.stringify(this.allnums));
          this.oldnums = JSON.parse(JSON.stringify(this.allnums));
          var parm = {
            sodoku: JSON.stringify(this.allnums),
          };
          axios.post('http://localhost:8888/getanswer', parm)
            .then((res) => {
              this.answer = res.data;
              this.reset();
            });
        });
    },
    getAnswer() {
      this.allnums = JSON.parse(JSON.stringify(this.answer));
      this.reset();
    },
    move(e) {
      var num = e.key;
      if (num == "ArrowUp") {
        this.clickPos.x = (this.clickPos.x + 8) % 9;
      }
      if (num == "ArrowDown") {
        this.clickPos.x = (this.clickPos.x + 1) % 9;
      }
      if (num == "ArrowLeft") {
        this.clickPos.y = (this.clickPos.y + 8) % 9;
      }
      if (num == "ArrowRight") {
        this.clickPos.y = (this.clickPos.y + 1) % 9;
      }
      this.hitNum(this.clickPos.x, this.clickPos.y);
    },
    hitNum(x, y) {
      this.showHlight(x, y);
      this.optionPos={
        x:x,
        y:y
      };
      this.nowClickBlock = this.getBlock(x,y);
      this.nowNum = this.allnums[x][y]==0?-1:this.allnums[x][y];
      this.clickPos = {
        x: x,
        y: y
      };
      var obj = document.getElementsByClassName("container")[0].children[x].children[y];
      obj.focus();
    },
    showHlight(x, y) {
      var num = this.allnums[x][y];
      if (num == 0) this.nowClickNum = -1;
      else this.nowClickNum = num;
      this.nowPos = {
        x: x,
        y: y,
      }
      this.nowBlock = this.getBlock(x, y);
    },
    getBlock(x, y) {
      x = parseInt(x / 3);
      y = parseInt(y / 3);
      return x * 3 + y;
    },
    checkWin() {
      var count = [0, 0, 0, 0, 0, 0, 0, 0, 0];
      for (var i = 0; i < 9; i++) {
        for (var j = 0; j < 9; j++) {
          count[this.allnums[i][j] - 1]++;
        }
      }
      for (var i = 0; i < 9; i++) {
        if (count[i] != 9) return false;
      }
      return true;
    },
    fillnum(e, x, y) {
      var num = e.key;
      if (num == 0) {
        this.$set(this.allnums[x], y, num);
        this.nowClickNum = -1;
        this.nowNum = -1;
      }
      if (num >= 1 && num <= 9 && this.oldnums[x][y] == 0) {
        this.optionPos = {
          x: x,
          y: y,
        }
        this.nowClickBlock = this.getBlock(x, y);
        this.$set(this.allnums[x], y, num);
        this.nowNum = num;
        this.nowClickNum = num;

        
        this.gameover = true;
        for (var i = 0; i < 9; i++) {
          for (var j = 0; j < 9; j++) {
            if (this.allnums[i][j] == 0) this.gameover = false;
          }
        }
  
        if (this.gameover && this.checkWin()) alert("你赢了");
      }

    }
  },
});

index.css

*{
  margin:0;
  padding:0;
}

.header{
  width:450px;
  height: 50px;
  position: absolute;
  left: 50%;
  transform: translate(-50%);
}
.header button{
  background-color: #4CAF50;
  border: none;
  color: white;
  border-radius: 2%;
  width: 121px;
  height: 25px;
  margin-left: 50px;
  margin-right: 50px;
  text-align: center;
  margin-top: 29px;
}
.container{
  width: 450px;
  height: 450px;
  position: absolute;
  left: 50%;
  top: 50%;
  transform: translate(-50%,-50%);
  background-color: rebeccapurple;
}
.row{
  width: 100%;
  height: 50px;
  background-color: #bababa;
  float: left;
  display: flex;
  flex-direction: row;
}
.row div{
  width: 49px;
  height: 49px;
  margin: 0.5px;
  text-align: center;
  line-height: 49px;
  color:  rgb(93,94,112);
  font-size: 28px;
  background-color: rgb(255,255,255);
  pointer-events: auto;
}
.block{
  width: 148px;
  height: 148px;
  border: 1px solid rgb(93,94,112);
}
.newcontainer{
  background-color: transparent;
  display: flex;
  flex-direction: row;
  flex-wrap: wrap;
  pointer-events: none;
}

.Hlight{
  background-color: rgb(238,238,238) !important;
  color: rgb(93,94,112) !important;
}
.newnums{
  color: rgb(123,135,187) !important;
}
.other-num{
  background-color: rgb(94,95,113) !important;
  color: #fff !important;
}
.no{
  background-color: rgb(179,182,187) !important;
  outline: none;
}
.num{
  background-color: rgb(140,163,57) !important;
  color: #fff !important;
}
/* 和新填入数冲突位置的样式 */
.error{
  background-color: rgb(238,238,238) !important;
  color: red !important;
}
/* 新填入数错误时的样式 */
.err{
  background-color: red !important;
  color:#fff !important;
}
/* 'err':num1==nowNum&&(index == nowClickPos.x||indexSub == nowClickPos.y||getBlock(index,indexSub)==nowClickBlock)&&(index != nowClickPos.x||indexSub != nowClickPos.y), */
.cf::after{
  height: 0px;
  display: block;
  clear: both;
  visibility: hidden;
  content: '';
}

后端部分

项目地址

https://gitee.com/yabcd/sodoku.git
用原来的helloworld项目改写的springboot项目,项目名字都没有改,使用DLX算法解题。生成题目采用随机删数,DLX求解,无解则回溯,回溯超过十次终止算法。

项目结构

在这里插入图片描述

生成jar包

在这里插入图片描述
生成后的jar包在target目录下,使用java -jar jar包名运行项目

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值