最近在家闲得蛋疼,写个控制台的2048游戏玩玩。

操作:方向键控制移动方向。R键显示上步操作记录。

源代码很简单

    static void Main(string[] args)
    {
            Game.R = 4;
            Game.C = 4;

            var game = new Game();

            while (true)
            {
                game.Show();

                var key = Console.ReadKey();
                switch (key.Key)
                {
                    case ConsoleKey.UpArrow:
                        game.Move(MoveDirection.Up);
                        break;
                    case ConsoleKey.DownArrow:
                        game.Move(MoveDirection.Down);
                        break;
                    case ConsoleKey.RightArrow:
                        game.Move(MoveDirection.Right);
                        break;
                    case ConsoleKey.LeftArrow:
                        game.Move(MoveDirection.Left);
                        break;
                    case ConsoleKey.R:
                        game.ShowPre = !game.ShowPre;
                        break;

                }
                if (game.State == GameState.None) continue;

                game.Show();

                var res = MessageBox.Show("需要重新开始吗?", game.State == GameState.Succ ? "恭喜你!!!成功过关!!!" : "很遗憾!!!失败了!!!",MessageBoxButtons.YesNo);
                if (res == DialogResult.Yes)
                {
                    game.Restart();
                    continue;
                }
                break;
            }

            Console.ReadKey();
        }

Game类:算法核心就是两个Move方法。思路就是不管哪个方向,都是通用的算法,通过参数控制具体流程。

 

    public enum MoveDirection{
        Up,
        Down,
        Left,
        Right
    }

    public enum GameState
    {
        None,
        Fail,
        Succ,
    }

    public class Game
    {
        public static int R = 4, C = 4;

        private int[,] _bs;
        private Random _rnd = new Random();
        public GameState State = GameState.None;
        public int Score, Steps;
        public (MoveDirection direction, int[,] data)? Log;
        public bool ShowPre;

        public Game()
        {
            Restart(); 
        } 

        public unsafe void Move(MoveDirection direction)
        {
            if (State != GameState.None) return;
             
            var move = false;
            var bs = (int[,])_bs.Clone();

            switch (direction)
            {
                case MoveDirection.Up:
                    move = Move(C, 0, R - 1, 1, (x, y) => {
                        fixed (int* _ = &_bs[0, 0])
                        {
                            return (IntPtr)(_ + y * C + x);
                        }
                    });
                    break;
                case MoveDirection.Down:
                    move = Move(C, R - 1, 0, -1, (x, y) => {
                        fixed (int* _ = &_bs[0,0])
                        {
                            return (IntPtr)(_ + y * C + x);
                        }
                    });
                    break;
                case MoveDirection.Left:
                    move = Move(R, 0, C - 1, 1, (x, y) => {
                        fixed (int* _ = &_bs[0, 0])
                        {
                            return (IntPtr)(_ + x * C + y);
                        }
                    });
                    break;
                case MoveDirection.Right:
                    move = Move(R, C - 1, 0, -1, (x,y)=> { 
                        fixed(int* _ = &_bs[0, 0])
                        {
                            return (IntPtr)(_ + x * C + y);
                        }
                    });
                    break;
            }

            if (move && State != GameState.Succ)
            { 
                Steps++;

                Log = (direction, bs);

                //有移动 随机中空位生成数字
                var emptyNum = GenerateNum();

                //判断是否结束
                if(emptyNum == 0) CheckGame();
            }
        }

        private void CheckGame()
        {
            //是否已经填满 并且无法移动
            for (int x = 0; x < R; x++)
            {
                for (int y = 0; y < C; y++)
                {
                    if (y < C - 1 && _bs[x, y] == _bs[x, y + 1]) return;
                    if (x < R - 1 && _bs[x, y] == _bs[x + 1, y]) return;
                }
            }

            State = GameState.Fail;
        }

        private int GenerateNum()
        {
            var ls = new List<(int x, int y)>(R * C);
            for (int x = 0; x < R; x++)
            {
                for (int y = 0; y < C; y++)
                {
                    if (_bs[x, y] == 0) ls.Add((x,y));
                }
            }

            Shuffle(ls);

            var xy = ls[_rnd.Next(ls.Count)];
            _bs[xy.x, xy.y] = _rnd.Next(10) == 9 ? 4 : 2;
            return ls.Count - 1;

        }

        private IList<T> Shuffle<T>(IList<T> arr)
        {
            for (var i = 0; i < arr.Count; i++)
            {
                var index = _rnd.Next(arr.Count);
                var tmp = arr[i];
                arr[i] = arr[index];
                arr[index] = tmp;
            }

            return arr;
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="si">开始索引</param>
        /// <param name="ei">结束索引</param>
        /// <param name="step">方向</param>
        /// <param name="getInt">取值(重定义[x,y]可以保持算法通用 同时满足x,y方向的移动)</param>
        /// <returns></returns>
        private unsafe bool Move(int loop, int si, int ei, int step, Func<int, int, IntPtr> getInt)
        { 
            //算法基于左向移动

            bool moved = false;
          
            for (int x = 0; x < loop; x++)
            {  
                //第一步 相同的进行合并
                for (int y = si; y != ei; y+=step)
                {
                    var val1 = (int*)getInt(x, y);

                    if (*val1 != 0)
                    {
                        for (int y2 = y + step; y2 != ei + step; y2 += step)
                        {
                            var val2 = (int*)getInt(x, y2);

                            if (*val1 == *val2)
                            {
                                *val1 *= 2;
                                *val2 = 0;
                                moved = true;

                                Score += *val1;

                                if (*val1 == 2048) State = GameState.Succ;
                                break;
                            }
                            else if(*val2 != 0) break;
                        }
                    } 

                }

                //第二步 往0位上移动
                for (int y = si; y != ei; y += step)
                {
                    var val1 = (int*)getInt(x, y);

                    if (*val1 == 0)
                    {
                        int y2 = y + step; 
                        for (; y2 != ei + step; y2 += step)
                        {
                            var val2 = (int*)getInt(x, y2);

                            if (*val2 != 0)
                            {
                                *val1 = *val2;
                                *val2 = 0;
                                moved = true;

                                break;

                            }
                        }

                        if (y2 == ei) break;
                    } 
                }
            } 

            return moved;
        } 

        /// <summary>
        /// 重启游戏
        /// </summary>
        public void Restart()
        {
            Score = Steps = 0;
            State = GameState.None;
            Log = null;

            _bs = new int[R, C];

            for (int i = 0; i < 2; i++)
            {
                var x = _rnd.Next(R);
                var y = _rnd.Next(C);
                if (_bs[x, y] == 0) _bs[x, y] = _rnd.Next(10) == 0 ? 4 : 2;
                else i--;
            }
        }

        public void RandNum()
        {
            for (int x = 0; x < R; x++)
            {
                for (int y = 0; y < C; y++)
                {
                    _bs[x, y] = (int)Math.Pow(2, _rnd.Next(12));
                } 
            }
        }
         
        public void Show()
        {
            Console.SetCursorPosition(0, 0);

            Console.WriteLine($"得分:{Score} 步数:{Steps} [R]键显示上一步操作记录(当前:{ShowPre})          ");

            Console.WriteLine();


            Console.WriteLine(new string('-', C * 5));
            for (int x = 0; x < R; x++)
            {
                for (int y = 0; y < C; y++)
                {
                    var b = _bs[x, y];
                    Console.Write($"{(b == 0 ? " " : b.ToString()),4}|");
                } 
                Console.WriteLine();
                Console.WriteLine(new string('-', C * 5)); 
            }

            if (ShowPre && Log != null)
            {
                Console.WriteLine();
                Console.WriteLine(new string('=', 100));
                Console.WriteLine();
                 
                var bs = Log?.data;

                Console.WriteLine($"方向:{Log?.direction}             ");
                Console.WriteLine();

                Console.WriteLine(new string('-', C * 5));
                for (int x = 0; x < R; x++)
                {
                    for (int y = 0; y < C; y++)
                    {
                        var b = bs[x, y];
                        Console.Write($"{(b == 0 ? " " : b.ToString()),4}|");
                    }
                    Console.WriteLine();
                    Console.WriteLine(new string('-', C * 5));
                } 
            }

        }

    }

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值