C# 之 带你玩转命令行版《2048》 -- 附源码分享
C# 之 带你玩转命令行版《2048》 -- 附源码分享
- 一,效果展示
- 二,玩法说明
- 三,主要逻辑
- 四,代码实现
- 4.1 游戏开始
- 4.2 随机生成
- 4.3 数字移动
- 4.4 判断胜负
- 4.5 重新开始
- 五,源码分享
一,效果展示
二,玩法说明
游戏的规则很简单,你需要控制所有方块向同一个方向运动,两个相同数字方块撞在一起之后合并成为他们的和,每次操作之后会随机生成一个2或者4,最终得到一个“2048”的方块就算胜利了。
三,主要逻辑
- 4*4的二维数组, 然后遍历里面的元素,统计所有的0,放到一个list里面,然后
Random.next(0,list.count)
随机一个赋成2. - 循环开始,初始化命令行.
- 键盘输入
上下左右
对应四种操作的函数 操作之后先遍历一下有没有空格 如果有就继续 没有空格还得再判断一下能不能再动了 如果不能就死了 - 只需要写向左和向下的逻辑,向右和向上对应取反即可
- 如果有任何一个元素是2048 即获胜
四,代码实现
4.1 游戏开始
游戏开始:
- 随机生成两个2
- 开启游戏循环
- 每次校验游戏是够结束
- 检测用户操作(上下左右)
- 输出当前状态到控制台
/// <summary>
/// 游戏开始
/// </summary>
public void GameStart()
{Add2();Add2();Output();while (true){// 用于遍历检测按下按键之后和之前有没有区别用的bool型变量bool flag = false;// 胜利条件 遍历foreach (int item in arr) {if (item == 2048){Console.WriteLine("\n(ノ´▽`)ノ♪ ------ 游戏胜利 ------ (ノ´▽`)ノ♪");Last();}}// 这是用于检测按下按键之后和之前有没有区别用的备份数组int[,] arrtmp = new int[4, 4];// 遍历给备份数组赋值for (int i = 0; i < 4; i++) {for (int j = 0; j < 4; j++){arrtmp[i, j] = arr[i, j];}}// 获取用户操作 --> 上下左右ConsoleKeyInfo info = Console.ReadKey(true); switch (info.Key){case ConsoleKey.UpArrow:MoveUp();break;case ConsoleKey.DownArrow:MoveDown();break;case ConsoleKey.LeftArrow:MoveLeft();break;case ConsoleKey.RightArrow:MoveRight();break;}// 遍历检测 按下方向键前的状态 和 按下方向键之后的状态是不是完全一样的for (int i = 0; i < 4; i++) {for (int j = 0; j < 4; j++){if (arrtmp[i, j] != arr[i, j]){// 一旦有任意一个元素在之前之后不一样 那么falg改为trueflag = true; }}}if (flag){// 如果falg是true 说明变了, 如果变了 就刷一个2出来, // 反之就什么也不干Add2(); }// 输出到控制台Output();// 检测按下方向键之后死没死if (!End()) {Console.WriteLine("\n(;´д`)ゞ ------ 游戏失败 ------ (;´д`)ゞ");Last();}}
}
4.2 随机生成
遍历非零元素 随机把一个赋为2
public void Add2()
{listOfCoo.Clear();// 遍历所有零元素的坐标for (int i = 0; i < 4; i++){for (int j = 0; j < 4; j++){if (arr[i, j] == 0){// 把遍历到的坐标 当成参数 实例化CoordinateTools coo = new CoordinateTools(i, j);// 把实例化的结果add到list里listOfCoo.Add(coo);}}}// 如果列表里一个元素都没存进来 说明表里没有空格了 直接退出if (listOfCoo.Count == 0){return;}// 从表里随机取一个位置 int cooPlus = rd.Next(0, listOfCoo.Count);// 把这个位置赋值改写为2arr[listOfCoo[cooPlus].x, listOfCoo[cooPlus].y] = 2;
}
4.3 数字移动
已向下移动为例:
- 非0数向下移动,遇到非0数,相同则累加,不同则保存到当前位置;
- 向上移动的话,再翻转一下就可以了
public void MoveDown()
{for (int j = 0; j < 4; j++){for (int i = 2; i >= 0; i--){if (arr[i, j] == 0) continue;for (int k = i + 1; k < 4; k++){if (arr[k, j] != 0){if (arr[i, j] == arr[k, j]){arr[k, j] += arr[i, j];arr[i, j] = 0;break;}else if (arr[i, j] != arr[k, j] && k - 1 != i){arr[k - 1, j] = arr[i, j];arr[i, j] = 0;break;}else if (arr[i, j] != arr[k, j] && k - 1 == i){break;}}if (k == 3){arr[k, j] = arr[i, j];arr[i, j] = 0;break;}}}}
}
4.4 判断胜负
判断游戏结束:
- 遍历数组 有任何一个空元素都说明不可能死
- 从2开始到2048进行遍历;目的是检测 每一个数字 他上下左右相邻有没有和他一样的数字
// 判断游戏结束
public bool End()
{// 遍历数组 有任何一个空元素都说明不可能死foreach (int item in arr){if (item == 0)return true;}// 从2开始到2048进行遍历 // 目的是检测 每一个数字 他上下左右相邻有没有和他一样的数字 for (int num = 2; num <= 2048; num *= 2){List<CoordinateTools> listOfget2 = new List<CoordinateTools>();for (int i = 0; i < 4; i++){for (int j = 0; j < 4; j++){if (arr[i, j] == num){// 先把所有值为NUM的元素的下标 存到list里CoordinateTools coo = new CoordinateTools(i, j); listOfget2.Add(coo);}}}// 如果这个list 是空的 就说明当前表里没有num 回到FOR继续if (listOfget2 == null) {continue;}// 从列表里的第一个元素开始 (每一个元素存的都是一组下标x,y)foreach (CoordinateTools item in listOfget2){foreach (CoordinateTools item2 in listOfget2){// 判断 同一行的是不是列坐标差的绝对值是1 同一列的是不是行坐标差的绝对值是1if ((item.y == item2.y && Math.Abs(item.x - item2.x) == 1) || (item.x == item2.x && Math.Abs(item.y - item2.y) == 1)) {// 如果有一个 就不用再循环了 肯定没死return true; }}}}// 全遍历完了 就说明已经死了 返回falsereturn false;
}
4.5 重新开始
判断游戏结束后,提示用户是“退出”还是“重玩”,根据用户选择进行逻辑处理
/// <summary>
/// 胜利或失败之后的选择
/// </summary>
public void Last()
{Console.WriteLine("\n输入X退出 输入R重新开始\n");while (true){string str = Console.ReadLine();if (str == "x"){Environment.Exit(0);}//重新开始 --> 初始化if (str == "r"){for (int i = 0; i < 4; i++){for (int j = 0; j < 4; j++){arr[i, j] = 0;}}GameStart();}}
}
五,源码分享
using System;
using System.Collections.Generic;namespace CSharp_2048
{class Program{static void Main(string[] args){Class2048 class2048 = new Class2048();class2048.GameStart();}/// <summary>/// 游戏类2048/// </summary>class Class2048{public int[,] arr = new int[4, 4];public Random rd = new Random();public List<CoordinateTools> listOfCoo = new List<CoordinateTools>();/// <summary>/// 输出当前状态/// </summary>public void Output(){string str = " ";Console.Clear();Console.WriteLine("┏┉┉┉┉┉┉┉┉┳┉┉┉┉┉┉┉┉┳┉┉┉┉┉┉┉┉┳┉┉┉┉┉┉┉┉┓");Console.WriteLine("┋ ┋ ┋ ┋ ┋");Console.WriteLine("┋ {0} ┋ {1} ┋ {2} ┋ {3} ┋",arr[0, 0] == 0 ? str : arr[0, 0].ToString().PadLeft(4, ' '),arr[0, 1] == 0 ? str : arr[0, 1].ToString().PadLeft(4, ' '), arr[0, 2] == 0 ? str : arr[0, 2].ToString().PadLeft(4, ' '),arr[0, 3] == 0 ? str : arr[0, 3].ToString().PadLeft(4, ' '));Console.WriteLine("┋ ┋ ┋ ┋ ┋");Console.WriteLine("┣┉┉┉┉┉┉┉┉╋┉┉┉┉┉┉┉┉╋┉┉┉┉┉┉┉┉╋┉┉┉┉┉┉┉┉┫");Console.WriteLine("┋ ┋ ┋ ┋ ┋");Console.WriteLine("┋ {0} ┋ {1} ┋ {2} ┋ {3} ┋", arr[1, 0] == 0 ? str : arr[1, 0].ToString().PadLeft(4, ' '),arr[1, 1] == 0 ? str : arr[1, 1].ToString().PadLeft(4, ' '),arr[1, 2] == 0 ? str : arr[1, 2].ToString().PadLeft(4, ' '),arr[1, 3] == 0 ? str : arr[1, 3].ToString().PadLeft(4, ' '));Console.WriteLine("┋ ┋ ┋ ┋ ┋");Console.WriteLine("┣┉┉┉┉┉┉┉┉╋┉┉┉┉┉┉┉┉╋┉┉┉┉┉┉┉┉╋┉┉┉┉┉┉┉┉┫");Console.WriteLine("┋ ┋ ┋ ┋ ┋");Console.WriteLine("┋ {0} ┋ {1} ┋ {2} ┋ {3} ┋",arr[2, 0] == 0 ? str : arr[2, 0].ToString().PadLeft(4, ' '),arr[2, 1] == 0 ? str : arr[2, 1].ToString().PadLeft(4, ' '), arr[2, 2] == 0 ? str : arr[2, 2].ToString().PadLeft(4, ' '),arr[2, 3] == 0 ? str : arr[2, 3].ToString().PadLeft(4, ' '));Console.WriteLine("┋ ┋ ┋ ┋ ┋");Console.WriteLine("┣┉┉┉┉┉┉┉┉╋┉┉┉┉┉┉┉┉╋┉┉┉┉┉┉┉┉╋┉┉┉┉┉┉┉┉┫");Console.WriteLine("┋ ┋ ┋ ┋ ┋");Console.WriteLine("┋ {0} ┋ {1} ┋ {2} ┋ {3} ┋",arr[3, 0] == 0 ? str : arr[3, 0].ToString().PadLeft(4, ' '),arr[3, 1] == 0 ? str : arr[3, 1].ToString().PadLeft(4, ' '),arr[3, 2] == 0 ? str : arr[3, 2].ToString().PadLeft(4, ' '),arr[3, 3] == 0 ? str : arr[3, 3].ToString().PadLeft(4, ' '));Console.WriteLine("┋ ┋ ┋ ┋ ┋");Console.WriteLine("┗┉┉┉┉┉┉┉┉┻┉┉┉┉┉┉┉┉┻┉┉┉┉┉┉┉┉┻┉┉┉┉┉┉┉┉┛");Console.WriteLine("\n<<命令行版2048>> 请按上下左右(↑←↓→)方向键操作");}/// <summary>/// 遍历非零元素 随机把一个赋为2/// </summary>public void Add2(){listOfCoo.Clear();// 遍历所有零元素的坐标for (int i = 0; i < 4; i++){for (int j = 0; j < 4; j++){if (arr[i, j] == 0){// 把遍历到的坐标 当成参数 实例化CoordinateTools coo = new CoordinateTools(i, j);// 把实例化的结果add到list里listOfCoo.Add(coo);}}}// 如果列表里一个元素都没存进来 说明表里没有空格了 直接退出if (listOfCoo.Count == 0){return;}// 从表里随机取一个位置 int cooPlus = rd.Next(0, listOfCoo.Count);// 把这个位置赋值改写为2arr[listOfCoo[cooPlus].x, listOfCoo[cooPlus].y] = 2;}/// <summary>/// 游戏开始/// </summary>public void GameStart(){Add2();Add2();Output();while (true){// 用于遍历检测按下按键之后和之前有没有区别用的bool型变量bool flag = false;// 胜利条件 遍历foreach (int item in arr) {if (item == 2048){Console.WriteLine("\n(ノ´▽`)ノ♪ ------ 游戏胜利 ------ (ノ´▽`)ノ♪");Last();}}// 这是用于检测按下按键之后和之前有没有区别用的备份数组int[,] arrtmp = new int[4, 4];// 遍历给备份数组赋值for (int i = 0; i < 4; i++) {for (int j = 0; j < 4; j++){arrtmp[i, j] = arr[i, j];}}// 获取用户操作 --> 上下左右ConsoleKeyInfo info = Console.ReadKey(true); switch (info.Key){case ConsoleKey.UpArrow:MoveUp();break;case ConsoleKey.DownArrow:MoveDown();break;case ConsoleKey.LeftArrow:MoveLeft();break;case ConsoleKey.RightArrow:MoveRight();break;}// 遍历检测 按下方向键前的状态 和 按下方向键之后的状态是不是完全一样的for (int i = 0; i < 4; i++) {for (int j = 0; j < 4; j++){if (arrtmp[i, j] != arr[i, j]){// 一旦有任意一个元素在之前之后不一样 那么falg改为trueflag = true; }}}if (flag){// 如果falg是true 说明变了, 如果变了 就刷一个2出来, // 反之就什么也不干Add2(); }// 输出到控制台Output();// 检测按下方向键之后死没死if (!End()) {Console.WriteLine("\n(;´д`)ゞ ------ 游戏失败 ------ (;´д`)ゞ");Last();}}}#region 核心逻辑 --> 向四个方向移动的控制/// <summary>/// 向下 非0数向下移动,遇到非0数,相同则累加,不同则保存到当前位置/// </summary>public void MoveDown(){for (int j = 0; j < 4; j++){for (int i = 2; i >= 0; i--){if (arr[i, j] == 0) continue;for (int k = i + 1; k < 4; k++){if (arr[k, j] != 0){if (arr[i, j] == arr[k, j]){arr[k, j] += arr[i, j];arr[i, j] = 0;break;}else if (arr[i, j] != arr[k, j] && k - 1 != i){arr[k - 1, j] = arr[i, j];arr[i, j] = 0;break;}else if (arr[i, j] != arr[k, j] && k - 1 == i){break;}}if (k == 3){arr[k, j] = arr[i, j];arr[i, j] = 0;break;}}}}}/// <summary>/// 向上移动: 先把数组上下翻转 然后向下移动 移动完了再翻转回来/// </summary>public void MoveUp(){for (int i = 0; i < 2; i++){for (int j = 0; j < 4; j++){int tmp = 0;tmp = arr[i, j];arr[i, j] = arr[3 - i, j];arr[3 - i, j] = tmp;}}MoveDown();for (int i = 0; i < 2; i++){for (int j = 0; j < 4; j++){int tmp = 0;tmp = arr[i, j];arr[i, j] = arr[3 - i, j];arr[3 - i, j] = tmp;}}}/// <summary>/// 向左移动/// </summary>public void MoveLeft(){for (int i = 0; i < 4; i++){for (int j = 1; j < 4; j++){if (arr[i, j] == 0) continue;for (int k = j - 1; k >= 0; k--){if (arr[i, k] != 0){if (arr[i, j] == arr[i, k]){arr[i, k] += arr[i, j];arr[i, j] = 0;break;}else if (arr[i, j] != arr[i, k] && k + 1 != j){arr[i, k + 1] = arr[i, j];arr[i, j] = 0;break;}else if (arr[i, j] != arr[i, k] && k + 1 == j){break;}}if (k == 0){arr[i, k] = arr[i, j];arr[i, j] = 0;break;}}}}}/// <summary>/// 向右移动: 先把数组左右翻转 然后向左移动 移动完了再翻转回来/// </summary>public void MoveRight(){for (int j = 0; j < 2; j++){for (int i = 0; i < 4; i++){int tmp = 0;tmp = arr[i, j];arr[i, j] = arr[i, 3 - j];arr[i, 3 - j] = tmp;}}MoveLeft();for (int j = 0; j < 2; j++){for (int i = 0; i < 4; i++){int tmp = 0;tmp = arr[i, j];arr[i, j] = arr[i, 3 - j];arr[i, 3 - j] = tmp;}}}#endregion/// <summary>/// 判断是否失败/// </summary>/// <returns></returns>public bool End(){// 遍历数组 有任何一个空元素都说明不可能死foreach (int item in arr){if (item == 0)return true;}// 从2开始到2048进行遍历 // 目的是检测 每一个数字 他上下左右相邻有没有和他一样的数字 for (int num = 2; num <= 2048; num *= 2){List<CoordinateTools> listOfget2 = new List<CoordinateTools>();for (int i = 0; i < 4; i++){for (int j = 0; j < 4; j++){if (arr[i, j] == num){// 先把所有值为NUM的元素的下标 存到list里CoordinateTools coo = new CoordinateTools(i, j); listOfget2.Add(coo);}}}// 如果这个list 是空的 就说明当前表里没有num 回到FOR继续if (listOfget2 == null) {continue;}// 从列表里的第一个元素开始 (每一个元素存的都是一组下标x,y)foreach (CoordinateTools item in listOfget2){foreach (CoordinateTools item2 in listOfget2){// 判断 同一行的是不是列坐标差的绝对值是1 同一列的是不是行坐标差的绝对值是1if ((item.y == item2.y && Math.Abs(item.x - item2.x) == 1) || (item.x == item2.x && Math.Abs(item.y - item2.y) == 1)) {// 如果有一个 就不用再循环了 肯定没死return true; }}}}// 全遍历完了 就说明已经死了 返回falsereturn false; }/// <summary>/// 胜利或失败之后的选择/// </summary>public void Last(){Console.WriteLine("\n输入X退出 输入R重新开始\n");while (true){string str = Console.ReadLine();if (str == "x"){Environment.Exit(0);}//重新开始 --> 初始化if (str == "r"){for (int i = 0; i < 4; i++){for (int j = 0; j < 4; j++){arr[i, j] = 0;}}GameStart();}}}}/// <summary>/// 工具类 用于存储搜索到的数组的下标/// </summary>class CoordinateTools{public int x { set; get; }public int y { set; get; }public CoordinateTools(int i, int j){this.x = i;this.y = j;}}}
}
C# 之 带你玩转命令行版《2048》 -- 附源码分享相关推荐
- java编辑2048小游戏_Java 制作命令行版 2048小游戏
Java 命令行版 2048小游戏(2020年8月14日) 制作背景 大二即将开学,从头开始学习了一个多月的java,对二维数组的操作稍微熟悉了一些.于是想做一个简单的2048来试一试. 众所周知,2 ...
- Python嘎嘎涨知识的7个小游戏,玩过的都爱不释手(附源码,直接运行就可)
前言 今天星期七,是一个快乐的日子.上班族不用上班,学生不用学习.我也不想分享太多的知识去为难大家,就给大家七个小游戏 吧,从周一玩到周日的那种,学会了记得来找我PK- 1.消消乐 玩法:三个相连就能 ...
- 教你用300万共享单车出行数据,预测骑行目的地 !(附源码)
点击有惊喜 摩拜单车在北京的单车投放量已经超过40万.用户可以直接在人行道上找到停放的单车,用手机解锁,然后骑到目的地后再把单车停好并锁上.因此,为了更好地调配和管理这40万辆单车,需要准确地预测每个 ...
- 后渗透——内网转发之借助WinRAR软件用命令行打包压缩网站源码
WinRAR是一个强大的压缩文件管理工 具.它能备份你的数据,减少你的E-mail附件的大小,解压缩从Internet上下载的RAR.ZIP和其他格式的压缩文件 本章主要讲解怎样用命令行实现对目录文件 ...
- 白话生成对抗网络 GAN,50 行代码玩转 GAN 模型!【附源码】
红色石头的个人网站:redstonewill.com 今天,红色石头带大家一起来了解一下如今非常火热的深度学习模型:生成对抗网络(Generate Adversarial Network,GAN).G ...
- 手把手教你生成对抗网络 GAN,50 行代码玩转 GAN 模型!(附源码)
来源:AI有道 本文约2820字,建议阅读12分钟. 本文为大家介绍了生成对抗网络(Generate Adversarial Network,GAN),以最直白的语言来讲解它,最后实现一个简单的 GA ...
- 【数据结构】带你细致理解十大排序(附源码)
文章目录 前言 一. 冒泡排序 前一个数跟后一个数比较 后一个数跟前一个数比较 优化 复杂度与稳定性 二. 插入排序 初始化条件从第一个元素开始 初始化条件从第二个元素开始 复杂度与稳定性 三. 选择 ...
- 【pygame游戏】用Python实现一个蔡徐坤大战篮球的小游戏,可还行?【附源码】
Python制作坤坤打篮球小游戏 序言 准备工作 开发环境 效果预览 开始界面 游戏规则 结束游戏 代码实现 序言 话说在前面,我不是小黑子~ 我是超级大黑子
- 【Python小游戏】一只大猩猩“刷”爆了朋友圈?敢玩这个游戏不?(附源码)
前言 如果让你模仿大猩猩,你会怎么做?一个典型的动作就是用两只手轮流快速拍打胸口,敲出嘭 嘭嘭打鼓一般的声音.对就是这样
- Visual C C++ studio2019 自制鼠标点击器,窗口版和命令行版 210325
一 窗口版 1.h和cpp h: DesktopMouseClick1.h #pragma once#include "resource.h" #include <threa ...
最新文章
- 【Android 安装包优化】WebP 图片格式性能测试 ( 测试 WebP 图片解码速度 | 测试 WebP 图片编码速度 )
- 求数组的子数组之和的最大值IV
- 【题解】Luogu SP1435 PT07X - Vertex Cover
- linux安装python_VTK:华为笔记本电脑+深度deepin-linux+python下安装和入门
- oracle 备份教研归档失败,归档日志丢失造成Rman备份失败解决办法
- android.mk ndk编译选项优化,Android NDK 编译脚本分析 之一
- c语言数组冒泡排序程序的解释,c语言指针数组冒泡排序代码
- UiAutomator喷射事件的源代码分析
- 知识分享:如何用插件实现操作校验
- manjaro Linux下使用腾讯会议
- Ubuntu各版本下载安装知网论文阅读神器CAJViewer,并添加快捷图标启动方式
- Python词频统计
- 安川工业机器人实训心得_安川MOTOMAN工业机器人编程与操作(3)
- Chrom浏览器安装CRX插件
- 迷茫的程序员和中国软件业
- 浏览器怎么录制网页视频?3种网页视频录制方法
- 八大经典排序算法(java版)
- 抖音短视频买的粉丝是真的吗?多少人懂这点
- JdbcTemplate报空指针异常 已解决
- 产品管理包括什么和什么_什么是产品管理?
热门文章
- 不会打字学计算机难吗,你知道你为什么学不会五笔吗 五笔难学吗
- 戴尔710服务器网卡型号怎么查,怎么看网卡驱动有问题_怎么看网卡驱动型号
- GitHub下载 无法分配请求的地址_百度网盘破限速软件PanDownload复活了!60MB/s!附下载地址...
- python中扑克牌类设计_创建扑克牌类Python
- 定时监控服务端口是否正常 发送邮件
- win10无限蓝屏_WIN10无限重启怎么解决,现在开不了机
- 摆脱五彩斑斓的黑,成为七彩程序员!
- QT3D场景快速绘制入门学习
- Java8 jdk1.8新特性
- 附解决方案,小程序用户昵称突然变成了“微信用户”,而且头像也显示不了?