这是一道用堆栈展示棋子马的移动路径的问题。在国际象棋中,马的走法是L形。棋盘的坐标水平用a到b表示,垂直用8比1表示。如果我输入起始位置和到达位置,程序应该运行,以便骑士显示已经通过的坐标。
但是与我的预期相反,骑士经过的路径没有正确输出。如果我输入b7作为起点,e2作为终点,应该输出如下:
b7 c2 e6 g7 h5 g3 e2
但是打印出来是这样的:
b7 e2
---
3
e2
我不知道这是怎么回事。如果您能更正代码,我将非常感激。
接下来是我编写的代码。 (希望大家不要修改gstack.c和gstack.h文件中的代码。)
typedef
struct {
void * buffer ;
int unit ;
int capacity ;
int size ;
}
gstack_t ;
gstack_t *
create_stack (int capacity, int unit) ;
void
delete_stack (gstack_t * stack) ;
int
push (gstack_t * stack, void * elem) ;
int
pop (gstack_t * stack, void * elem) ;
int
is_empty (gstack_t * stack) ;
int
is_full (gstack_t * stack) ;
int
get_size (gstack_t * stack) ;
int
get_element (gstack_t * stack, int index, void * elem) ;
gstack.c
#include <stdlib.h>
#include <string.h>
#include "gstack.h"
gstack_t *
create_stack (int capacity, int unit)
{
gstack_t * st = malloc(sizeof(gstack_t)) ;
st->capacity = capacity ;
st->unit = unit ;
st->size = 0 ;
st->buffer = calloc(capacity, unit) ;
return st ;
}
void
delete_stack (gstack_t * st)
{
if (st->buffer != 0x0)
free(st->buffer) ;
free(st) ;
}
int
push (gstack_t * st, void * elem)
{
if (is_full(st))
return 0 ;
// memcpy: memory + copy(메모리의 값 복사.)
// void* memcpy(*(복사받을데), *(복사할데), size(바이트단위));
memcpy(st->buffer + ((st->size) * (st->unit)), elem, st->unit) ;
st->size += 1 ;
return 1 ;
}
int
pop (gstack_t * st, void * elem)
{
if (is_empty(st))
return 0 ;
memcpy(elem, st->buffer + (st->size - 1) * st->unit, st->unit) ;
st->size -= 1 ;
return 1 ;
}
int
is_empty (gstack_t * st)
{
return (st->size == 0) ;
}
int
is_full (gstack_t * st)
{
return (st->size == st->capacity) ;
}
int
get_size (gstack_t * st)
{
return st->size ;
}
int
get_element (gstack_t * st, int index, void * elem)
{
if (st->size <= index)
return 0 ;
memcpy(elem, st->buffer + index * st->unit, st->unit) ;
return 1 ;
}
骑士.c
#include <stdio.h>
#include <stdlib.h>
#include "gstack.h"
int visited[8][8] = {0,};
typedef
enum {
// e.g U2R1: a kinght moves 2 squares Upward and 1 squares Right.
U2R1, U2L1, L2U1, L2D1, D2L1, D2R1, R2D1, R2U1
}
dir;
char departure_h;
int departure_v;
char arrival_h;
int arrival_v;
void depart_to_arrival() {
scanf(" %c %d", &departure_h, &departure_v); // input departure coordinate
scanf(" %c %d", &arrival_h, &arrival_v); // input arrival coordinate;
printf("---\n");
}
void search() {
gstack_t * hs = create_stack(64, sizeof(char)); // about horizontal coordinate (X, char a~b)
gstack_t * vs = create_stack(64, sizeof(int)); // about vertical coordinate (Y, integer 8~1)
gstack_t * ds = create_stack(64, sizeof(dir)); // about diretion ( U2R1, U2L1, ... R2U1)
int found = 0; // 목적지에 도달했는지를 나타냄.
char h = departure_h; // horizon(x)
int v = departure_v; // vertical(y)
dir d = U2R1; // direction
visited[v-1][h-'a'] = 1;
push(hs, &h);
push(vs, &v);
push(ds, &d);
while(is_empty(hs) == 0 && !found) {
pop(hs, &h); pop(vs, &v); pop(ds, &d);
if(h == arrival_h && v == arrival_v) { // check arrivial
found = 1;
push(hs, &h); push(vs, &v);
break; // end of search
}
for(dir i=d; i<=R2U1; i++) {
char nh=h;
int nv=v;
switch(i) {
case U2R1: {
nh = h+1;
nv = v+2;
break ;
}
case U2L1: {
nh = h-1;
nv = v+2;
break ;
}
case L2U1: {
nh = h-2;
nv = v+1;
break ;
}
case L2D1: {
nh = h-2;
nv = v-1;
break ;
}
case D2L1: {
nh = h-1;
nv = v-2;
break ;
}
case D2R1: {
nh = h+1;
nv = v-2;
break ;
}
case R2D1: {
nh = h+2;
nv = v-1;
break ;
}
case R2U1: {
nh = h+2;
nv = v+1;
d = U2R1;
break ;
}
default: {
continue;
}
}
if ('a'<=nh && nh <='h' && 1<=nv && nv <=8 && !visited[nv-1][nh-'a']) {
visited[nv-1][nh-'a']=1;
push(hs, &nh); push(vs, &nv);
push(ds, &i);
break;
}
}
}
if(found) {
for(int i=get_size(hs); i>=0; i--) {
char h;
int v;
get_element(hs, i, &h); get_element(vs, i, &v);
printf("%c%d\n", h, v);
}
}
else {
printf("failed.\n");
}
}
int main(void) {
depart_to_arrival();
search();
return EXIT_SUCCESS;
}
我在搜索函数中的while语句中删除了(L 43) pop(),并修改了代码,将if语句(L 101)的else语句修改为如果不满足条件则弹出,即如果关闭则弹出棋盘。但它不能正常工作。我知道推送不能正常工作,但我真的不知道……编码高手,请救救我。请。
主要问题是你的算法逻辑:堆栈永远不会有多个元素。每个堆栈都以一个元素开始,然后主循环开始:在主循环的每次迭代中,您从每个堆栈中弹出一项,并在每个堆栈上推送一项。因此,这些堆栈不可能获得超过一件物品。
我不清楚您打算实现哪种算法,但由于 8x8 板只有 64 个方格,我会在没有堆栈的情况下执行此操作。相反,使用
visited
数组不仅可以指示是否访问过某个方格,还可以指示到达该方格的步数。您可以从给定的方块开始,然后应用骑士跳跃来找到具有下一个距离的方块。由于现在您尚未将这些结果存储在堆栈中,因此您将扫描 visited
数组以再次找到这些结果,并通过另一次移动来扩展它们,...等等。
为了打印路径,您将沿着路径向后移动,始终寻找会缩短距离的移动。由于这会向后打印路径,因此从头到尾执行第一阶段会很有帮助。
这确实是一种广度优先搜索,其中通过扫描棋盘来替换队列。但它保证你找到最短路径。
不是必需的,但在一维 (0..63) 而不是二维 ('a'..'h', 1..8) 中工作可能更容易。
这是一个实现:
#include <stdio.h>
#include <stdlib.h>
int pair_to_square(char h, int v) {
return (h - 'a') + 8 * (v - 1);
}
void depart_to_arrival(int * departure, int * arrival) {
// Avoid globals
char departure_h;
int departure_v;
char arrival_h;
int arrival_v;
scanf(" %c %d", &departure_h, &departure_v); // input departure coordinate
scanf(" %c %d", &arrival_h, &arrival_v); // input arrival coordinate;
printf("---\n");
*departure = pair_to_square(departure_h, departure_v);
*arrival = pair_to_square(arrival_h, arrival_v);
}
int apply_jump(int square, int i) {
static int jumps[8] = {-17, -15, -10, -6, 6, 10, 15, 17};
int newsquare = square + jumps[i];
int coldiff = abs(square % 8 - newsquare % 8);
if (newsquare >= 64 || coldiff > 2) return -1;
return newsquare;
}
void search(int departure, int arrival) {
int visited[64] = {0,};
visited[arrival] = 1; // Start from the end
int distance = 1;
while (!visited[departure]) {
// Scan the board to find the squares with the current distance
for (int square = 0; square < 64; square++) {
if (visited[square] != distance) continue;
for (int i = 0; i < 8; i++) {
int newsquare = apply_jump(square, i);
if (newsquare >= 0 && !visited[newsquare]) {
// Mark the distance at the target of the played move
visited[newsquare] = distance + 1;
}
}
}
distance++;
}
// Traverse the path in opposite direction, and print it
while (distance-- > 0) {
printf("%c%d\n", 'a' + (departure % 8), (departure / 8) + 1);
for (int i = 0; i < 8; i++) {
int newsquare = apply_jump(departure, i);
if (newsquare >= 0 && visited[newsquare] == distance) {
departure = newsquare;
break;
}
}
}
}
int main(void) {
int departure, arrival;
depart_to_arrival(&departure, &arrival);
search(departure, arrival);
return EXIT_SUCCESS;
}