C++ 滚球迷宫

2024 年 08 月 29 日 | 阅读 9 分钟

引言

迷宫 长期以来一直吸引着解谜者和游戏开发者的思维;在复杂的网格中导航、在障碍物之间穿梭并最终到达目标,这已成为一种永恒的追求。在本文中,我们将讨论如何用 C++ 创建一个迷宫导航游戏,让玩家能够引导球(也称为对象)穿过迷宫。

问题陈述

问题是创建一个基于控制台的 C++ 迷宫游戏,玩家可以通过控制(即上、下、左、右)在迷宫中导航一个球(代表对象),同时迷宫已经提供。迷宫应由二维数组表示,其中'#' 字符是墙,空白空间可以只是空白(C++ 中的大多数二维数组有'0' 和其他数字来表示实际值,在我们的二维数组中,只有' ' 表示空白空间)。迷宫的主要目标是在不碰到墙的情况下,将球从其起始位置移动到目标位置。

在此问题陈述中,给定一个大小为M x N 的二维数组maze[][],每个列都会落下一个球。迷宫的顶部和底部是开放的。覆盖每个格子两个角落的对角线墙允许将球重定向到左侧或右侧。迷宫中将球重定向到右侧的单元格符号是 "R",它跨越左上角到右下角。迷宫中将球重定向到左侧的"L" 代表一块挡板,跨越右上角到左下角。任何球都可能从底部落下或最终落入盒子。如果球撞到左右两侧的"R""L" 单元格,或者如果一个单元格将其重定向并将其送入迷宫的墙壁,球就会被困住。从顶部第 i 列放下球后,返回一个大小为 N 的数组 answer,其中 answer[i] 是球在底部落出的列,如果球被困在盒子里,则为 -1。

程序 1

让我们举一个例子来说明 C++ 中的滚球 迷宫。

输出

##########
#        #
# ### ## #
# # #  # #
# # #### #
#      # #
##### ## #
#        #
#O########
##########
Enter direction (w/a/s/d):   d

注意:输出是迷宫网格的连续显示,其中包含每次移动后球的更新位置。给定的输出是示例。

说明

1. 头文件

  • #include <iostream>: 包含此头文件是为了进行输入/输出操作。
  • #include <conio.h>: 这个头文件是 Windows 特有的,用于控制台输入。它提供了_getch() 函数,该函数从控制台读取单个字符而不回显。
  • using namespace std;: 这行使我们能够使用标准的 C++ 函数和对象,而无需在它们前面加上 std::前缀。

2. 常量

  • const int ROWS = 10; 和 const int COLS = 10;: 这些常量定义了迷宫网格的尺寸。

3. 迷宫网格

  • maze[][] 数组表示迷宫网格。它是一个字符二维数组,其中 '#' 表示墙壁,' ' 表示空格,'O' 表示球的当前位置。
  • 迷宫使用预定义的字符进行初始化,以形成简单的迷宫布局。

4. 位置结构体

  • Position struct 表示球在迷宫中的位置。它包含 x 和 y 坐标来跟踪球的位置。

5. 显示迷宫函数 (displayMaze())

  • 此函数遍历迷宫网格的每个单元格并将其内容打印到控制台。

6. isWall 函数

  • isWall() 函数检查迷宫网格中给定位置 (x, y) 是否包含墙壁 ('#')。如果是墙壁,则返回 true;否则返回 false。

7. 移动球函数 (moveBall())

  • 此函数根据用户输入在迷宫中移动球。
  • 它接受方向('w' 表示向上,'s' 表示向下,'a' 表示向左,'d' 表示向右)作为输入,并相应地更新球的位置。
  • 如果移动后的新位置不是墙壁,则更新球的位置,并更新迷宫网格以反映球的新位置。

8. 主函数

  • 主函数初始化球的起始位置(x = 1ballPos.y = 1)并相应地更新迷宫网格。
  • 之后,它进入一个无限循环,在该循环中它使用_getch() 持续监听用户输入。
  • 根据接收到的输入字符,它调用moveBall() 函数在迷宫中移动球。
  • 每次移动后,它使用system("cls")(适用于 Windows)清除控制台屏幕,并使用displayMaze() 重新显示更新后的迷宫。

9. 用户输入

  • 用户可以使用箭头键或其他指定的按键来控制球的移动,用于上、下、左、右移动。

时间和空间复杂度

时间复杂度

  • displayMaze() 函数恰好遍历迷宫网格的每个单元格一次以打印其内容。由于网格中有ROWS * COLS 个单元格,因此该函数的时间复杂度为O(ROWS * COLS)
  • moveBall() 函数根据给定方向更新球的位置。
  • 它执行一个恒定时间的操作来更新球的位置并检查新位置是否为墙壁(isWall() 函数)
  • 因此,该函数的时间复杂度为O(1)
  • 总而言之,所提供代码的整体时间复杂度是初始化和显示迷宫的 O(ROWS * COLS),加上用户与球移动交互的线性时间复杂度。

空间复杂度

  • 迷宫网格是一个尺寸为 ROWS * COLS 的字符二维数组。
  • 因此,迷宫网格的空间复杂度为 O(ROWS * COLS)。
  • ballPos struct 存储球的位置(x、y 坐标)。
  • 它需要恒定空间,O(1)
  • 变量 input 存储用于球移动的用户输入字符。
  • 它需要恒定空间,O(1)。

方法 2:网格优化问题

这是网格优化问题,可以使用动态规划来解决。逐一迭代所有球。它还维护一个dp[][] 数组,以便dp[i][j] 存储如果球出现在单元格 (i, j) 中的最终列号。

我们可以使用递归函数来查找球将落入的列,以及球通过检查球向右和向左移动的条件到达单元格时的去向。

如果当前单元格是"R" 并且不是行中的最后一个单元格,球将向右移动;同样,右侧的相邻单元格不应包含 "L"。如果当前单元格是"L" 并且不是行中的第一个单元格,球将向左移动,并且左侧的相邻单元格不应包含 "R"。

程序 2

输出

1 2 -1 -1 -1 

说明

1. 头文件

我们包含程序中需要的某些库,例如iostream(用于输入输出操作)或vector(s) 用于使用向量。

  • 命名空间:我们为了方便而使用std 命名空间。我们可以获得与标准容器和算法相关的任何内容,而无需写出 std::。

2. 函数定义

  • findColumn:该函数使用递归来查找从 m 个成本的单元格的特定点(rowNo,colNo) 处球的最终列。此函数有一些参数,例如迷宫、迷宫的大小 m 和 n、记忆化数组 dp 以及球的当前位置(rowNo, colNo)。
  • solve:在此函数中,遍历每个起始列,然后按列获取球的结束位置。将ans vector 初始化为我们的最后一个位置,并将array dp 用于记住中间结果。

3. 主函数

  • 在主函数中,我们使用提供的输入值初始化迷宫,其中'R' 表示右方向,'L' 表示左方向。
  • 之后,我们调用 solve 函数来获取每个起始列的球的最终位置。
  • 最后,我们输出球的最终位置。

4. 输入

  • 输入是一个二维字符向量,每个字符表示该单元格可能采取的方向,以便从底部行出来('r' 表示右,'l' 表示左)。

5. 输出

  • 输出包含一个整数集,表示球从底部落出的最终列,对应于每个起始列。

时间和空间复杂度

  • 时间复杂度:O(N * M),M 是迷宫的行数,N 是迷宫的列数 maze[][].
  • 辅助空间: O(N * M)

结论

总之,这个可爱的小滚球迷宫游戏是用 C++ 创建和运行的。您可以在游戏过程中通过拖动鼠标左键来倾斜整个迷宫或将其旋转(90 度),这比通常的物理效应和重力作用给您控制迷宫中的球带来了更大的挑战。

滚球迷宫游戏的代码教授了许多游戏开发、碰撞检测、用户输入处理、迷宫生成、图形渲染等方面的基本概念。但最重要的是,它让玩家在享受乐趣的同时提高空间意识、解决问题的能力和反应能力。


下一个主题C++ 基本命令