巧用二进制实现俄罗斯方块小游戏

效果预览

在这里插入图片描述

思想

首先建立两个数组board、tetris用来存储当前已经堆积在棋盘的方块与正在下落的方块。
这两个是一维数组当需要在页面画棋盘时就对其每一项转成二进制(看计算属性tetrisBoard),其中1(红色)0(白色)。
判断是否可以下落:对board、tetris每一项 &(与操作),如果都为0则还可以下落,否则停止下落。
判断是否触底:tetris的最后一项是否为0如果不为0则说明已经触底了
判断是否可以左(右)移: :对board、tetris每一项 &(与操作),如果都为0则还可以移动,否则停止移动
判断是否已经触碰右边界:对tetris每一项同二进制的0b00001进行与操作,如果是0则未触碰边界,相反则已经触碰边界了。
判断是否已经触碰左边界:对tetris每一项同二进制的0b100000进行与操作,如果是0则未触碰边界,相反则已经触碰边界了。
判断是否可以消除:循环board中的每一项与二进制0b11111(对应计算属性allOnesInBinaryDecimal)是否大小相同,相同的话就说明这行已经满了,满的话就将这项变为0,并把其上面的项向下移,同时给最上面补0。

代码

<template><div class="tetris-box"><div class="top-operator"><el-button type="primary" size="default" @click="init">{{ isStart ? '重新开始' : '开始' }}</el-button>宽:<el-input-numberv-model="widthNum":min="10":max="15"@change="handleChange":disabled="isStart"/>高:<el-input-numberv-model="heightNum":min="15":max="20"@change="handleChange":disabled="isStart"/><span>Score: {{ score }}</span></div><div class="game-container"><div class="row" v-for="(rowItem, index) in tetrisBoard" :key="index"><divclass="cell":style="{ background: cellItem === '1' ? 'red' : 'white' }"v-for="(cellItem, index) in rowItem":key="index"></div></div></div></div>
</template><script setup lang="ts">
import { ref, computed, onMounted, watch, nextTick, onBeforeUnmount } from 'vue'
import { cloneDeep } from 'lodash'
import { Scale } from 'canvg'
const widthNum = ref(10)
const heightNum = ref(14)
let score = ref(0)
const board = ref<number[]>([])
const tetris = ref<number[]>([])
let timer: number | null = null
let isStart = ref(false)
const allOnesInBinaryDecimal = computed(() => {return (1 << widthNum.value) - 1
})
const boardNum = computed(() => {// 将tetris中的每一项转成对应的2进制return board.value?.map((item, index) => {return item + tetris.value[index]})
})
// 用来画棋盘的二维数组
const tetrisBoard = computed({get() {// 将tetrisNum中的每一项转成对应的2进制return boardNum.value.map((item) => {return item.toString(2).padStart(widthNum.value, '0').split('')})},set(value) {},
})
const action = () => {timer = setInterval(() => {down()}, 1000)
}
onMounted(() => {// 棋盘初始化board.value = Array(heightNum.value).fill(0)
})
onBeforeUnmount(() => {clearInterval(timer as number)removeEventListener('keydown', listenser)
})
const init = () => {isStart.value = truescore.value = 0board.value = Array(heightNum.value).fill(0)removeEventListener('keydown', listenser)clearInterval(timer as number)initTetris()action()document.addEventListener('keydown', listenser)
}
const initTetris = () => {const tetrisArr = [[1, 1, 1, 1],[2, 3, 1],[3, 2, 2],[3, 1, 1],[2, 2, 3],[1, 1, 3],[1, 3, 2],[1, 3, 1],[2, 3, 2],[7, 1],[7, 2],[7, 4],[1, 7],[3, 6],[6, 3],[3, 3],[4, 7],[2, 7],[15],]let tempTetris = tetrisArr[Math.floor(Math.random() * tetrisArr.length)]const zeroArr = Array(heightNum.value - tempTetris.length).fill(0)tempTetris = tempTetris.concat(zeroArr)tetris.value = tempTetris// 让方块随机右移出现let rightMoveNum = Math.floor(Math.random() * widthNum.value)for (let i = 0; i < rightMoveNum; i++) {right()}let leftMoveNum = Math.floor(Math.random() * widthNum.value)for (let i = 0; i < leftMoveNum; i++) {left()}// 判断是否有哪一行已经满了就可以消除了board.value.forEach((item, index) => {if (item === allOnesInBinaryDecimal.value) {board.value.splice(index, 1)board.value.unshift(0)score.value += widthNum.value}})// 判断是否结束游戏for (let i = 0; i < tetris.value.length; i++) {if (tetris.value[i] & board.value[i]) {clearInterval(timer as number)removeEventListener('keydown', listenser)board.value = Array(heightNum.value).fill(0)alert('游戏结束')tetris.value = Array(heightNum.value).fill(0)isStart.value = falsebreak}}
}
const down = () => {const tempTetris = cloneDeep(tetris.value)tetris.value = [0].concat(tetris.value.splice(0, tetris.value.length - 1))// 判断是否可以下落for (let i = 0; i < tetris.value.length; i++) {// 如果有碰撞或者已经触底了就用board存储目前已经堆积的方块// 并重新在最上方生成一个新的方块if (tetris.value[i] & board.value[i] || tempTetris[tempTetris.length - 1]) {board.value = board.value?.map((item, index) => {return item + tempTetris[index]})initTetris()break}}
}
const right = () => {const tempTetris = cloneDeep(tetris.value)tetris.value = tetris.value.map((item, index) => {return item >> 1})// 判断是否可以右移for (let i = 0; i < tetris.value.length; i++) {// 如果触发边界就不再移动if (tetris.value[i] & board.value[i] || tempTetris[i] & 1) {tetris.value = tempTetrisbreak}}
}
const left = () => {const tempTetris = cloneDeep(tetris.value)tetris.value = tetris.value.map((item, index) => {return item << 1})// 判断是否可以左移for (let i = 0; i < tetris.value.length; i++) {// 如果触发边界就不再移动if (tetris.value[i] & board.value[i] ||tempTetris[i] & (1 << (widthNum.value - 1))) {tetris.value = tempTetrisbreak}}
}
const up = () => {const tempTetris = cloneDeep(tetris.value)// tetris.value = tetris.value.map((item, index) => {//   return item ^ 1// })let temp = tetris.value.map((item) => {return item.toString(2).padStart(widthNum.value, '0').split('')})temp = rotateMatrix90(temp)tetris.value = temp.map((item) => {return parseInt(item.join(''), 2)})// 判断是否可以旋转for (let i = 0; i < tetris.value.length; i++) {if (tetris.value[i] & board.value[i]) {tetris.value = tempTetrisbreak}}
}
const listenser = (e) => {switch (e.keyCode) {case 37:left()breakcase 40:down()breakcase 39:right()breakcase 38:up()breakdefault:break}
}
const handleChange = () => {board.value = Array(heightNum.value).fill(0)
}// ---------下面都是旋转逻辑---------
// 找出非零最小正方形区域
const findMinSquare = (matrix) => {let top = matrix.length,left = matrix[0].length,bottom = 0,right = 0// 寻找非零元素的边界for (let i = 0; i < matrix.length; i++) {for (let j = 0; j < matrix[i].length; j++) {if (matrix[i][j] !== '0') {top = Math.min(top, i)left = Math.min(left, j)bottom = Math.max(bottom, i)right = Math.max(right, j)}}}// 返回最小正方形区域let result = {top: top,left: left,width: right - left + 1,height: bottom - top + 1,square: [],radius: 0,chaju: 0,}// 半径let radius = Math.max(result.width, result.height)result.radius = radiuslet chaju = 0if (left + radius > widthNum.value) {chaju = left + radius - widthNum.value}result.chaju = chaju// 如果需要返回实际的最小正方形子矩阵,请添加以下代码for (let i = 0; i < radius; i++) {const row = []for (let j = 0; j < radius; j++) {row.push(matrix[top + i][left + j - chaju])}result.square.push(row)}return result
}
// 对正方形区域进行旋转90度
const rotateMinSquareMatrix90 = (matrix) => {const n = matrix.lengthconst rotatedMatrix = Array.from({ length: n }, () => new Array(n).fill(null))for (let i = 0; i < n; i++) {for (let j = 0; j < n; j++) {rotatedMatrix[j][n - i - 1] = matrix[i][j]}}return rotatedMatrix
}
// 旋转矩阵90度的主函数
const rotateMatrix90 = (matrix) => {const tempMatrix = cloneDeep(matrix)let result = findMinSquare(tempMatrix)result.square = rotateMinSquareMatrix90(result.square)for (let i = 0; i < result.radius; i++) {for (let j = 0; j < result.radius; j++) {tempMatrix[result.top + i][result.left + j - result.chaju] =result.square[i][j]}}return tempMatrix
}
</script><style scoped lang="scss">
.tetris-box {display: flex;flex-direction: column;align-items: center;.game-container {}.row {display: flex;}.cell {width: 35px;height: 35px;background: pink;border: 0.5px solid #000;}
}
</style>
</script><style scoped lang="scss">
.tetris-box {display: flex;flex-direction: column;align-items: center;.game-container {}.row {display: flex;}.cell {width: 35px;height: 35px;background: pink;border: 0.5px solid #000;}
}
</style>

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

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

加密与安全_深入了解Hmac算法(消息认证码)

文章目录 PreHMAC概述常见的Hmac算法Code随机的key的生成 KeyGeneratorHmacMD5用Hmac算法取代原有的自定义的加盐算法 HmacMD5 VS MD5HmacSHA256 Pre 加密与安全_深入了解哈希算法中我们提到&#xff0c; 存储用户的哈希口令时&#xff0c;要加盐存储&#xff0c;目的就在于抵…

现货黄金价格今日行情怎样把握?

由于受到各种经济和政治因素的影响&#xff0c;国际市场上的黄金价格&#xff0c;每天的行情走势都在不断地波动&#xff0c;有时候行情上涨&#xff0c;有时候行情下跌&#xff0c;如果投资者不懂得灵活地应对&#xff0c;在哪一种行情中都有可能亏损&#xff0c;但如果投资者…

Linux系统CPU模式部署Qwen1.5-14B

Qwen1.5已适配Ollama。 Ollama 是一个命令行聊天机器人&#xff0c;它使得几乎可以在任何地方使用大型语言模型变得简单。 下载 Ollma 安装文件 访问以下网站&#xff1a;https://ollama.com/download/linux 执行&#xff1a;curl -fsSL https://ollama.com/install.sh | sh…

信息安全是什么

信息安全&#xff0c;也称为信息安全或数据安全&#xff0c;是防止未经授权的访问、更改、中断和破坏信息。 信息安全本身包括的范围很大&#xff0c;大到国家军事政治等机密安全&#xff0c;小范围的当然还包括如防范商业企业机密泄露&#xff0c;防范青少年对不良信息的浏览…

解决虚拟机启动报错:“End kernel panic - not syncing: attempted to kill the idle task”

原本能正常运行的虚拟机&#xff0c;很长一段时间没用后&#xff0c;今天再次启动&#xff0c;然后就出现下面的问题&#xff1a; 然后走了一些弯路&#xff0c;比如说删除该虚拟机然后新建一个虚拟机&#xff08;问题未解决&#xff09;、直接删除VitualBox重新安装&#xff0…

探索网络世界:IP代理与爬虫技术的全景解析

博主猫头虎的技术世界 &#x1f31f; 欢迎来到猫头虎的博客 — 探索技术的无限可能&#xff01; 专栏链接&#xff1a; &#x1f517; 精选专栏&#xff1a; 《面试题大全》 — 面试准备的宝典&#xff01;《IDEA开发秘籍》 — 提升你的IDEA技能&#xff01;《100天精通鸿蒙》 …

全新攻击面管理平台

首页大屏 内测阶段&#xff0c;免费试用一个月 有兴趣体验的师傅&#xff0c;来长亭云图极速版群里找我 py

0201sherlock(福尔摩斯)-通过名称寻找媒体账号(地址)-github-开源项目学习

文章目录 一 项目简介二 项目安装和演示1 安装2 演示 三 源码分析1 项目结构2 主程序源代码分析 四 添加自定义网址结语 一 项目简介 二 项目安装和演示 1 安装 # clone the repo $ git clone https://github.com/sherlock-project/sherlock.git# change the working direct…

【acwing】前缀与差分

前缀和 题目 输入一个长度为 n的整数序列。 接下来再输入 m个询问&#xff0c;每个询问输入一对 l,r。 对于每个询问&#xff0c;输出原序列中从第 l 个数到第 r 个数的和。 输入格式 第一行包含两个整数 n和 m。 第二行包含 n个整数&#xff0c;表示整数数列。 接下来 …

手把手教你用VMware安装华为存储模拟器

你们好&#xff0c;我的网工朋友。 对于新手来说&#xff0c;很多人因为不清楚虚拟机的操作原理&#xff0c;导致不知道怎么安装创建虚拟机。 群里经常看到有人问虚拟机的相关问题&#xff0c;今天来一篇教你用Vmware虚拟机安装华为存储模拟器&#xff0c;一步步实现简单创建…

通过jenkins进行部署java程序到centos上

1.通过jumpserver访问到centos上&#xff0c;准备下java环境 // step1: 先编辑下 vim /etc/profile// step2: 编写好环境变量 JAVA_HOME/usr/local/java export JAVA_HOME export ZOOKEEPER_HOME/opt/zookeeper/apache-zookeeper-3.7.0-bin PATH$PATH:$JAVA_HOME/bin:$ZOOKEEP…

cgroup——在pod内使用cgroup限制CPU

在Kubernetes中&#xff0c;可以使用Cgroup来限制Pod中的CPU资源使用。具体步骤如下&#xff1a; Pod的定义文件中配置 在Pod的定义文件中&#xff0c;添加资源限制&#xff08;limits&#xff09;和资源请求&#xff08;requests&#xff09;字段。例如&#xff1a; apiVer…

ArrayList集合源码分析

ArrayList集合源码分析 文章目录 ArrayList集合源码分析一、字段分析二、构造方法分析三、方法分析四、总结 内容如有错误或者其他需要注意的知识点&#xff0c;欢迎指正或者探讨补充&#xff0c;共同进步。 一、字段分析 //默认初始化容量。这里和Vector一样&#xff0c;只是…

刷题日记:面试经典 150 题 DAY3

刷题日记&#xff1a;面试经典 150 题 DAY3 274. H 指数238. 除自身以外数组的乘积380. O(1) 时间插入、删除和获取随机元素134. 加油站135. 分发糖果 274. H 指数 原题链接 274. H 指数 重要的是都明白H指数到底是是个啥。注意到如果将引用数从大到小排序&#xff0c;则对于…

windows环境下Grafana+loki+promtail入门级部署日志系统,收集Springboot(Slf4j+logback)项目日志

&#x1f339;作者主页&#xff1a;青花锁 &#x1f339;简介&#xff1a;Java领域优质创作者&#x1f3c6;、Java微服务架构公号作者&#x1f604; &#x1f339;简历模板、学习资料、面试题库、技术互助 &#x1f339;文末获取联系方式 &#x1f4dd; 往期热门专栏回顾 专栏…

【开发工具】GIF 录屏工具推荐 ( GIF123 - 推荐使用 | GifCam | LICEcap )

文章目录 一、GIF 录屏工具推荐1、GIF123 ( 推荐使用 )2、GifCam3、LICEcap 本博客中介绍的 3 款 GIF 录屏工具下载地址 : https://download.csdn.net/download/han1202012/88905642 也可以到对应的官网独立下载 : GIF123 : https://gif123.aardio.com/ ;GifCam : https://bl…

【JavaEE】_Spring MVC 项目传参问题

目录 1. 传递单个参数 1.1 关于参数名的问题 2. 传递多个参数 2.1 关于参数顺序的问题 2.2 关于基本类型与包装类的问题 3. 使用对象传参 4. 后端参数重命名问题 4.1 关于RequestPara注解 1. 传递单个参数 现创建Spring MVC项目&#xff0c;.java文件内容如下&#xff…

探索数字未来:DApp钱包Defi引领新纪元

​小编介绍&#xff1a;10年专注商业模式设计及软件开发&#xff0c;擅长企业生态商业模式&#xff0c;商业零售会员增长裂变模式策划、商业闭环模式设计及方案落地&#xff1b;扶持10余个电商平台做到营收过千万&#xff0c;数百个平台达到百万会员&#xff0c;欢迎咨询。 随…

99.qt qml-单例程序实现

在之前讲过: 58.qt quick-qml系统托盘实现https://nuoqian.blog.csdn.net/article/details/121855993 由于,该示例只是简单讲解了系统托盘实现,并没有实现单例程序,所以多次打开后就会出现多个exe出现的可能,本章出一章QML单例程序实现, 多次打开始终只显示出第一个打开…

深入分析Android运行时环境ART:原理、特点与优化策略

摘要 随着移动互联网的快速发展&#xff0c;智能手机的性能和功能日益强大&#xff0c;其中Android操作系统因其开放性和灵活性而占据主导地位。Android运行时环境&#xff08;ART&#xff09;作为执行应用程序代码的关键组件&#xff0c;在系统性能和用户体验方面起着至关重要…