You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
aaa/ConsoleApplication.c

290 lines
8.0 KiB

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
#include <string.h>
#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));
//请实现该函数
// 用 malloc 函数在内存中分配空间
// 将 puzzle 数组的值复制到新节点的 puzzle 数组中
for (int i = 0; i < N; i++) {
for (int j = 0; j < N; j++) {
newnode->puzzle[i][j] = puzzle[i][j];
}
}
// 初始化新节点的 parent 节点为 NULL
newnode->parent = NULL;
// 初始化新节点的 f, g, h 的值为 0
newnode->f = 0;
newnode->g = 0;
newnode->h = 0;
// 返回指向新节点的指针
return newnode;
}
// 检查两个拼图状态是否相同
bool isSamePuzzle(int a[N][N], int b[N][N]) {
//相同则返回true,否则返回false
for (int i = 0; i < N; i++) {
for (int j = 0; j < N; j++) {
// 如果有任何一个元素不相同,则返回 false
if (a[i][j] != b[i][j]) {
return false;
}
}
}
return true;
// 如果所有元素都相同,则返回 true
}
// 打印拼图状态
void printPuzzle(int puzzle[N][N]) {
//双重for循环实现拼图的打印
for (int i = 0; i < N; i++) {
for (int j = 0; j < N; j++) {
// 打印每个元素,并在元素间空一格
printf("%d ", puzzle[i][j]);
}
// 换行
printf("\n");
}
// 打印额外的换行,提高输出的可读性
printf("\n");
}
// 启发函数,计算当前状态到目标状态的估计代价
int heuristic(Node* current, Node* goal) {
int h = 0;
// 计算不匹配的拼图块数量
// 利用双重 for 循环计算遍历两节点的 puzzle 数组,若不匹配则 h 加 1
for (int i = 0; i < N; i++) {
for (int j = 0; j < N; j++) {
if (current->puzzle[i][j] != goal->puzzle[i][j]) {
h++;
}
}
}
// 返回 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;
}
}
}
// 给 new_x、new_y 赋值
int new_x = key_x;
int new_y = key_y;
// 根据移动方向更新新块的位置,上下左右移动
if (dir == 0) { // 上移
new_x--;
}
else if (dir == 1) { // 下移
new_x++;
}
else if (dir == 2) { // 左移
new_y--;
}
else if (dir == 3) { // 右移
new_y++;
}
// 检查新位置是否在边界内
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;
CLOSED_SIZE = 0;
while (OPEN_SIZE > 0) {//对open列表进行操作
int min_f = OPEN[0]->f;//初始化最小的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值的节点
// 从开放列表中移除当前节点
OPEN[min_index] = OPEN[OPEN_SIZE - 1];
OPEN_SIZE--;
// 将当前节点添加到关闭列表关闭列表大小加1
CLOSED[CLOSED_SIZE] = current;
CLOSED_SIZE++;
// 检查是否找到解
if (isSamePuzzle(current->puzzle, goal->puzzle)) {
// 找到解,返回当前节点
return 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;
// 检查新节点是否在关闭列表中
if (!in_OPEN && !in_CLOSED) {
// 新节点既不在开放列表中也不在关闭列表中
// 把gNew、hNew、fNew赋给new_node对应的g、h、f值并将其父节点设置为当前节点。
new_node->g = gNew;
new_node->h = hNew;
new_node->f = fNew;
new_node->parent = current;
// 添加新节点new_node到开放列表开放列表大小加1
OPEN[OPEN_SIZE] = new_node;
OPEN_SIZE++;
}
else if (in_OPEN && fNew < OPEN[open_index]->f) {
// 新节点已经在开放列表中,但新的 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++) {
if (i % 3 == 0) {
printf("-------\n");
}
for (int j = 0; j < N; j++) {
printf("%d ", final->puzzle[i][j]);
}
printf("\n");
}
}
int main() {
//int start[N][N] = {{1, 0, 3}, {0, 8, 4}, {7, 6, 5}};
// int target[N][N] = {{1, 2, 3}, {7, 0, 4}, {8, 6, 5}};
int start[N][N] = { {2, 0, 3}, {1, 5, 6}, {4, 7, 8} };
int target[N][N] = { {1, 2, 3}, {4, 5, 6}, {7, 8, 0} };
// int start[N][N] = { {2, , 3}, {1, 0, 4}, {7, 6, 5} };
// int target[N][N] = { {1, 2, 3}, {8, 0, 4}, {7, 6, 5} };
Node* init = createNode(start);
Node* goal = createNode(target);
Node* final = AStar(init, goal);
if (final) {
printf("This problem has a solution:\n");
printPath(final); // 打印解路径
}
else {
printf("This problem has no solution\n");
}
return 0;
}