
#include <stdio.h> #include <stdint.h> #include <stdlib.h> #include <string.h> #include <unistd.h> #include <ncurses.h> #include <algorithm> typedef uint16_t* pi16; const char* room_str[] = { " ##### ", " #---# ", " #@--# ", " ###--@## ", " #--@-@-# ", "###-#-##-# ######", "#---#-##-#####--**#", "#-@--@----------**#", "#####-###-#+##--**#", " #-----#########", " ####### "}; char room[32][32]; int W, H; // box被ncurses占用了,换拼音 char man[2], xz[8][2], goal[8][2]; // (x,y)坐标 int n_xz; // 箱子数=目标数 char old_man[2], old_xz[2]; // 旧坐标 int can_undo, old_xz_idx = -1; void parse_room () { W = strlen(room_str[0]); H = sizeof(room_str) / sizeof(room_str[0]); int n = 0; for (int y = 0; y < H; y++) for (int x = 0; x < W; x++) { char c = '-'; switch (room_str[y][x]) { case '+': man[0] = x; man[1] = y; break; case '@': xz[n_xz][0] = x; xz[n_xz++][1] = y; break; case '*': goal[n][0] = x; goal[n++][1] = y; break; default: c = room_str[y][x]; } room[y][x] = c; } std::sort(pi16(xz), pi16(xz + n)); std::sort(pi16(goal), pi16(goal + n)); } void draw_ch (int x, int y, int ch, int color) { int attr = COLOR_PAIR(color); if (ch != ' ' && ch != '-') attron(attr); mvaddch(3 + y, 30 + x, ch); if (ch != ' ' && ch != '-') attroff(attr); } void draw () { for (int x = 0; x < 16; x++) mvprintw(2, 30+x, "%x", x); for (int y = 0; y < 11; y++) mvprintw(3+y, 29, "%x", y); for (int i = 0; i < n_xz; i++) mvprintw(1, 20+i*6, "%d,%d", xz[i][0], xz[i][1]); for (int y = 0; y < H; y++) for (int x = 0; x < W; x++) draw_ch(x, y, room[y][x], 1); for (int i = 0; i < n_xz; i++) draw_ch(goal[i][0], goal[i][1], '*', 2), draw_ch(xz[i][0], xz[i][1], '@', 3); draw_ch(man[0], man[1], '+', 4); refresh(); } void init_ncurses () { initscr(); start_color(); init_pair(1, COLOR_BLUE, COLOR_BLUE); init_pair(2, COLOR_YELLOW, COLOR_BLACK); init_pair(3, COLOR_GREEN, COLOR_BLACK); init_pair(4, COLOR_RED, COLOR_BLACK); cbreak(); noecho(); keypad(stdscr, 1); curs_set(0); //timeout(0); let getch() block; ch == ERR atexit((void (*)())endwin); } #define XY(x,y) (((y) << 8) | (x)) inline int get_xz (uint16_t xy) { int low = 0, high = n_xz - 1; while (low <= high) { const int m = (low + high) >> 1; const uint16_t xy0 = *(uint16_t*)xz[m]; if (xy0 == xy) return m; else if (xy0 < xy) low = m + 1; else high = m - 1; } return -1; } bool move (int d) { static const char D[][2] = { 0, -1, 0, 1, -1, 0, 1, 0 }; int x = man[0], y = man[1]; if (room[y += D[d][1]][x += D[d][0]] == '#') return false; int i = get_xz(XY(x,y)); if (i != -1) { if (room[y += D[d][1]][x += D[d][0]] == '#') return false; int j = get_xz(XY(x,y)); if (j != -1) return false; *((uint16_t*)old_xz) = *((uint16_t*)xz[i]); int x = xz[i][0] += D[d][0], y = xz[i][1] += D[d][1]; std::sort(pi16(xz), pi16(xz + n_xz)); bool f0 = room[y-1][x] == '#' || get_xz(XY(x, y-1)) != -1; bool f1 = room[y+1][x] == '#' || get_xz(XY(x, y+1)) != -1; bool f2 = room[y][x-1] == '#' || get_xz(XY(x-1, y)) != -1; bool f3 = room[y][x+1] == '#' || get_xz(XY(x+1, y)) != -1; mvprintw(16,20, "(%x,%x):%d (%x,%x):%d (%x,%x):%d (%x,%x):%d", x,y-1,f0, x,y+1,f1, x-1,y,f2, x+1,y,f3); } *((uint16_t*)old_man) = *((uint16_t*)man); man[0] += D[d][0]; man[1] += D[d][1]; old_xz_idx = i; can_undo = 1; return true; } void undo () { if (!can_undo) return; *((uint16_t*)man) = *((uint16_t*)old_man); if (old_xz_idx != -1) *((uint16_t*)xz[old_xz_idx]) = *((uint16_t*)old_xz); old_xz_idx = -1; can_undo = 0; } int main () { for (parse_room(), init_ncurses();;) { draw(); int ch = getch(); if (ch == KEY_UP || ch == 'w') move(0); else if (ch == KEY_DOWN || ch == 'x') move(1); else if (ch == KEY_LEFT || ch == 'a') move(2); else if (ch == KEY_RIGHT || ch == 'd') move(3); else if (ch == 'u') undo(); else if (ch == 'q') break; } return 0; } // usleep(10000);
截图是较早处理' '和'-'有bug的版本。
箱子会动,没法简单判断是否是死局:暂时推不动,推开别的箱子后能推动了。
试了下算箱子和目标的坐标向量的点积。程序应该没错,完全重合时是1,快推出来时接近1,别的时候堪做反向指标。

人能一目了然,视线还可以拐弯。也许我得学神经网络了。
也许可以:
- 用畅通度打分。扫描每个箱子的水平和竖直方向,看有无目标、离目标的距离,途中障碍物的多少。
- 在墙外再包一层,move前放所有箱子,move后拿走,不用坐标,只用字符来判断碰撞。
- move后可能产生死局。箱子能在某方向移动的条件(以竖直方向为例)是上下都是空。如果两个箱子在比如水平方向挨着,竖直方向都不能动,则陷入死局。
用了大字体xterm:
XTerm*faceName: DejaVu Sans Mono : antialias=True : pixelsize=32
XTerm*faceNameDoubleSize :Noto Sans CJK : antialias=True : pixelsize=32
浙公网安备 33010602011771号