re-迷宫题学习

news2024/11/13 8:09:57

re中的迷宫问题有以下特点:

  • 在内存中布置一张 "地图"
  • 将用户输入限制在少数几个字符范围内.
  • 一般只有一个迷宫入口和一个迷宫出口

布置的地图可以由可显字符 (比如#*)组合而成 (这非常明显, 查看字符串基本就知道这是个迷宫题了.), 也可以单纯用不可显的十六进制值进行表示. 可以将地图直接组成一条非常长的字符串, 或是一行一行分开布置. 如果是一行一行分开布置的话, 因为迷宫一般都会比较大, 所以用于按行(注意, 布置并非按顺序布置, 每行都对应一个具体的行号, 你需要确定行号才能还原迷宫地图) 布置迷宫的函数会明显重复多次.

而被限制的字符通常会是一些方便记忆的组合 (不是也没办法), 比如w/s/a/d, h/j/k/l, l/r/u/d这样的类似组合. 当然各个键具体的操作需要经过分析判断 (像那种只用一条字符串表示迷宫的, 就可以用t键表示向右移动12个字符这样). 对于二维的地图, 一般作者都会设置一个X坐标和一个Y坐标用于保存当前位置. 我们也可以根据这个特点来入手分析.

一般情况下, 迷宫是只有 1 个入口和 1 个出口, 像入口在最左上角(0, 0)位置, 而出口在最右下角(max_X, max_Y)处. 但也有可能是出口在迷宫的正中心, 用一个Y字符表示等等. 解答迷宫题的条件也是需要根据具体情况判断的.

当然迷宫的走法可能不止 1 条, 也有情况是有多条走法, 但是要求某一个走法比如说代价最小. 那么这就可以变相为一个算法问题.

DFS和BFS算法讲解

深度优先遍历(Depth Fist Search)

什么是深度优先,用树来看就是从一个结点开始,沿着其中一条支路,一直搜索下去直到尽头;然后再原路返回起点,再找另一条路不断遍历下去。
用迷宫来讲的话,就是从起点开始,不断向四周的格子走,不考虑回头的话,总有到尽头的时候(终点或是一堵墙)。到尽头后,回到起点,再沿着没有走过的路走一次,不断重复这个过程。

深度优先算法有俩种实现方法,一种是利用递归实现,一种是非递归实现。

广度优先遍历(Breath First Search)

广度优先遍历指的是从图的一个未遍历的结点出发,先遍历这个点的相邻结点,再依次遍历每个相邻节点的相邻节点。
在迷宫的例子里,就是说我们按照走1步能到达的位置,走2步能到达的位置…这样的顺序逐一搜索,直到不再有能到达的位置。

深度优先利用的是栈实现,广度优先利用的是队列实现。

具体代码实现部分可以看[算法]搜索初步: 从迷宫最短路问题来理解DFS和BFS · Issue #14 · Locietta/blogs · GitHub
图文解析可以看图文详解 DFS 和 BFS

步骤和代码实现

maze

NSSCTF的 [SWPUCTF 2021 新生赛]老鼠走迷宫为例子,用深度优先遍历DFS。

maze = [
    [
        1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1],
    [
        1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1],
    [
        1, 0, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 0, 1, 0, 1],
    [
        1, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 1],
    [
        1, 0, 1, 1, 1, 1, 1, 0, 1, 0, 1, 0, 1, 0, 1, 1, 1, 1, 1, 0, 1, 1, 1, 0, 1],
    [
        1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1],
    [
        1, 1, 1, 0, 1, 1, 1, 1, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 1, 1, 1, 1, 0, 1],
    [
        1, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 1, 0, 1],
    [
        1, 0, 1, 1, 1, 0, 1, 0, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 0, 1, 0, 1],
    [
        1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 1],
    [
        1, 0, 1, 1, 1, 1, 1, 1, 1, 0, 1, 0, 1, 0, 1, 1, 1, 0, 1, 0, 1, 1, 1, 0, 1],
    [
        1, 0, 1, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1],
    [
        1, 0, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 0, 1, 0, 1, 1, 1, 0, 1, 0, 1, 1, 1],
    [
        1, 0, 0, 0, 1, 0, 1, 0, 1, 0, 0, 0, 1, 0, 1, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1],
    [
        1, 1, 1, 1, 1, 0, 1, 0, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 0, 1, 0, 1, 0, 1],
    [
        1, 0, 1, 0, 0, 0, 1, 0, 1, 0, 0, 0, 1, 0, 1, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1],
    [
        1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 1, 1, 0, 1, 1, 1, 1, 1, 0, 1, 0, 1],
    [
        1, 0, 1, 0, 1, 0, 0, 0, 1, 0, 1, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1],
    [
        1, 0, 1, 0, 1, 1, 1, 1, 1, 0, 1, 0, 1, 0, 1, 1, 1, 0, 1, 0, 1, 1, 1, 0, 1],
    [
        1, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 1, 0, 0, 0, 1, 0, 1, 0, 0, 0, 1, 0, 1],
    [
        1, 0, 1, 1, 1, 0, 1, 1, 1, 1, 1, 0, 1, 1, 1, 0, 1, 0, 1, 1, 1, 0, 1, 0, 1],
    [
        1, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 1, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1],
    [
        1, 0, 1, 0, 1, 1, 1, 0, 1, 0, 1, 0, 1, 0, 1, 1, 1, 0, 1, 0, 1, 0, 1, 0, 1],
    [
        1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1],
    [
        1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 1]]

这里有一个地方进行了修改,最后一行的倒数第二个位置原本是0,我手动修改成了2;原题有明确该坐标是出口。maze[0][1]处是入口。

具体操作

先写从当前位置前往下一个位置的限制条件;(例如,通行的要求,是否遇到墙;走到终点了)

# 添加限制条件
def check(map, x, y):
    if (x >= 0) and (x <= 24) and (y >= 0) and (y <= 24):    # 这一行检查(x,y)是否在有效范围内;
        return (map[x][y] != 1) and ((map[x][y] == 0) or (map[x][y] == 2)) 	# 这里是如果坐标在地图范围内,就检测该坐标是不是障碍物;是不是可以前进的道路或者终点;
    else:
        return False

写出当前位置四周的情况,并存入一个列表里。该列表中的每一项包含三个信息(x坐标,y坐标,前进方向)

def gen_nex(map, x, y):
    all_dir = []
    if check(map, x - 1, y):
        all_dir.append((x - 1, y, 'w'))
    if check(map, x + 1, y):
        all_dir.append((x + 1, y, 's'))
    if check(map, x, y - 1):
        all_dir.append((x, y - 1, 'a'))
    if check(map, x, y + 1):
        all_dir.append((x, y + 1, 'd'))
    return all_dir

# all_dir是一个列表,用于存储下一个可能的坐标和前进方向的信息。每个元素都是一个包含三个值的元组,格式如下:(x, y, direction)

写出DFS用递归查找路线

  • ①第一步先写判断dfs成功的条件
  • ②将访问过的值设置成其它特殊值,即我们走过一遍的地方不能再走,不然会出bug,俩个点来回横跳。
  • ③进行递归dfs调用
def check_success(map, x, y):
    if map[x][y] == 2:
        return True
    else:
        return False

def dfs(maze, x, y, path):
    map = maze.copy()    # 这里用将maze复制给map,避免修改掉原地图。
    if map[x][y] != 2:
        map[x][y] = 1
    if check_success(map, x, y):
        print(path)
        return True

    next_point = gen_nex(map, x, y)
    for n in next_point:
        pathn = path + n[2]       # 将all_dir列表中的元组的第三个值,即方向传给pathn
        dfs(map, n[0], n[1], pathn)        # 这里开始递归 用all_dir的元组第一二个值和pathn作为参数,进行当前位置的又一次深度优先遍历。

最后再加个尾巴

output = ""
dfs(maze, 0, 1, output)

直接运行

实战分析

[SWPUCTF 2021 新生赛]老鼠走迷宫

这一题是pyinstaller类的题目,前面是简单的python逆向,这里不再进行分析,直接默认分析迷宫步骤开始

在maze下面添加一个for循环,输出maze,会报错,把最下面的return none直接删了,这不是重点不要紧
修改之后的代码,可以直接输出maze

#!/usr/bin/env python
# visit https://tool.lu/pyc/ for more information
# Version: Python 3.7

import random
import msvcrt
(row, col) = (12, 12)
(i, j) = (0, 0)
maze = [
    [
        1,
        0,
        1,
        1,
        1,
        1,
        1,
        1,
        1,
        1,
        1,
        1,
        1,
        1,
        1,
        1,
        1,
        1,
        1,
        1,
        1,
        1,
        1,
        1,
        1],
    [
        1,
        0,
        1,
        0,
        0,
        0,
        0,
        0,
        0,
        0,
        0,
        0,
        0,
        0,
        0,
        0,
        0,
        0,
        0,
        0,
        0,
        0,
        1,
        0,
        1],
    [
        1,
        0,
        1,
        0,
        1,
        1,
        1,
        1,
        1,
        1,
        1,
        1,
        1,
        1,
        1,
        1,
        1,
        0,
        1,
        1,
        1,
        0,
        1,
        0,
        1],
    [
        1,
        0,
        1,
        0,
        0,
        0,
        0,
        0,
        1,
        0,
        0,
        0,
        1,
        0,
        0,
        0,
        0,
        0,
        1,
        0,
        0,
        0,
        1,
        0,
        1],
    [
        1,
        0,
        1,
        1,
        1,
        1,
        1,
        0,
        1,
        0,
        1,
        0,
        1,
        0,
        1,
        1,
        1,
        1,
        1,
        0,
        1,
        1,
        1,
        0,
        1],
    [
        1,
        0,
        0,
        0,
        1,
        0,
        0,
        0,
        1,
        0,
        1,
        0,
        1,
        0,
        1,
        0,
        1,
        0,
        0,
        0,
        1,
        0,
        0,
        0,
        1],
    [
        1,
        1,
        1,
        0,
        1,
        1,
        1,
        1,
        1,
        0,
        1,
        0,
        1,
        0,
        1,
        0,
        1,
        0,
        1,
        1,
        1,
        1,
        1,
        0,
        1],
    [
        1,
        0,
        1,
        0,
        0,
        0,
        1,
        0,
        0,
        0,
        1,
        0,
        0,
        0,
        1,
        0,
        1,
        0,
        0,
        0,
        0,
        0,
        1,
        0,
        1],
    [
        1,
        0,
        1,
        1,
        1,
        0,
        1,
        0,
        1,
        1,
        1,
        1,
        1,
        1,
        1,
        0,
        1,
        1,
        1,
        1,
        1,
        0,
        1,
        0,
        1],
    [
        1,
        0,
        0,
        0,
        0,
        0,
        1,
        0,
        0,
        0,
        0,
        0,
        1,
        0,
        0,
        0,
        0,
        0,
        1,
        0,
        1,
        0,
        0,
        0,
        1],
    [
        1,
        0,
        1,
        1,
        1,
        1,
        1,
        1,
        1,
        0,
        1,
        0,
        1,
        0,
        1,
        1,
        1,
        0,
        1,
        0,
        1,
        1,
        1,
        0,
        1],
    [
        1,
        0,
        1,
        0,
        0,
        0,
        0,
        0,
        1,
        0,
        1,
        0,
        1,
        0,
        0,
        0,
        1,
        0,
        0,
        0,
        1,
        0,
        0,
        0,
        1],
    [
        1,
        0,
        1,
        0,
        1,
        1,
        1,
        0,
        1,
        1,
        1,
        0,
        1,
        0,
        1,
        0,
        1,
        1,
        1,
        0,
        1,
        0,
        1,
        1,
        1],
    [
        1,
        0,
        0,
        0,
        1,
        0,
        1,
        0,
        1,
        0,
        0,
        0,
        1,
        0,
        1,
        0,
        0,
        0,
        1,
        0,
        1,
        0,
        1,
        0,
        1],
    [
        1,
        1,
        1,
        1,
        1,
        0,
        1,
        0,
        1,
        0,
        1,
        1,
        1,
        0,
        1,
        1,
        1,
        0,
        1,
        0,
        1,
        0,
        1,
        0,
        1],
    [
        1,
        0,
        1,
        0,
        0,
        0,
        1,
        0,
        1,
        0,
        0,
        0,
        1,
        0,
        1,
        0,
        0,
        0,
        1,
        0,
        1,
        0,
        1,
        0,
        1],
    [
        1,
        0,
        1,
        0,
        1,
        0,
        1,
        0,
        1,
        0,
        1,
        0,
        1,
        1,
        1,
        0,
        1,
        1,
        1,
        1,
        1,
        0,
        1,
        0,
        1],
    [
        1,
        0,
        1,
        0,
        1,
        0,
        0,
        0,
        1,
        0,
        1,
        0,
        1,
        0,
        0,
        0,
        1,
        0,
        0,
        0,
        1,
        0,
        0,
        0,
        1],
    [
        1,
        0,
        1,
        0,
        1,
        1,
        1,
        1,
        1,
        0,
        1,
        0,
        1,
        0,
        1,
        1,
        1,
        0,
        1,
        0,
        1,
        1,
        1,
        0,
        1],
    [
        1,
        0,
        1,
        0,
        0,
        0,
        1,
        0,
        0,
        0,
        1,
        0,
        1,
        0,
        0,
        0,
        1,
        0,
        1,
        0,
        0,
        0,
        1,
        0,
        1],
    [
        1,
        0,
        1,
        1,
        1,
        0,
        1,
        1,
        1,
        1,
        1,
        0,
        1,
        1,
        1,
        0,
        1,
        0,
        1,
        1,
        1,
        0,
        1,
        0,
        1],
    [
        1,
        0,
        1,
        0,
        0,
        0,
        1,
        0,
        0,
        0,
        1,
        0,
        1,
        0,
        0,
        0,
        1,
        0,
        1,
        0,
        1,
        0,
        1,
        0,
        1],
    [
        1,
        0,
        1,
        0,
        1,
        1,
        1,
        0,
        1,
        0,
        1,
        0,
        1,
        0,
        1,
        1,
        1,
        0,
        1,
        0,
        1,
        0,
        1,
        0,
        1],
    [
        1,
        0,
        0,
        0,
        0,
        0,
        0,
        0,
        1,
        0,
        0,
        0,
        1,
        0,
        0,
        0,
        0,
        0,
        0,
        0,
        1,
        0,
        0,
        0,
        1],
    [
        1,
        1,
        1,
        1,
        1,
        1,
        1,
        1,
        1,
        1,
        1,
        1,
        1,
        1,
        1,
        1,
        1,
        1,
        1,
        1,
        1,
        1,
        1,
        0,
        1]]
for row in maze:
    print(row)
print('Mice walk in a maze: wasd to move,q to quit')
print("flag is the shortest path's md5,example:if the shortest path is wasdsdw,the flag is md5('wasdsdw')")
(i, j) = (0, 1)
n = 0
while i == row * 2 and j == col * 2 - 1:
    print('ohhhh!!!!you did it')
    break
    print('your position:({},{})'.format(i, j))
    inp = msvcrt.getch()
    n += 1
    ti = i
    tj = j
    if b'a' == inp and i > 0:
        tj -= 1
    elif b'w' == inp and j > 0:
        ti -= 1
    elif b's' == inp and j < row * 2:
        ti += 1
    elif b'd' == inp and i < col * 2:
        tj += 1
    elif b'q' == inp:
        exit('bye!!')
    else:
        print('What???')
    if maze[ti][tj] == 1:
        print(random.choice([
            'no wayy!!',
            "it's wall",
            'nop']))
        continue
    elif maze[ti][tj] == 0:
        print(random.choice([
            'nice!!',
            'yeah!!',
            'Go on']))
        i = ti
        j = tj

接下来用上面的的DFS,这里不再重复

dirs = [(0, 1), (1, 0), (0, -1), (-1, 0)]  # 当前位置四个方向的偏移量
path = []  # 存找到的路径


def mark(maze, pos):  # 给迷宫maze的位置pos标"2"表示“倒过了”
    maze[pos[0]][pos[1]] = 2


def passable(maze, pos):  # 检查迷宫maze的位置pos是否可通行
    return maze[pos[0]][pos[1]] == 0


def find_path(maze, pos, end):
    mark(maze, pos)
    if pos == end:
        print(pos, end=" ")  # 已到达出口,输出这个位置。成功结束
        path.append(pos)
        return True
    for i in range(4):  # 否则按四个方向顺序检查
        nextp = pos[0] + dirs[i][0], pos[1] + dirs[i][1]
        # 考虑下一个可能方向
        if passable(maze, nextp):  # 不可行的相邻位置不管
            if find_path(maze, nextp, end):  # 如果从nextp可达出口,输出这个位置,成功结束
                print(pos, end=" ")
                path.append(pos)
                return True
    return False


def see_path(maze, path):  # 使寻找到的路径可视化
    for i, p in enumerate(path):
        if i == 0:
            maze[p[0]][p[1]] = "E"
        elif i == len(path) - 1:
            maze[p[0]][p[1]] = "S"
        else:
            maze[p[0]][p[1]] = 3
    print("\n")
    for r in maze:
        for c in r:
            if c == 3:
                print('\033[0;31m' + "*" + " " + '\033[0m', end="")
            elif c == "S" or c == "E":
                print('\033[0;34m' + c + " " + '\033[0m', end="")
            elif c == 2:
                print('\033[0;32m' + "#" + " " + '\033[0m', end="")
            elif c == 1:
                print('\033[0;;40m' + " " * 2 + '\033[0m', end="")
            else:
                print(" " * 2, end="")
        print()


if __name__ == '__main__':
    maze = [
        [
            1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1],
        [
            1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1],
        [
            1, 0, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 0, 1, 0, 1],
        [
            1, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 1],
        [
            1, 0, 1, 1, 1, 1, 1, 0, 1, 0, 1, 0, 1, 0, 1, 1, 1, 1, 1, 0, 1, 1, 1, 0, 1],
        [
            1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1],
        [
            1, 1, 1, 0, 1, 1, 1, 1, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 1, 1, 1, 1, 0, 1],
        [
            1, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 1, 0, 1],
        [
            1, 0, 1, 1, 1, 0, 1, 0, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 0, 1, 0, 1],
        [
            1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 1],
        [
            1, 0, 1, 1, 1, 1, 1, 1, 1, 0, 1, 0, 1, 0, 1, 1, 1, 0, 1, 0, 1, 1, 1, 0, 1],
        [
            1, 0, 1, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1],
        [
            1, 0, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 0, 1, 0, 1, 1, 1, 0, 1, 0, 1, 1, 1],
        [
            1, 0, 0, 0, 1, 0, 1, 0, 1, 0, 0, 0, 1, 0, 1, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1],
        [
            1, 1, 1, 1, 1, 0, 1, 0, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 0, 1, 0, 1, 0, 1],
        [
            1, 0, 1, 0, 0, 0, 1, 0, 1, 0, 0, 0, 1, 0, 1, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1],
        [
            1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 1, 1, 0, 1, 1, 1, 1, 1, 0, 1, 0, 1],
        [
            1, 0, 1, 0, 1, 0, 0, 0, 1, 0, 1, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1],
        [
            1, 0, 1, 0, 1, 1, 1, 1, 1, 0, 1, 0, 1, 0, 1, 1, 1, 0, 1, 0, 1, 1, 1, 0, 1],
        [
            1, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 1, 0, 0, 0, 1, 0, 1, 0, 0, 0, 1, 0, 1],
        [
            1, 0, 1, 1, 1, 0, 1, 1, 1, 1, 1, 0, 1, 1, 1, 0, 1, 0, 1, 1, 1, 0, 1, 0, 1],
        [
            1, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 1, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1],
        [
            1, 0, 1, 0, 1, 1, 1, 0, 1, 0, 1, 0, 1, 0, 1, 1, 1, 0, 1, 0, 1, 0, 1, 0, 1],
        [
            1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1],
        [
            1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1]]
    start = (0, 1)
    end = (24, 23)
    find_path(maze, start, end)
    see_path(maze, path)

NSSCTF [GDOUCTF 2023]润!

UPX壳但是是魔改过的upx壳,将FUK都改成UPX就好;再看就是正常的upx壳了,用upx -d

之后用IDA分析就好,直接反汇编来看主函数

init是创建迷宫, 让我们输入长度为31的字符串,moving是在迷宫中的移动,这里的511是个hint

init点进去看看

这里具体迷宫的生成具体可以不用在意,可以明显看出这是一个 8 * 8大小的迷宫;

moving这里是三维的,还有上下楼这种操作。注意看:在case ‘u’:处又调用了一次init创建了一个迷宫,还有layer也是个hint,layer是层的意思,这里就是有八层。 8 * 8 * 8 = 512 ;即意味着我们的终点就是左下角的位置,511;起点是一楼的左上角。我觉得难点就在这了,后面就按部就班。

哦还有,需要动态调试,输入uuuuuuuuuuuuuuuuuuuu就好,连续创建七次迷宫,将迷宫copy出来就好,4015CE下断点

x表示楼层,y是w和s表示行,z是列。

maze = [0, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1,
        1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
        1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0,
        1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
        1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 1, 0, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1,
        1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
        1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
        1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
        1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 0, 0, 1,
        1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
        1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1,
        1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 0, 0, 1, 1, 1, 1, 1, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
        1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
        1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
        1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
        1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 2]


# maze[x * 64 + y * 8 + z]
def check_point_valid(map, x, y, z):
    if (x >= 0) and (x <= 7) and (y >= 0) and (y <= 7) and (z >= 0) and (z <= 7):
        return (map[x * 64 + y * 8 + z] != 1) and ((map[x * 64 + y * 8 + z] == 0) or (map[x * 64 + y * 8 + z] == 2))
    else:
        return False


def gen_nex(map, x, y, z):
    all_dir = []
    if check_point_valid(map, x - 1, y, z):
        all_dir.append((x - 1, y, z, 'n'))
    if check_point_valid(map, x + 1, y, z):
        all_dir.append((x + 1, y, z, 'u'))
    if check_point_valid(map, x, y - 1, z):
        all_dir.append((x, y - 1, z, 'w'))
    if check_point_valid(map, x, y + 1, z):
        all_dir.append((x, y + 1, z, 's'))
    if check_point_valid(map, x, y, z - 1):
        all_dir.append((x, y, z - 1, 'a'))
    if check_point_valid(map, x, y, z + 1):
        all_dir.append((x, y, z + 1, 'd'))
    return all_dir


def check_success(map, x, y, z):
    if map[x * 64 + y * 8 + z] == 2:
        return True
    else:
        return False


def dfs(mapb, x, y, z, path):
    map = mapb.copy()
    if map[x * 64 + y * 8 + z] != 2:
        map[x * 64 + y * 8 + z] = 1
    if check_success(map, x, y, z):
        print(path)
        return True

    next_point = gen_nex(map, x, y, z)
    for n in next_point:
        pathn = path + n[3]
        dfs(map, n[0], n[1], n[2], pathn)


outpus = ""
dfs(maze, 0, 0, 0,  outpus)

BUUCTF:[HDCTF2019]Maze

前面正常的upx32,脱壳

进去发现函数不完整,解析也出现错误,分析一下有花指令的干扰,直接去花

花指令,nop掉他!这里call直接nop就好

nop完后,全选红色的地址用p键得到main函数,再次反编译

现在就是找地图了,查看字符串

没有找到迷宫的规模在哪里,结合一共有70个字符,而且一共走了14步,asc_408078 = 5,dword_40807C = -4,可以大概猜出 7 * 10 的迷宫大小。

可知起始:408078=7 40807c=0(即+(7,0)),结束:408078=5 40807c=-4(F(5,-4)),画出地图。(a:左,s:下,d:右,w:上)

EXP:

map = ['*', '*', '*', '*', '*', '*', '*', '+', '*', '*', '*', '*', '*', '*', '*', '*', '*', ' ', '*', '*', '*', '*', '*', '*', ' ', ' ', ' ', ' ', '*', '*', '*', '*', ' ', ' ', ' ', '*', '*', '*', '*', '*', '*', '*', ' ', '*', '*', 'F', '*', '*', '*', '*', '*', '*', ' ', ' ', ' ', ' ', '*', '*', '*', '*', '*', '*', '*', '*', '*', '*', '*', '*', '*', '*']


# 添加限制条件
def check(map, x, y):
    if (x >= 0) and (x <= 7) and (y >= 0) and (y <= 9):    # 这一行检查(x,y)是否在有效范围内;
        return (map[10 * x + y] != '*') and ((map[10 * x + y] == ' ') or (map[10 * x + y] == 'F')) 	# 这里是如果坐标在地图范围内,就检测该坐标是不是障碍物;是不是可以前进的道路或者终点;
    else:
        return False

def gen_nex(map, x, y):
    all_dir = []
    if check(map, x - 1, y):
        all_dir.append((x - 1, y, 'w'))
    if check(map, x + 1, y):
        all_dir.append((x + 1, y, 's'))
    if check(map, x, y - 1):
        all_dir.append((x, y - 1, 'a'))
    if check(map, x, y + 1):
        all_dir.append((x, y + 1, 'd'))
    return all_dir
# all_dir是一个列表,用于存储下一个可能的坐标和前进方向的信息。每个元素都是一个包含三个值的元组,格式如下:(x, y, direction)


def check_success(map, x, y):
    if map[10 * x + y] == 'F':
        return True
    else:
        return False

def dfs(maze, x, y, path):
    map = maze.copy()    # 这里用将maze复制给map,避免修改掉原地图。
    if map[10 * x + y] != 'F':
        map[10 * x + y] = 1
    if check_success(map, x, y):
        print(path)
        return True

    next_point = gen_nex(map, x, y)
    for n in next_point:
        pathn = path + n[2]       # 将all_dir列表中的元组的第三个值,即方向传给pathn
        dfs(map, n[0], n[1], pathn)        # 这里开始递归 用all_dir的元组第一二个值和pathn作为参数,进行当前位置的又一次深度优先遍历。

output = ""
dfs(map, 0, 7, output)

2019华南师大CTF新生赛maze

题目地址:https://github.com/scnu-sloth/hsctf-2019-freshmen

找走迷宫的规则和方法,点开check函数看到

分析可知:这是一个含14*12的迷宫;'*'是迷宫的墙;'#'是迷宫终点

d为向右走一步;s为向右13步,在本二维数组中为向左下方一步或向右13步;w为向右上方一步或向左13步;a为向左一步

exp,直接借用了师傅BSF的算法:

#include<bits/stdc++.h>
using namespace std;
char mp[12*15];
int vis[12*15];
int dir[4]={1,-1,13,-13};
char S[4]={'d','a','s','w'};
struct node
{
	int x;
	string s;
};
queue<node> Q;
void bfs()
{
	node tmp;
	tmp.x=15;tmp.s="";
	Q.push(tmp);
	while(!Q.empty())
	{
		node now=Q.front();
		Q.pop();
		vis[now.x]=1;
		if(mp[now.x]=='#')
		{
			cout<<"flag{"<<now.s<<"}"<<endl;
			return;
		}
		for(int k=0;k<4;k++)
		{
			int ux=now.x+dir[k];
			if(ux<1||ux>168||mp[ux]=='X'||vis[ux]==1)
			continue;
			tmp.x=ux;
			tmp.s=now.s+S[k];
			Q.push(tmp);
		}
	}
}
int main()
{
	int t=0;
	for(int i=1;i<=12;i++)
	{
		for(int j=1;j<=14;j++)
		{
			cin>>mp[++t];
		}
	}
	memset(vis,0,sizeof(vis));
	bfs();
	return 0;
}

还有突然发现了169 个字符,不就是 13 的平方,发现了13*13也对,上下左右就出来了,直接画个图就可以手解

flag{sssssdsssddsdddwwdwwaaaw}

攻防世界新手区  NJUPT CTF 2017 maze

64位ELF文件,无壳,先扔入IDA中查看伪代码

分析代码:

  puts("Input flag:");
  scanf("%s", &input_flag, 0LL);
  if ( strlen(&input_flag) != 24 || strncmp(&input_flag, "nctf{", 5uLL) || *(&byte_6010BF + 24) != '}' )		//这里要求输入的flag是24个字符,且前5个和最后一个都确定了
  {
LABEL_22:
    puts("Wrong flag!");
    exit(-1);
  }
  v3 = 5LL;
  if ( strlen(&input_flag) - 1 > 5 )		 
  {

    while ( 1 )
    {
      singleflag = *(&input_flag + v3);         // 这里v3是从5开始递增的数,目的是从第5个字符开始判断是否符合下述条件
      v5 = 0;
      if ( singleflag > 78 )	//这里给个范围,ASCII码大于78的划为第一类
      {
        singleflag = (unsigned __int8)singleflag;
        if ( (unsigned __int8)singleflag == 'O' )//如果第一个取O
        {
          v6 = sub_400650((_DWORD *)&v9 + 1);   
          goto LABEL_14;
        }
        if ( singleflag == 'o' )//如果第一个取o
        {
          v6 = sub_400660((int *)&v9 + 1);      // 有符号32位高字节操作,r15寄存器
          goto LABEL_14;
        }
      }
      else
      {
        singleflag = (unsigned __int8)singleflag;
        if ( (unsigned __int8)singleflag == '.' )//如果取到.
        {
          v6 = sub_400670(&v9);                 // 无符号底字节32位操作,r14寄存器
          goto LABEL_14;
        }
        if ( singleflag == '0' )
        {
          v6 = sub_400680((int *)&v9);          // 有符号底字节32位,r14寄存器
LABEL_14:
          v5 = v6;
          goto LABEL_15;
        }
      }
LABEL_15:
      if ( !(unsigned __int8)sub_400690((__int64)asc_601060, SHIDWORD(v9), v9) )
        goto LABEL_22;
      if ( ++v3 >= strlen(&input_flag) - 1 )   //在flag范围内v3加1,对应前面singleflag取第6、7、8~个一个个比较
      {
        if ( v5 )		//如果flag取完了,且sub_这些函数没有返回flase,也就是没有越界,就可以判断是否抵达终点了
          break;
LABEL_20:
        v7 = "Wrong flag!";
        goto LABEL_21;
      }
    }
  }
  if ( asc_601060[8 * (signed int)v9 + SHIDWORD(v9)] != '#' )	  //判断是否为#这个终点。
    goto LABEL_20;
  v7 = "Congratulations!";
LABEL_21:
  puts(v7);
  return 0LL;
}

由伪代码可见,这是个8*8的迷宫,有四个判断条件,分别进入了四个函数。
‘O’,‘o’,‘0’,’.'这四个字符分别控制不同方向
O左,o右,0下,.上
四个方向函数如下

bool __fastcall sub_400650(_DWORD *a1)//O
{
  int v1; // eax

  v1 = (*a1)--;//向左一步
  return v1 > 0;//防止越界
}
bool __fastcall sub_400660(int *a1)//o
{
  int v1; // eax

  v1 = *a1 + 1;//向右一步
  *a1 = v1;
  return v1 < 8;
}
bool __fastcall sub_400670(_DWORD *a1)//.
{
  int v1; // eax

  v1 = (*a1)--;//向上一步
  return v1 > 0;
}
bool __fastcall sub_400680(int *a1)//0
{
  int v1; // eax

  v1 = *a1 + 1;
  *a1 = v1;//向下一步
  return v1 < 8;
}

怎么分辨v9和v10各自控制的是上下还是左右呢?
点开sub_400690函数,看到

__int64 __fastcall sub_400690(__int64 a1, int a2, int a3)
{//a1是数组的首地址,a2是v10,a3是v9
  __int64 result; // rax

  result = *(unsigned __int8 *)(a1 + a2 + 8LL * a3);//a3乘以8表明v9在二维数组中表示上下
  LOBYTE(result) = (_DWORD)result == ' ' || (_DWORD)result == '#';
  return result;
}

得知v9表示行,就是控制上下。v10表示列,就是控制左右。
而且只有‘ ’ 和#可以走,否则返回return 0。’*'是迷宫的墙。
写代码生成迷宫,0可走,X为墙。

找到类似迷宫的字符串

exp:

import numpy as np
q='nctf{'
h='}'
asc='  *******   *  **** * ****  * ***  *#  *** *** ***     *********'
mg=np.array(list(asc))
print(str(mg.reshape(int(len(asc)/8),8)).replace('\'',''))
# [[    * * * * * *]
#  [*       *     *]
#  [* * *   *   * *]
#  [* *     *   * *]
#  [*     * #     *]
#  [* *   * * *   *]
#  [* *           *]
#  [* * * * * * * *]]
mid_str='右下右右下下左下下下右右右右上上左左'.replace('上','.').replace('下','0').replace('左','O').replace('右','o')
print(q+mid_str+h)

BUUCTF:不一样的flag

拖进IDA查看main函数

int __cdecl __noreturn main(int argc, const char **argv, const char **envp)
{
  char v3[29]; // [esp+17h] [ebp-35h] BYREF
  int v4; // [esp+34h] [ebp-18h]
  int v5; // [esp+38h] [ebp-14h] BYREF
  int i; // [esp+3Ch] [ebp-10h]
  _BYTE v7[12]; // [esp+40h] [ebp-Ch] BYREF

  __main();
  v4 = 0;
  strcpy(v3, "*11110100001010000101111#");//这就是迷宫
  while ( 1 )
  {
    puts("you can choose one action to execute");
    puts("1 up");
    puts("2 down");
    puts("3 left");
    printf("4 right\n:");//控制方向
    scanf("%d", &v5);
    if ( v5 == 2 )
    {
      ++*(_DWORD *)&v3[25];
    }
    else if ( v5 > 2 )
    {
      if ( v5 == 3 )
      {
        --v4;
      }
      else
      {
        if ( v5 != 4 )
LABEL_13:
          exit(1);
        ++v4;
      }
    }
    else
    {
      if ( v5 != 1 )
        goto LABEL_13;
      --*(_DWORD *)&v3[25];
    }
    for ( i = 0; i <= 1; ++i )
    {
      if ( *(int *)&v3[4 * i + 25] < 0 || *(int *)&v3[4 * i + 25] > 4 )
        exit(1);
    }
    if ( v7[5 * *(_DWORD *)&v3[25] - 41 + v4] == '1' )
      exit(1);//是个5*5的迷宫且1为墙
    if ( v7[5 * *(_DWORD *)&v3[25] - 41 + v4] == '#' )
    {//‘#’是迷宫终点
      puts("\nok, the order you enter is the flag!");
      exit(0);
    }
  }
}

显然是一道迷宫题。
1,2,3,4分别控制上下左右

走迷宫即可

参考资料:

迷宫问题 - CTF Wiki (ctf-wiki.org)

bugku上一道迷宫逆向题的分析 - 『脱壳破解区』 - 吾爱破解 - LCG - LSG |安卓破解|病毒分析|www.52pojie.cn

逆向迷宫题总结(持续更新) 2020华南师大CTF新生赛maze,攻防世界新手区:NJUPT CTF 2017,BUUCTF:不一样的flag_ctf lostmaze-CSDN博客

CTF-Reverse 迷宫地图类题目分析‘‘DFS和BFS算法‘‘(学习笔记)【详】_ctf 迷宫-CSDN博客【2021.12.28】ctf逆向中的迷宫问题(含exe及wp)_ctf迷宫-CSDN博客CTF-Reverse 迷宫地图类题目分析‘‘DFS和BFS算法‘‘(学习笔记)【详】_ctf 迷宫-CSDN博客

[算法]搜索初步: 从迷宫最短路问题来理解DFS和BFS · Issue #14 · Locietta/blogs (github.com)

【bugku】【ZSCTF】【迷宫RE】Take The Maze WriteUp - Reddest - 博客园 (cnblogs.com)

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

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

相关文章

冷链物流温度监测解决方案,确保从生产端到患者端的制药供应链合规性和产品稳定性

全球制药、医疗保健、生命科学和生物制品物流市场 先进疗法&#xff08;细胞和基因&#xff09;和生物制剂的生产线非常庞大。由于高度个性化&#xff0c;这些医疗方法大多需要高质量的超低温储存和运输。这些疗法的冷冻或运输过程中的任何一个失误都可能关乎到患者的生命安全。…

Milvus向量库安装部署

GitHub - milvus-io/milvus-sdk-java: Java SDK for Milvus. 1、安装Standstone 版本 参考&#xff1a;Linux之milvus向量数据库安装_milvus安装-CSDN博客 参考&#xff1a;Install Milvus Standalone with Docker Milvus documentation 一、安装步骤 1、安装docker docke…

【开源】SpringBoot框架开发婚恋交友网站

目录 一、摘要1.1 项目介绍1.2 项目录屏 二、功能模块2.1 数据中心模块2.2 会员管理模块2.3 新闻管理模块2.4 相亲大会管理模块2.5 留言管理模块 三、系统设计3.1 用例设计3.2 数据库设计3.2.1 会员信息表3.2.2 新闻表3.2.3 相亲大会表3.2.4 留言表 四、系统展示五、核心代码5.…

六、回归与聚类算法 - 岭回归

目录 1、带有L2正则化的线性回归 - 岭回归 1.1 API 2、正则化程度的变化对结果的影响 3、波士顿房价预测 线性回归欠拟合与过拟合线性回归的改进 - 岭回归分类算法&#xff1a;逻辑回归模型保存与加载无监督学习&#xff1a;K-means算法 1、带有L2正则化的线性回归 - 岭回…

day53 String

创建String 对象 String s "abc"; String s new String(); String的常用方法 长度方法 length(); 比较方法 equals() equalsIgnoreCase() 忽略大小写比较 compareTo() compareToIgnoreCase() 比较是否相等 基本类型比较数值是否相等 引用类型比较两个引用是…

【MATLAB源码-第144期】基于matlab的蝴蝶优化算法(BOA)无人机三维路径规划,输出做短路径图和适应度曲线。

操作环境&#xff1a; MATLAB 2022a 1、算法描述 ​蝴蝶优化算法&#xff08;Butterfly Optimization Algorithm, BOA&#xff09;是基于蝴蝶觅食行为的一种新颖的群体智能算法。它通过模拟蝴蝶个体在寻找食物过程中的嗅觉导向行为以及随机飞行行为&#xff0c;来探索解空间…

应对电脑重新分区文件消失:预防措施、常见成因与恢复关键要点

电脑重新分区文件不见了是一个常见的问题&#xff0c;通常发生在用户对硬盘进行重新分区、格式化或操作系统重装过程中&#xff0c;可能导致已存在的文件和数据暂时不可见或永久丢失。 **预防文件丢失的方法&#xff1a;** 1. **提前备份**: 在进行任何重大磁盘操作前&#xff…

EXCEL 在列不同单元格之间插入N个空行

1、第一步数据&#xff0c;要求在每个数字之间之间插入3个空格 2、拿数据个数*&#xff08;要插入空格数1&#xff09; 19*4 3、填充 4、复制数据到D列 5、下拉数据&#xff0c;选择复制填充这样1-19就会重复4次 6、全选数据D列排序&#xff0c;这样即完成了插入空格 以…

SQLite 的使用

SQLite 是一个轻量级、自包含和无服务器的关系型数据库管理系统&#xff08;RDBMS&#xff09;&#xff0c;广泛应用于嵌入式系统、移动应用程序和小中型网站。它易于创建、需要的配置较少&#xff0c;并且提供了用于管理和操作数据的强大功能集。本文&#xff0c;我们将带领你…

mysql 自定义函数create function

方便后续查询&#xff0c;做以下记录&#xff1b; 自定义函数是一种与存储过程十分相似的过程式数据库对象&#xff0c; 它与存储过程一样&#xff0c;都是由 SQL 语句和过程式语句组成的代码片段&#xff0c;并且可以被应用程序和其他 SQL 语句调用。 自定义函数与存储过程之间…

「递归算法」:求根节点到叶节点数字之和

一、题目 给你一个二叉树的根节点 root &#xff0c;树中每个节点都存放有一个 0 到 9 之间的数字。 每条从根节点到叶节点的路径都代表一个数字&#xff1a; 例如&#xff0c;从根节点到叶节点的路径 1 -> 2 -> 3 表示数字 123 。 计算从根节点到叶节点生成的 所有数…

MyBatis参数处理和查询语句专题

MyBatis参数处理和查询语句专题 一、MyBatis参数处理1.单个简单类型参数2.单个Map参数3.单个实体类参数4.多参数5.Param注解&#xff08;命名参数&#xff09; 二、MyBatis查询语句专题1.结果映射&#xff08;1&#xff09;as 给列起别名&#xff08;2&#xff09;使⽤resultMa…

【C++】STL容器之string(迭代器,范围for)

&#x1f490; &#x1f338; &#x1f337; &#x1f340; &#x1f339; &#x1f33b; &#x1f33a; &#x1f341; &#x1f343; &#x1f342; &#x1f33f; &#x1f344;&#x1f35d; &#x1f35b; &#x1f364; &#x1f4c3;个人主页 &#xff1a;阿然成长日记 …

ChatGPT回答模式

你发现了吗&#xff0c;ChatGPT的回答总是遵循这些类型方式。 目录 1.解释模式 2.类比模式 3.列举模式 4.限制模式 5.转换模式 6.增改模式 7.对比模式 8.翻译模式 9.模拟模式 10.推理模式 1.解释模式 ChatGPT 在回答问题或提供信息时&#xff0c;不仅仅给出…

【C++私房菜】面向对象中的简单继承

文章目录 一、 继承基本概念二、派生类对象及派生类向基类的类型转换三、继承中的公有、私有和受保护的访问控制规则四、派生类的作用域五、继承中的静态成员 一、 继承基本概念 通过继承&#xff08;inheritance&#xff09;联系在一起的类构成一种层次关系。通常在层次关系的…

2.22 作业

顺序表 运行结果 fun.c #include "fun.h" seq_p create_seq_list() {seq_p L (seq_p)malloc(sizeof(seq_list));if(LNULL){printf("空间申请失败\n");return NULL;}L->len 0; bzero(L,sizeof(L->data)); return L; } int seq_empty(seq_p L) {i…

音频声波的主观感受

一、响度 声压是“客观”的&#xff0c;响度是“主观”的。 响度又称音量。人耳感受到的声音强弱&#xff0c;它是人对声音大小的一个主观感觉量。响度的大小决定于声音接收处的波幅&#xff0c;就同一声源来说&#xff0c;波幅传播的愈远&#xff0c;响度愈小…

mybatis 集成neo4j实现

文章目录 前言一、引入jar包依赖二、配置 application.properties三、Mybatis Neo4j分页插件四、Mybatis Neo4j自定义转换器handler五、MybatisNeo4j代码示例总结 前言 MyBatis是一个基于Java语言的持久层框架&#xff0c;它通过XML描述符或注解将对象与存储过程或SQL语句进行…

面试必问!JVM 不得不说的知识点(三)

一、 JVM指令集: 1. 了解Java虚拟机的指令集是什么?举例说明一些常见的指令及其作用。 Java虚拟机的指令集是一组用于执行Java程序的低级操作码。这些指令直接在Java虚拟机上执行,可以认为是Java程序的二进制表示形式。以下是一些常见的Java虚拟机指令及其作用的例子: ic…

微信小程序 ---- 生命周期

目录 生命周期 1. 小程序运行机制 2. 小程序更新机制 3. 生命周期介绍 4. 应用级别生命周期 5. 页面级别生命周期 6. 生命周期两个细节补充说明 7. 组件生命周期 总结 生命周期 1. 小程序运行机制 冷启动与热启动&#xff1a; 小程序启动可以分为两种情况&#xff0…