c印记(六): 数组与递归联合应用的小游戏

目录

    • 目录
    • 一概述
    • 二汉诺塔Hanoi Tower
      • 将汉诺塔变为算法问题化描述
      • 分析
        • a 当n 1的时候
        • b 当n 2的时候
        • c 当n 3的时候
        • d 当n N的时候
      • 实现
    • 三迷宫
      • 迷宫的表示方式
      • 手动版迷宫
      • AI版迷宫

一、概述

前面分别讲述了数组和递归,他们在c语言程序设计与编程当中是非常有用的,出现的频率也比较高,
下面就用两个经典的小游戏(汉诺塔,迷宫)来说明一下数组和递归的具体应用。

二、汉诺塔(Hanoi Tower)

汉诺塔:汉诺塔(又称河内塔)问题是源于印度一个古老传说的益智玩具。大梵天创造世界的时候做了三根金刚石柱子,在一根柱子上从下往上按照大小顺序摞着64片黄金圆盘。大梵天命令婆罗门把圆盘从下面开始按大小顺序重新摆放在另一根柱子上。并且规定,在小圆盘上不能放大圆盘,在三根柱子之间一次只能移动一个圆盘。

这算是一个比较经典的递归问题了。下面就来简单说明一下其实现方式。

1.将汉诺塔变为算法问题化描述

假设,这里有A,B,C三根柱子,在柱子A上有n个由大到小的圆盘,现需要将A柱子上的圆盘全部移动到C柱子上,其具体规则如下:
- 圆盘要始终保持上小下大的顺序
- 一次只能移动一个圆盘
- 在从A移动到C的过程中可以记住柱子B进行中间移动

2. 分析

这里以数字来表示圆盘,数字的大小就是圆盘的大小,那么汉诺塔就可以简单的用字幕和数字表示为:

A B C

1
2

n - 1
n

a. 当n = 1的时候

直接将圆盘从A移动到C,A ——> C

b. 当n = 2的时候

移动顺序为:

圆盘 移动策略
1 A ——> B
2 A ——> C
1 B ——> C

c. 当n = 3的时候

可以将上面两个圆盘(1,2)看着一个整体,这样就可以像上面一样只处理两个圆盘,这里以大写的‘一’表示(1,2)两个圆盘的合体,以‘二’表示圆盘三,其移动顺序为:

圆盘 移动策略
A ——> B
A ——> C
B ——> C

如果完整的展开其移动顺序为:

圆盘 移动策略
1 A ——> C
2 A ——> B
1 C ——> B
3 A ——> C
1 B ——> A
2 B ——> C
1 A ——> C

d. 当n = N的时候

和上面一样,可以将前面N - 1个圆盘视为同意的一个圆盘,第N个圆盘视为第二个圆盘,那么其以供 顺序为为:

圆盘 移动策略
N-1 A ——> B
N A ——> C
N-1 B ——> C

这个移动策略就是汉诺塔归纳出来的通用移动策略,也就是说,汉诺塔游戏的递归函数只需要实现这样的移动策略就可以了

3. 实现

这里所说的小游戏并不是常规的有炫酷界面的游戏,这个汉诺塔小游戏是一个简单的控制台程序,既然是游戏,那么这里还是按照比较常用的MVC的架构来实现,其中:
- M: 模型(也就是数据部分),这里以一个二维数组来实现这个小游戏的数据模型,以数组的列分别表示柱子A,B,C,以数组的行表示圆盘(形如:int data_arrray[10][3])
- V:视图(也就是显示部分),这里将实现一个show函数,用于将二维数组显示与控制台界面上
- C:控制(也就是逻辑部分),这里将用一个递归函数实现移动圆盘的过程

接下来就将完整的c语言代码贴出来:

#include <stdio.h>
#include <stdlib.h>

 /**< the data struct, this is M in MVC model */
typedef struct my_hanoi_tower_s
{
    int row; /** the count of array row */
    int column; /** the count of array column */
    int column_name[3];
    int data_array[10][3];
}my_hanoi_tower_t;

/** * *@brief show the hanoi tower data array. * *@param mht [in] the data struct. * *@return None. * *@see *@note this is V in MVC model */
 void show(my_hanoi_tower_t* mht)
 {
    int i,j;
    int n;
    for (n = 0; n < mht->column; n++)
    {
        printf("%5c", mht->column_name[n]);/**< show the name of columns */
    }
    printf("\n---------------------\n"); /** show split line */
    for (i = 0; i < mht->row; i++)
    {
        for(j = 0; j < mht->column; j++)
        {
            printf("%5d", mht->data_array[i][j]);
        }
        printf("\n");
    }
    printf("\n");
 }

/** * *@brief initialize the hanoi tower data array . * *@param mht [in] the data struct. *@param n [in] the count of disc * *@return None. * *@see *@note this is M in MVC model */
void init(my_hanoi_tower_t* mht, int n)
{
    int j = 1;
    int i;
    for (i = n; i > 0; i--)
    {
        /** the set number means disc size */
        mht->data_array[mht->row - i][0] = j++; /** just initialize column 'A' */
    }

    mht->column_name[0] = 'A';
    mht->column_name[1] = 'B';
    mht->column_name[2] = 'C';
}

int get_zero_start_row(my_hanoi_tower_t* mht, int column)
{
    int ret = -1;
    int i;
    for (i = mht->row - 1; i >= 0; i--)
    {
        if (mht->data_array[i][column] == 0)
        {
            ret = i;
            break;
        }
    }

    return ret;
}
int get_noe_zero_start_row(my_hanoi_tower_t* mht, int column)
{
    int ret = -1;
    int i;
    for (i = 0; i < mht->row; i++)
    {
        if (mht->data_array[i][column] > 0)
        {
            ret = i;
            break;
        }
    }

    return ret;
}

void move_disc(my_hanoi_tower_t* mht, int from_col, int to_col, int from_row, int to_row)
{
    int to_val   = mht->data_array[to_row][to_col];
    int from_val = mht->data_array[from_row][from_col];
    mht->data_array[to_row][to_col] = from_val;
    mht->data_array[from_row][from_col] = to_val;
    printf("move: %c(%d) --> %c\n", mht->column_name[from_col], from_val, mht->column_name[to_col]);
    show(mht);
}

/** * *@brief the AI to auomatic process hanoi tower. * *@param mht [in] the data struct. * *@return None. * *@see *@note this is C in MVC model *@note 算法: 1. 当只有一个盘子的时候,只需要从将A塔上的一个盘子移到C塔上。 2. 当A塔上有两个盘子时,先将A塔上的1号盘子(编号从上到下)移动到B塔上, 再将A塔上的2号盘子移动的C塔上,最后将B塔上的小盘子移动到C塔上。 3. 当A塔上有3个盘子时,先将A塔上编号1至2的盘子(共2个)移动到B塔上(需借助C塔), 然后将A塔上的3号最大的盘子移动到C塔,最后将B塔上的两个盘子借助A塔移动到C塔上。 4. 当A塔上有n个盘子是,先将A塔上编号1至n-1的盘子(共n-1个)移动到B塔上(借助C塔), 然后将A塔上最大的n号盘子移动到C塔上,最后将B塔上的n-1个盘子借助A塔移动到C塔上。 */
void hanoi_AI(my_hanoi_tower_t* mht,int n, int a, int b, int c)
{
    if (n < 1)
    {
        return ;
    }
    else if (1 == n)
    {
        int a_row = get_noe_zero_start_row(mht, a);
        int c_row = get_zero_start_row(mht, c);
        move_disc(mht, a, c, a_row, c_row);
    }
    else
    {
        hanoi_AI(mht, n - 1, a, c, b);

        int a_row = get_noe_zero_start_row(mht, a);
        int c_row = get_zero_start_row(mht, c);
        move_disc(mht, a, c, a_row, c_row);
        hanoi_AI(mht, n - 1, b, a, c);
    }
}

int main(int argc, char* argv[])
{
    my_hanoi_tower_t mht = {0};
    mht.column = 3;
    mht.row = 10;


    printf("Hello world!\n");
    init(&mht, 3);
    show(&mht);
    hanoi_AI(&mht, 3, 0, 1, 2);
    show(&mht);
    system("pause");
    return 0;
}

三、迷宫

迷宫也是一个比较经典的小游戏,其中自动走迷宫的算法,也算是寻路算法的简单雏形。

1. 迷宫的表示方式

这里的迷宫和上面的汉诺塔小游戏一样,都是使用一个二维数组来表示的。不同的是,在迷宫小游戏中二维数组里面会有几组不同的数据,首先,数组的大部分元素都是 0,起到‘背景’的作用,然后内部会 有一些值为2元素,它们散落在数组内的不同地方,起到‘墙壁’的作用,表示此方向在当前位置被阻断,无法通行,还有一个值为1的元素,初始化之后,其位置在[0][0]的地方,表示走迷宫的角色。形如

// ---- x
// |
// |
// y
{
    { 1, 0, 2, 0, 0, 0, 0, 0, 0, 0 },
    { 0, 0, 2, 2, 2, 2, 0, 0, 0, 0 },
    { 0, 0, 2, 0, 0, 0, 2, 0, 0, 0 },
    { 0, 0, 0, 0, 2, 0, 2, 0, 2, 2 },
    { 2, 0, 2, 0, 0, 0, 2, 0, 0, 2 },
    { 0, 0, 0, 0, 2, 0, 0, 0, 0, 2 },
    { 0, 2, 0, 0, 0, 2, 0, 2, 0, 0 },
    { 0, 2, 0, 2, 0, 0, 0, 0, 2, 0 },
    { 0, 0, 0, 0, 2, 0, 2, 0, 0, 0 },
    { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }
};

2. 手动版迷宫

先来这一种相对比较简单,这种情况相对来说比较简单,其原理就是,接收来自键盘输入的字母来确定角色‘1’ 应该怎样移动,使用x,y来表示坐标,x为横向从左至右依次递增(即 0 ——> x),用数组的列数 表示, x为从上至下依次递增(即0 ——> y),用数组的行数表示。角色在迷宫中移动需要注意以下几点:

  • 欲移动的新坐标中,x,y的值均不能小于0(否则就出现越界了),
  • 欲移动的新坐标中,x,y的值均不能大于,数组的最大行和列减1,例如迷宫使用数组 int a[M][N],
    那么,新坐标中,必须要有 x < N 或 x <= (N - 1), y < M或 y <= (M - 1)

  • 不能移动到数组表示墙的元素(如上面二维数组中的‘2’)的坐标上,如上面的二维数组中,角色就不能移动到坐标(2, 0)上,也就是二维数组的[0][2]位置

  • 每次只能移动一个单位坐标
  • 移动的方向只能是 上,下,左,右

有了上面几点限制条件之后,剩下的就是具体的移动实现了,这个比较简单,就是根据输入的字母判断应该向哪个方向移动,然后再判断欲将移动的新坐标是否满足上面几个条件,如果满足就移动,不满足,就原地不动。具体实现代码如下

/** * *@brief role move a step with direction. * *@param a [in] the 2D array. *@param x [io] input orignal x coordinate,output move result. *@param y [io] input orignal y coordinate,output move result. *@param direction [in] move direction. * *@return None. * *@see */
static void maze_move(int a[MAZE_ROW][MAZE_COLUMN],int* x, int* y, int direction)
{
    int org_x = *x; //old coordinate x
    int org_y = *y; // old coordinate y
    int role_x = org_x;
    int role_y = org_y;
    const char* dir_name = "unknown";
    switch (direction)
    {
    case 'w':// up
        if ((role_y - 1) >= 0)
        {
            role_y--;
            dir_name = "up";
        }
        break;
    case 's': //down
        if ((role_y + 1) < MAZE_ROW)
        {
            role_y++;
            dir_name = "down";
        }
        break;
    case 'a': //left
        if ((role_x - 1) >= 0)
        {
            role_x--;
            dir_name = "left";
        }
        break;
    case 'd'://right
        if ((role_x + 1) < MAZE_COLUMN)
        {
            role_x++;
            dir_name = "right";
        }
        break;
    default:
        printf("unspport this command:%c\n", direction);
        break;
    }

    if ((org_x != role_x) || (org_y != role_y)) //coordinate has change,then move
    {
        printf("move:%s\n", dir_name);
        int temp = a[org_y][org_x];
        a[org_y][org_x] = a[role_y][role_x];
        a[role_y][role_x] = temp;
        *x = role_x;
        *y = role_y;
    }


}

其中 MAZE_ROW, MAZE_COLUMN是宏定义,表示数组的行和列,可根据具体需要定义其值

3. AI版迷宫

这个版本将使用寻路算法实现自动计算走出迷宫的路径(当然,如果迷宫是死胡同,那自动寻路也将找不到走出迷宫的路径。然后寻路的实现也可分递归版本和循环版本),在数据表示方面和手动版迷宫一样,都是使用二维数组来实现,当然也有不同的地方,就是在AI版中,会在手动版的基础上,在定义一个一模一样(行列相同)的二维数组用于自动寻路算法使用,其中的数据也就会被初始化为和表示迷宫数据的二维数组一样。

既然要自动寻路,那么就需要来分析一下,迷宫寻路的规律或者实现方式:

  • 首先,忽略掉限制条件的情况下,在每一个坐标点,都可以有4种移动方式,上,下,左,右
  • 其次,移动的过程,就是将当前坐标的数组元素与计算出来的新坐标的数组元素进行交换
  • 再次,在移动过程中的限制条件和手动版是一样的
  • 然后,因为初始化之后,角色是在左上角(坐标为(0,0),数组位置为[0][0]),而走出迷宫的标志是走到右下角(坐标为(MAZE_COLUMN-1, MAZE_ROW-1),数组位置为[MAZE_ROW-1][MAZE_COLUMN-1]),所以,判 断一种能否移动的顺序为:右,下,左,上
  • 最后,需要防止移动的时候,出现回退的情况,即从位置A移动到位置B之后,在计算新的移动点C的时候,不能让其再次落到A位置的坐标上,否则会出现死循环

首先是判断各个方向能否进行移动的函数:

/** * *@brief try move a step(just got x,y coordinate,not really move). * *@param a [in] the 2D array. *@param x [io] input orignal x coordinate,output move result. *@param y [io] input orignal y coordinate,output move result. * *@return 1:can move, 0:cann't move. * *@see */
int  try_move(int a[MAZE_ROW][MAZE_COLUMN], int* x, int *y)
{
    int ret = 1;
    int tempx = *x;
    int tempy = *y;
    //try order: right->down->left->up


    if (((tempx + 1) < MAZE_COLUMN) && (a[tempy][(tempx + 1)] < BARRIER))
    {//try right
        *x = tempx + 1;
    }
    else if (((tempy + 1) < MAZE_ROW) && (a[(tempy + 1)][tempx] < BARRIER))
    {//try down
        *y = tempy + 1;
    }
    else if (((tempx - 1) >= 0) && (a[tempy][(tempx - 1)] < BARRIER))
    {//try left
        *x = tempx - 1;
    }else if (((tempy - 1) >= 0) && (a[(tempy - 1)][tempx] < BARRIER))
    {//try up
        *y = tempy - 1;
    }
    else
    {
        ret = 0;
    }


    return ret;
}

其中 MAZE_ROW, MAZE_COLUMN是宏定义,表示数组的行和列,可根据具体需要定义其值。宏BARRIER表示迷宫中的‘墙’,其值为2,之所以判断小于BARRIER,而不是等于,是因为之后还需要定义一个比BARRIER大的宏记录寻路算法走过的路径,且不能重复的走已经走过的路径。

然后是递归寻路函数:

/** * *@brief the AI of pathfinding (recursive implement) * *@param a [in] the 2D array. *@param x [in] the x coordinate of role. *@param y [in] the y coordinate of role. * *@return 1: find, 0: doesn't. * *@see */
int maze_pathfinding_ai_recursive(int a[MAZE_ROW][MAZE_COLUMN], int x, int y)
{
    a[y][x] = AI_OBJ;

    if (((MAZE_COLUMN - 1) == x) && ((MAZE_ROW - 1) == y)) //recursive end condition
    {
        return 1;
    }
    else
    {
        if (try_move(a, &x, &y)) //check try move.
        {
            return maze_pathfinding_ai_recursive(a, x, y);
        }

    }

    return 0;
}

其中宏AI_OBJ的值为3,用来记录寻路算法走过的路径以及防止重复走过的路径(也就是死循环)

上面有提供寻路算法有递归和循环两个版本,而循环的算法实现方式为:

/** * *@brief the AI of pathfinding (loop implement) * *@param a [in] the 2D array. *@param x [in] the x coordinate of role. *@param y [in] the y coordinate of role. * *@return 1: find, 0: doesn't. * *@see */
int maze_pathfinding_ai_loop(int a[MAZE_ROW][MAZE_COLUMN], int x, int y)
{
    int ret = 0;
    int loop_cnt = 0;
    int max_loop = MAZE_ROW * MAZE_COLUMN; //maximum move steps, to avoid endless loop.


    while (loop_cnt++ < max_loop)
    {
        //end condition,it is same with recursive ai.
        if (((MAZE_COLUMN - 1) == x) && ((MAZE_ROW - 1) == y))
        {
            ret = 1;
            break;
        }

        if (try_move(a, &x, &y)) //check try move
        {
            a[y][x] = AI_OBJ;
        }
    }

    return ret;
}

在最后将整个迷宫小游戏的全部代码都贴出来:

#include <stdio.h>
#include <stdlib.h>

//maze data array
#define MAZE_ROW 10
#define MAZE_COLUMN 10

//playing maze mode: 1: AI, 0: human
#define MAZE_PLAY_MODE 1

//pathfinding ai type(AI only): 1: recursive, 0: loop
#define MAZE_PATHFINDING_AI_TYPE 1


#define ROLE_OBJ 1
#define AI_OBJ 3 //this value must bigger than BARRIER
#define BARRIER 2
#define MAZE_PAD 0

//orignal coordinate
#define ROLE_ORG_X 0 //in array column
#define ROLE_ORG_Y 0 //in array row

#define show_obj(obj) printf("%4d ", obj)


// ---- x
// |
// |
// y



static int g_maze_data[MAZE_ROW][MAZE_COLUMN] =
{
    { 1, 0, 2, 0, 0, 0, 0, 0, 0, 0 },
    { 0, 0, 2, 2, 2, 2, 0, 0, 0, 0 },
    { 0, 0, 2, 0, 0, 0, 2, 0, 0, 0 },
    { 0, 0, 0, 0, 2, 0, 2, 0, 2, 2 },
    { 2, 0, 2, 0, 0, 0, 2, 0, 0, 2 },
    { 0, 0, 0, 0, 2, 0, 0, 0, 0, 2 },
    { 0, 2, 0, 0, 0, 2, 0, 2, 0, 0 },
    { 0, 2, 0, 2, 0, 0, 0, 0, 2, 0 },
    { 0, 0, 0, 0, 2, 0, 2, 0, 0, 0 },
    { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }
};

static int g_maze_ai_data[MAZE_ROW][MAZE_COLUMN];


/** * *@brief show all element of 2D array. * *@param a [in] the 2D array. * *@return None. * *@see */
void show(int a[MAZE_ROW][MAZE_COLUMN])
{
    printf("\n----------------------------------------------------\n");
    int i,j;
    for (i = 0; i < MAZE_ROW; i++)
    {
        for (j = 0; j < MAZE_COLUMN; j++)
        {
            show_obj(a[i][j]);
        }
        printf("\n");
    }
    printf("\n");
}

/** * *@brief initialize maze ai data arrray with a 2D array. * *@param a [in] the 2D array. * *@return None. * *@see */
void init_ai_data(int a[MAZE_ROW][MAZE_COLUMN])
{
    int i, j;
    for (i = 0; i < MAZE_ROW; i++)
    {
        for (j = 0; j < MAZE_COLUMN; j++)
        {
           g_maze_ai_data[i][j] = a[i][j];
        }
    }
}


/** * *@brief role move a step with direction. * *@param a [in] the 2D array. *@param x [io] input orignal x coordinate,output move result. *@param y [io] input orignal y coordinate,output move result. *@param direction [in] move direction. * *@return None. * *@see */
static void maze_move(int a[MAZE_ROW][MAZE_COLUMN],int* x, int* y, int direction)
{
    int org_x = *x; //old coordinate x
    int org_y = *y; // old coordinate y
    int role_x = org_x;
    int role_y = org_y;
    const char* dir_name = "unknown";
    switch (direction)
    {
    case 'w':// up
        if ((role_y - 1) >= 0)
        {
            role_y--;
            dir_name = "up";
        }
        break;
    case 's': //down
        if ((role_y + 1) < MAZE_ROW)
        {
            role_y++;
            dir_name = "down";
        }
        break;
    case 'a': //left
        if ((role_x - 1) >= 0)
        {
            role_x--;
            dir_name = "left";
        }
        break;
    case 'd'://right
        if ((role_x + 1) < MAZE_COLUMN)
        {
            role_x++;
            dir_name = "right";
        }
        break;
    default:
        printf("unspport this command:%c\n", direction);
        break;
    }

    if ((org_x != role_x) || (org_y != role_y)) //coordinate has change,then move
    {
        printf("move:%s\n", dir_name);
        int temp = a[org_y][org_x];
        a[org_y][org_x] = a[role_y][role_x];
        a[role_y][role_x] = temp;
        *x = role_x;
        *y = role_y;
    }


}

/** * *@brief try move a step(just got x,y coordinate,not really move). * *@param a [in] the 2D array. *@param x [io] input orignal x coordinate,output move result. *@param y [io] input orignal y coordinate,output move result. * *@return 1:can move, 0:cann't move. * *@see */
int  try_move(int a[MAZE_ROW][MAZE_COLUMN], int* x, int *y)
{
    int ret = 1;
    int tempx = *x;
    int tempy = *y;
    //try order: right->down->left->up


    if (((tempx + 1) < MAZE_COLUMN) && (a[tempy][(tempx + 1)] < BARRIER))
    {//try right
        *x = tempx + 1;
    }
    else if (((tempy + 1) < MAZE_ROW) && (a[(tempy + 1)][tempx] < BARRIER))
    {//try down
        *y = tempy + 1;
    }
    else if (((tempx - 1) >= 0) && (a[tempy][(tempx - 1)] < BARRIER))
    {//try left
        *x = tempx - 1;
    }else if (((tempy - 1) >= 0) && (a[(tempy - 1)][tempx] < BARRIER))
    {//try up
        *y = tempy - 1;
    }
    else
    {
        ret = 0;
    }


    return ret;
}


/** * *@brief the AI of pathfinding (recursive implement) * *@param a [in] the 2D array. *@param x [in] the x coordinate of role. *@param y [in] the y coordinate of role. * *@return 1: find, 0: doesn't. * *@see */
int maze_pathfinding_ai_recursive(int a[MAZE_ROW][MAZE_COLUMN], int x, int y)
{
    a[y][x] = AI_OBJ;

    if (((MAZE_COLUMN - 1) == x) && ((MAZE_ROW - 1) == y)) //recursive end condition
    {
        return 1;
    }
    else
    {
        if (try_move(a, &x, &y)) //check try move.
        {
            return maze_pathfinding_ai_recursive(a, x, y);
        }

    }

    return 0;
}

/** * *@brief the AI of pathfinding (loop implement) * *@param a [in] the 2D array. *@param x [in] the x coordinate of role. *@param y [in] the y coordinate of role. * *@return 1: find, 0: doesn't. * *@see */
int maze_pathfinding_ai_loop(int a[MAZE_ROW][MAZE_COLUMN], int x, int y)
{
    int ret = 0;
    int loop_cnt = 0;
    int max_loop = MAZE_ROW * MAZE_COLUMN; //maximum move steps, to avoid endless loop.


    while (loop_cnt++ < max_loop)
    {
        //end condition,it is same with recursive ai.
        if (((MAZE_COLUMN - 1) == x) && ((MAZE_ROW - 1) == y))
        {
            ret = 1;
            break;
        }

        if (try_move(a, &x, &y)) //check try move
        {
            a[y][x] = AI_OBJ;
        }
    }

    return ret;
}


void maze_walk_out(int real_data[MAZE_ROW][MAZE_COLUMN], int ai_data[MAZE_ROW][MAZE_COLUMN])
{
    int x = 0;
    int y = 0;
    int loop_cnt = 0;
    int max_loop = MAZE_ROW * MAZE_COLUMN; //maximum move steps, to avoid endless loop.
    ai_data[ROLE_ORG_Y][ROLE_ORG_X] = ROLE_OBJ;


    while (loop_cnt++ < max_loop)
    {
        //end condition,it is same with recursive ai.
        if (((MAZE_COLUMN - 1) == x) && ((MAZE_ROW - 1) == y))
        {
            break;
        }

        /** move order: right->down->left->up. */

        //try right
        if (((x + 1) < MAZE_COLUMN) && (ai_data[y][(x + 1)] == AI_OBJ))
        {
            ai_data[y][(x + 1)] = MAZE_PAD; //reset ai path value.
            maze_move(real_data, &x, &y, 'd'); //move right
            show(real_data);
        }

        //try down
        if (((y + 1) < MAZE_ROW) && (ai_data[(y + 1)][x] == AI_OBJ))
        {
            ai_data[(y + 1)][x] = MAZE_PAD;//reset ai path value.
            maze_move(real_data, &x, &y, 's'); //move down
            show(real_data);
        }

        //try left
        if (((x - 1) >= 0) && (ai_data[y][(x - 1)] == AI_OBJ))
        {
            ai_data[y][(x - 1)] = MAZE_PAD;//reset ai path value.
            maze_move(real_data, &x, &y, 'a'); //move left
            show(real_data);
        }

        //try up
        if (((y - 1) >= 0) && (ai_data[(y - 1)][x] == AI_OBJ))
        {
            ai_data[(y - 1)][x] = MAZE_PAD;//reset ai path value.
            maze_move(real_data, &x, &y, 'w'); //move up
            show(real_data);
        }
    }
}

/** * *@brief human play the game. * *@param None * *@return None * *@see */
void human_play()
{
    int x = ROLE_ORG_X;
    int y = ROLE_ORG_Y; //role, initialize coordinate
    printf("\n------------------------------------\n");
    printf("input:w,s,a,d to play the game:\n ");
    printf("w --> up\n");
    printf("s --> down\n");
    printf("a --> left\n");
    printf("d --> right\n");
    printf("note: aways need to input the key of \'ENTER\' as end");
    printf("\n------------------------------------\n");

    while (1)
    {
        int ch = getchar();
        getchar(); //skip the key of 'enter'
        maze_move(g_maze_data,&x, &y, ch);
        show(g_maze_data);
    }
}

/** * *@brief AI play the game. * *@param None * *@return None * *@see */
void ai_play()
{
    int ret = 0;
    int x = ROLE_ORG_X;
    int y = ROLE_ORG_Y;

    init_ai_data(g_maze_data); //initialize ai data array.

#if MAZE_PATHFINDING_AI_TYPE //if 1, recursive implement
    ret = maze_pathfinding_ai_recursive(g_maze_ai_data, x, y);
#else//if 0, loop implement.
    ret = maze_pathfinding_ai_loop(g_maze_ai_data, x, y);
#endif

    if (1 == ret)
    {
        printf("congratulations! you can walk out the maze!\n");

        printf("show AI data array\n");
        show(g_maze_ai_data);

        printf("starting demonstrate the procedure of walk out maze...\n");
        maze_walk_out(g_maze_data, g_maze_ai_data);

    }
    else
    {
        printf("unfortunate! cann't find any path to walk out the maze!\n");
    }
    //show(g_maze_data);
}



int main(void)
{
    printf("show maze default data array\n");

    show(g_maze_data);
#if MAZE_PLAY_MODE //1:ai play mode
    ai_play();
#else //0: human play mode.
    human_play();
#endif

    system("pause");
    return 0;
}

你可能感兴趣的:(游戏,递归,C语言)