diff --git a/A8code.c b/A8code.c new file mode 100644 index 0000000..a58be68 --- /dev/null +++ b/A8code.c @@ -0,0 +1,284 @@ +#include +#include +#include +#include + +#define N 3 // 拼图的维度,这是一个3x3的拼图 + +typedef struct Node { + int puzzle[N][N]; // 存储拼图状态的数组 + struct Node *parent; // 指向父节点的指针,用于追踪路径 + int f, g, h; // A*算法中的 f, g, h 值 +} Node; + +// 创建新的拼图节点 +Node *createNode(int puzzle[N][N]) +{ + Node *newnode = (Node *)malloc(sizeof(Node)); + // 复制拼图到新节点 + memcpy(newnode->puzzle, puzzle, sizeof(int) * N * N); + newnode->parent = NULL; + newnode->f = newnode->g = newnode->h = 0; + return newnode; +} + +// 检查两个拼图状态是否相同 +bool isSamePuzzle(int a[N][N], int b[N][N]) +{ + for (int i = 0; i < N; i++) + { + for (int j = 0; j < N; j++) + { + if (a[i][j] != b[i][j]) + return false; + } + } + return true; +} + +// 打印拼图状态 +void printPuzzle(int puzzle[N][N]) +{ + for (int i = 0; i < N; i++) + { + for (int j = 0; j < N; j++) + { + printf("%-2d", puzzle[i][j]); + } + printf("\n"); + } + printf("\n"); +} + +// 启发函数,计算当前状态到目标状态的估计代价 +int heuristic(Node *current, Node *goal) +{ + int h = 0; + // 计算不匹配的拼图块数量 + for (int i = 0; i < N; i++) + { + for (int j = 0; j < N; j++) + { + if (current->puzzle[i][j] != goal->puzzle[i][j]) + h++; + } + } + return h; +} + +// 移动操作,生成新的拼图状态 +Node *move(Node *current, int dir) +{ + int key_x, key_y; // 记录空白块的位置 + + // 找到空白块的位置 + for (int i = 0; i < N; i++) + { + for (int j = 0; j < N; j++) + { + if (current->puzzle[i][j] == 0) + { + key_x = i; + key_y = j; + break; + } + } + } + + int new_x = key_x, new_y = key_y; + + // 根据移动方向更新新块的位置,上下左右移动 + switch (dir) + { + case 0: + new_x--; + break; + case 1: + new_x++; + break; + case 2: + new_y--; + break; + case 3: + new_y++; + break; + default: + break; + } + + // 检查新位置是否在边界内 + if (new_x < 0 || new_x >= N || new_y < 0 || new_y >= N) + return NULL; + + // 创建新节点,复制当前拼图状态,并交换块的位置 + Node *new_node = createNode(current->puzzle); + new_node->puzzle[key_x][key_y] = current->puzzle[new_x][new_y]; + new_node->puzzle[new_x][new_y] = 0; + + return new_node; +} + +// A*算法,寻找最短路径 +Node *AStar(Node *start, Node *goal) +{ + Node *OPEN[1000]; // 开放列表,用于存储待探索的节点 + Node *CLOSED[1000]; // 关闭列表,用于存储已探索的节点 + int OPEN_SIZE = 0; // 开放列表的大小 + int CLOSED_SIZE = 0;// 关闭列表的大小 + + OPEN[0] = start; // 将起始节点添加到开放列表 + OPEN_SIZE = 1; // 开放列表的大小设置为1 + CLOSED_SIZE = 0; // 关闭列表的大小设置为0 + + while (OPEN_SIZE > 0) + { + int min_f = OPEN[0]->f; + int min_index = 0; + // 查找开放列表中具有最小f值的节点 + for (int i = 1; i < OPEN_SIZE; i++) + { + if (OPEN[i]->f < min_f) + { + min_f = OPEN[i]->f; + min_index = i; + } + } + + Node *current = OPEN[min_index]; // 获取具有最小f值的节点 + + // 如果当前节点与目标状态匹配,表示找到解 + if (isSamePuzzle(current->puzzle, goal->puzzle)) + { + return current; + } + + // 开放列表的大小减1,表示从开放列表中移除了一个节点 + OPEN_SIZE--; + + // 将最小f值的节点移到开放列表的末尾,以便稍后将其添加到关闭列表中。 + // 这是为了优化开放列表的结构。 + Node *temp = OPEN[min_index]; + OPEN[min_index] = OPEN[OPEN_SIZE]; + OPEN[OPEN_SIZE] = temp; + + // 将当前节点添加到关闭列表,关闭列表大小加1 + CLOSED[CLOSED_SIZE++] = current; + + int key = 0; + // 查找当前节点中空白块的位置 + for (int i = 0; i < N; i++) + { + for (int j = 0; j < N; j++) + { + if (current->puzzle[i][j] == 0) + { + key = i * N + j; + break; + } + } + } + + // 尝试四个方向的移动操作 + for (int dir = 0; dir < 4; dir++) + { + Node *new_node = move(current, dir); + + if (new_node != NULL && !isSamePuzzle(new_node->puzzle, current->puzzle)) + { + int gNew = current->g + 1; + int hNew = heuristic(new_node, goal); + int fNew = gNew + hNew; + + bool in_OPEN = false; + int open_index = -1; + // 检查新节点是否在开放列表中 + for (int i = 0; i < OPEN_SIZE; i++) + { + if (isSamePuzzle(new_node->puzzle, OPEN[i]->puzzle)) + { + in_OPEN = true; + open_index = i; + break; + } + } + + bool in_CLOSED = false; + // 检查新节点是否在关闭列表中 + for (int i = 0; i < CLOSED_SIZE; i++) + { + if (isSamePuzzle(new_node->puzzle, CLOSED[i]->puzzle)) + { + in_CLOSED = true; + break; + } + } + + // 如果新节点既不在开放列表也不在关闭列表中,将其添加到开放列表 + if (!in_OPEN && !in_CLOSED) + { + new_node->g = gNew; + new_node->h = hNew; + new_node->f = fNew; + new_node->parent = current; + + OPEN[OPEN_SIZE++] = new_node; + } + // 如果新节点已经在开放列表中,但新的 f 值更小,更新开放列表中已存在节点的信息 + else if (in_OPEN && fNew < OPEN[open_index]->f) + { + OPEN[open_index]->g = gNew; + OPEN[open_index]->h = hNew; + OPEN[open_index]->f = fNew; + OPEN[open_index]->parent = current; + } + } + } + } + + return NULL; // 无解 +} + +// 打印解路径 +void printPath(Node *final) +{ + + if (final == NULL) + { + return; + } + printPath(final->parent); // 递归打印路径 + for (int i = 0; i < N; i++) + { + for (int j = 0;jpuzzle[i][j]); + } + printf("\n"); + }printf("------"); + printf("\n"); +} + +int main() +{ + int start_puzzle[N][N] = {{2, 8, 3}, {1, 6, 4}, {7, 0, 5}}; // 起始拼图状态 + int goal_puzzle[N][N] = {{1, 2, 3}, {8, 0, 4}, {7, 6, 5}}; // 目标拼图状态 + + Node *start = createNode(start_puzzle); // 创建起始节点 + Node *goal = createNode(goal_puzzle); // 创建目标节点 + + + + Node *final = AStar(start, goal); // 运行A*算法,寻找最短路径 + + if (final != NULL) + { + printf("Solution path:\n"); + printPath(final); // 打印解路径 + } + else + { + printf("No solution found.\n"); + } + + return 0; +} \ No newline at end of file