【趣味项目】2048 简单实现

【趣味项目】2048 简单实现

请添加图片描述

算法原理

假设用一个二维矩阵表示 2048 页面,操作是左滑

const matrix = [[2, 2, 4, 0],[0, 2, 4, 0],[0, 2, 2, 0],[2, 4, 4, 8]
];
  • 将所有非空的数字向左移动

    matrix = [[2, 2, 4, 0],[2, 4, 0, 0],[2, 2, 0, 0],[2, 4, 4, 8]
    ]
    
  • 将相邻的相同数字合并

    matrix = [[4, 0, 4, 0],[2, 4, 0, 0],[4, 0, 0, 0],[2, 8, 0, 8]
    ]
    
  • 将所有非空的数字向左移动

    matrix = [[4, 4, 0, 0],[2, 4, 0, 0],[4, 0, 0, 0],[2, 8, 8, 0]
    ]
    
  • 将相邻的相同数字合并

    matrix = [[8, 0, 0, 0],[2, 4, 0, 0],[4, 0, 0, 0],[2, 8, 8, 0]
    ]
    
  • 将所有非空的数字向左移动

     matrix = [[8, 0, 0, 0],[2, 4, 0, 0],[4, 0, 0, 0],[2, 8, 8, 0]]
    
  • 将相邻的相同数字合并

    matrix = [[8, 0, 0, 0],[2, 4, 0, 0],[4, 0, 0, 0],[2, 16, 0, 0]
    ]
    

用 js 实现上述操作

const moveLeft = (matrix) => {const moveLeftOnce = (matrix) => {const size = matrix.length;// 第一步:将所有非零的数字向左移动for (let i = 0; i < size; i++) {let currentRow = matrix[i].filter((item) => item !== 0);let zeroCount = size - currentRow.length;matrix[i] = currentRow.concat(Array(zeroCount).fill(0));}// 第二步:将相邻的相同数字合并for (let i = 0; i < size; i++) {for (let j = 0; j < size - 1; j++) {if (matrix[i][j] === matrix[i][j + 1]) {matrix[i][j] *= 2;matrix[i][j + 1] = 0;}}}}// 记录上一步结束的矩阵let lastSMatrix = JSON.stringify(matrix);while (true) {moveLeftOnce(matrix);// 没有变化则操作完毕if (JSON.stringify(matrix) === lastSMatrix) {break;}lastSMatrix = JSON.stringify(matrix);}
}
  • 左滑
  • 右滑: 翻转 -> 左滑 -> 翻转
  • 上滑: 对角线翻折 -> 左滑 -> 对角线翻折
  • 下滑: 对角线翻折 -> 右滑 -> 对角线翻折

实现思路

  1. render 函数用于渲染外部容器和内部单元格
  2. 通过 requestAnimationFrame 循环调用 render 函数
  3. 添加键盘事件,借助复杂类型传参直接修改 matrix
  4. render 函数根据 matrix 遍历渲染单元格
  5. 键盘事件触发后检测是否结束

实现源码

仅为 JS 文件部分,其他文件及目录结构可在该仓库查看 GitCode

// main.js
const moveLeft = (matrix) => {const moveLeftOnce = (matrix) => {const size = matrix.length;// 第一步:将所有非零的数字向左移动for (let i = 0; i < size; i++) {let currentRow = matrix[i].filter((item) => item !== 0);let zeroCount = size - currentRow.length;matrix[i] = currentRow.concat(Array(zeroCount).fill(0));}// 第二步:将相邻的相同数字合并for (let i = 0; i < size; i++) {for (let j = 0; j < size - 1; j++) {if (matrix[i][j] === matrix[i][j + 1]) {matrix[i][j] *= 2;matrix[i][j + 1] = 0;}}}}let lastSMatrix = JSON.stringify(matrix);while (true) {moveLeftOnce(matrix);if (JSON.stringify(matrix) === lastSMatrix) {break;}lastSMatrix = JSON.stringify(matrix);}
}const moveRight = (matrix) => {const reverseMatrix = (matrix) => {const size = matrix.length;for (let i = 0; i < size; i++) {matrix[i] = matrix[i].reverse();}}reverseMatrix(matrix);moveLeft(matrix);reverseMatrix(matrix);
}const moveUp = (matrix) => {const transposeMatrix = (matrix) => {const size = matrix.length;const newMatrix = Array.from({ length: size }, () => Array(size).fill(0));for (let i = 0; i < size; i++) {for (let j = 0; j < size; j++) {newMatrix[i][j] = matrix[j][i];}}for (let i = 0; i < size; i++) {for (let j = 0; j < size; j++) {matrix[i][j] = newMatrix[i][j];}}}transposeMatrix(matrix);moveLeft(matrix);transposeMatrix(matrix);
}const moveDown = (matrix) => {const transposeMatrix = (matrix) => {const size = matrix.length;const newMatrix = Array.from({ length: size }, () => Array(size).fill(0));for (let i = 0; i < size; i++) {for (let j = 0; j < size; j++) {newMatrix[i][j] = matrix[j][i];}}for (let i = 0; i < size; i++) {for (let j = 0; j < size; j++) {matrix[i][j] = newMatrix[i][j];}}}transposeMatrix(matrix);moveRight(matrix);transposeMatrix(matrix);
}const main = () => {const color = {0: '#CCC0B3',2: '#EEE4DA',4: '#EDE0C8',8: '#F2B179',16: '#F49563',32: '#F5794D',64: '#F55D37',128: '#EEE863',256: '#EDB04D',512: '#ECB04D',1024: '#EB9437',2048: '#EA7821',};const matrix = [[2, 2, 4, 0, 4],[0, 2, 4, 0, 0],[0, 2, 2, 0, 16],[2, 4, 4, 8, 32],[2, 4, 4, 8, 32],];/*** 绘制一个单元格* @param {string} color 颜色* @param {number} num 数字 */const renderPixel = (color, num) => {const div = document.createElement('div');div.style.width = '100px';div.style.height = '100px';div.style.backgroundColor = color;div.style.fontSize = '40px';div.style.textAlign = 'center';div.style.lineHeight = '100px';div.innerText = num;return div;}const size = matrix.length;const app = document.getElementById('app');const render = (matrix) => {const container = document.createElement('div');container.style.display = 'grid';container.style.gridTemplateColumns = `repeat(${size}, 100px)`;container.style.gridTemplateRows = `repeat(${size}, 100px)`;container.style.width = `${size * 100}px`;container.style.height = `${size * 100}px`;container.style.border = '1px solid #000';container.style.borderRadius = '5px';container.style.margin = '100px auto';container.style.boxShadow = '0 0 10px #000';container.style.position = 'relative';container.style.overflow = 'hidden';container.style.backgroundColor = '#BBADA0';container.style.borderRadius = '5px';container.style.padding = '5px';container.style.boxSizing = 'border-box';container.style.transition = 'all 0.3s';container.style.userSelect = 'none';container.style.touchAction = 'none';container.style.cursor = 'pointer';for (let i = 0; i < size; i++) {for (let j = 0; j < size; j++) {const pixel = renderPixel(color[matrix[i][j]], matrix[i][j]);container.appendChild(pixel);}}app.appendChild(container);};const update = (matrix) => {app.innerHTML = '';render(matrix);requestAnimationFrame(() => {update(matrix);});}requestAnimationFrame(() => {update(matrix);});document.addEventListener('keydown', (e) => {switch (e.key) {case 'ArrowLeft':moveLeft(matrix);break;case 'ArrowRight':moveRight(matrix);break;case 'ArrowUp':moveUp(matrix);break;case 'ArrowDown':moveDown(matrix);break;}const finishend = matrix.every((row) => row.every((item) => item !== 0));if (finishend) {alert('Game Over!');} else {const empty = [];for (let i = 0; i < size; i++) {for (let j = 0; j < size; j++) {if (matrix[i][j] === 0) {empty.push([i, j]);}}}const random = empty[Math.floor(Math.random() * empty.length)];matrix[random[0]][random[1]] = Math.random() > 0.5 ? 2 : 4;}});
};window.onload = main;

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

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

相关文章

自动化工程师涨薪难,原因出在这里

大家好&#xff0c;今天说说真实的工控行业&#xff0c;摒弃虚无的鸡汤&#xff0c;聊点实在的。 举个例子&#xff0c;某工做销售&#xff0c;卖电控器件&#xff0c;眼见PLC收入可观&#xff0c;开始感到压力。于是&#xff0c;他下定决心学PLC&#xff0c;报了培训班。毕业后…

手写简易操作系统(一)--环境配置

本专栏是我新开设的一个学术专栏&#xff0c;旨在全面介绍手写操作系统的相关内容。其中包括实模式向保护模式的过渡、锁机制、信号量操作、内存分配、硬盘驱动、文件系统、简单shell和管道等操作系统核心知识。该专栏旨在为有意开发自己操作系统的研究人员提供指导与帮助。作为…

昏暗场景增强-低照度增强-弱光增强(附代码)

引言 随着现代科技的发展&#xff0c;图像采集设备已经渗透到生活的方方面面&#xff0c;然而在昏暗场景、低照度或弱光条件下&#xff0c;图像的质量往往受到严重影响&#xff0c;表现为亮度不足、对比度低下、色彩失真以及细节丢失等问题。这类图像对于人眼识别和计算机视觉…

【NR技术】 3GPP支持无人机的关键技术以及场景

1 背景 人们对使用蜂窝连接来支持无人机系统(UAS)的兴趣浓厚&#xff0c;3GPP生态系统为UAS的运行提供了极好的好处。无处不在的覆盖范围、高可靠性和QoS、强大的安全性和无缝移动性是支持UAS指挥和控制功能的关键因素。与此同时&#xff0c;监管机构正在调查安全和性能标准以及…

C++进阶之路---继承(二)

顾得泉&#xff1a;个人主页 个人专栏&#xff1a;《Linux操作系统》 《C从入门到精通》 《LeedCode刷题》 键盘敲烂&#xff0c;年薪百万&#xff01; 一、继承与友元 友元关系不能继承&#xff0c;也就是说基类友元不能访问子类私有和保护成员。 class Student; class Per…

leetcode 热题 100_除自身以外数组的乘积

题解一&#xff1a; 前缀 / 后缀数组&#xff1a;某元素除自身以外的乘积&#xff0c;也就是其全部前缀元素乘积 * 全部后缀元素乘积&#xff0c;因此我们可以构造前缀数组和后缀数组&#xff0c;分别存储前i个元素的成绩和后i个元素的乘积&#xff0c;再将i-1前缀乘积 * i1后缀…

SpringBoot整合Redis实现分布式锁

SpringBoot整合Redis实现分布式锁 分布式系统为什么要使用分布式锁&#xff1f; 首先&#xff0c;分布式系统是由多个独立节点组成的&#xff0c;这些节点可能运行在不同的物理或虚拟机器上&#xff0c;它们通过网络进行通信和协作。在这样的环境中&#xff0c;多个节点可能同…

Java数组常用操作

创建数组 int[] a {1,2,3};int[] a new int[]{1,2,3};int[] a new int[3];ArrayList<Integer> arr new ArrayList<>(); 添加元素 arr.add(99); //将99加入到数组末尾arr.add(3,99); //将99加入到指定索引3处访问元素 int c1 c[1]; int arr1 arr.get(1); …

方阵的特征值与特征向量

目录 特征值 & 特征向量 相关性质 特征值 & 特征向量 相关性质

BlackHole

BlackHole 文章目录 BlackHole一、关于 BlackHole功能描述 二、安装、卸载安装方式一&#xff1a;下载安装器方式二&#xff1a;使用 Homebrew 安装 卸载方式一&#xff1a;使用卸载器方式二&#xff1a;手动卸载 三、用户使用指南1、Logic Pro X2、GarageBand3、Reaper4、录制…

MRI基础--k空间

k空间定义 k空间是表示 MR 图像中空间频率的数字数组。 k空间物理意义 k 空间的单元通常显示在主轴 kx 和 ky 的矩形网格上。 k 空间的 kx 和 ky 轴对应于图像的水平 (x) 和垂直 (y) 轴。然而,k 轴表示 x 和 y 方向上的空间频率而不是位置。 k 空间中的各个点 (kx,ky) 与图像…

聊一聊日常开发中如何优雅的避免那无处不在的空指针异常

在Java编程语言中&#xff0c;NullPointerException&#xff08;简称NPE&#xff09;是一种常见的运行时异常&#xff0c;当程序试图访问或操作一个还未初始化&#xff08;即值为null&#xff09;的对象引用时&#xff0c;Java虚拟机就会抛出NullPointerException。如果我们在日…

【技术】基于Github Pages搭建个人博客静态网页

写在前面&#xff1a; 如果文章对你有帮助&#xff0c;记得点赞关注加收藏一波&#xff0c;利于以后需要的时候复习&#xff0c;多谢支持&#xff01; 文章目录 一、技术基础二、新建特殊仓库三、上传网页文件四、Github Pages设置 个人网页作为仅服务个人的网页&#xff0c;一…

【打工日常】使用docker部署IT运维管理平台CAT

​一、CAT介绍 CAT是一个专为 IT 运维从业者打造的一站式解决方案平台&#xff0c;包含资产管理、工单、工作流、仓储等功能模块。 本项目是celaraze/chemex重构版&#xff0c;原项目chemex名称弃用&#xff1b;CAT采用全新架构设计&#xff0c;大量提升使用体验的细节&#xf…

Trie巧妙解决前后缀问题,3045. 统计前后缀下标对 II

目录 一、题目 1、题目描述 2、接口描述 3、原题链接 二、解题报告 1、思路分析 2、复杂度 3、代码详解 ​Python3 c 一、题目 1、题目描述 给你一个下标从 0 开始的字符串数组 words 。 定义一个 布尔 函数 isPrefixAndSuffix &#xff0c;它接受两个字符串参数 str…

JavaWeb笔记 --- 二、Maven

二、Maven Maven概述 所有的IDE创建的Maven项目都可以使用 Maven简介 Maven模型 Maven常用命令 Maven生命周期 Maven坐标 依赖管理 dpendencies&#xff1a;依赖 依赖范围

java-ssm-jsp-大学生互动交流网站设计与实现

java-ssm-jsp-大学生互动交流网站设计与实现 获取源码——》公主号&#xff1a;计算机专业毕设大全

STM32基础--构建自己的固件库

CMSIS 标准及库层次关系 因为基于 Cortex 系列芯片采用的内核都是相同的&#xff0c;区别主要为核外的片上外设的差异&#xff0c;这些差异却导致软件在同内核&#xff0c;不同外设的芯片上移植困难。为了解决不同的芯片厂商生产的 Cortex 微控制器软件的兼容性问题&#xff0…

鸿蒙Harmony应用开发—ArkTS声明式开发(基础手势:DatePicker)

日期选择器组件&#xff0c;用于根据指定日期范围创建日期滑动选择器。 说明&#xff1a; 该组件从API Version 8开始支持。后续版本如有新增内容&#xff0c;则采用上角标单独标记该内容的起始版本。 子组件 无 接口 DatePicker(options?: DatePickerOptions) 根据指定范…

java及特性的简单介绍

简介&#xff1a; 印度尼西亚有一个盛产咖啡的岛屿java&#xff0c;中文名翻译为爪哇&#xff0c;给这种新语言起码java 寓意端上一杯热咖啡。 特性&#xff1a; 1.面向对象 2.与平台无关 3.稳定安全 4.多线程 面向对象 1.面向对象语言关注的是对象&#xff0c;而不关注过程 2…