C语言现代方法:第八章第9题编程题——自己做个笔记
本书的官方源码地址及github地址:
http://knking.com/books/c2/answers/index.html
https://github.com/fordea/c-programming-a-modern-approach
题目描述:
生成一种贯穿10x10字符数组(初始时权威字符点‘.’ )的“随机步法”。程序必须随机地从一个元素“走到”另一个元素,每次都想上、向下、向左或向右移动一个元素。已访问过的元素按访问顺序用字符A到Z进行标记。
上一张原书对此题的描述:
代码如下:
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <stdbool.h>
#define N 10
int main(void){
// 棋盘初始化
char ch[N][N]={'.'};
for(int i =0 ; i < N ; i++){
for(int j = 0; j < N ;j++){
ch[i][j]='.';
}
}
srand((unsigned int) time(NULL)); // 生成随机数前,先调用 srand 函数
bool point[N][N]={false}; // 此bool型所有元素,必须先初始化。因为我调试了好久发现,如果不初始化,程序运行后,棋盘有的为true,有的为fale。
int ptx = 0,pty = 0; // 数组元素的横纵坐标
ch[0][0] = 'A'; // 给 A 一个初始化,程序总是从ch[0][0] = 'A' 开始打印的
point[0][0] = 1;
//简单讲个小故事,分析一下代码~~~~~~~~~~~此段可略过
// 现在假设我们站在十字路口——即一个 crossroads[4][3],
// 我们面临4个方向,但是要随机产生一个方向通过,
// 0:表示这个点没有字母,为false。
// 某个位置的字母这样表示 ch[temp_ptx][temp_pty]
// temp_ptx:以"十字路口"为起点,下一个字母所在位置的temp_ptx值,
// temp_pty:以"十字路口"为起点,下一个字母所在位置的temp_pty值。
// 所以,我们要全力打造出如下形式的数组,冲鸭!!!
// int crossroads[4][3] = {
// {0,temp_ptx,temp_pty},
// {0,temp_ptx,temp_pty},
// {0,temp_ptx,temp_pty},
// {0,temp_ptx,temp_pty}
// };
int k = 0; // 根据k的值,可以判断crossroads数组元素有几个(十字路口的出口个数)
int m = 0 , n = 0; // crossroads 下标
int letusgo = 0; // 出口方向——冲鸭!!!
for(int Alphabet = 0; Alphabet < 25; Alphabet++){ //'A'已经有了,剩余那25个在此等候
// crossroads 的 4 种出口情况
m = 0 ; n = 0 ; // m ,n 出口下标清零
k = 0; //根据 k 的值,计算出口的个数
int crossroads[4][3];
int temp_ptx = ptx; // 每次循环,用临时变量temp_ptx和temp_pty记住上次所在位置,
int temp_pty = pty; // 要是直接用全局变量ptx和pty,你会迷路的!!!嘿嘿!
// 第一种情况:南下
if((ptx+1)>0 && (ptx+1)<=9){
temp_ptx = ptx + 1;
temp_pty = pty;
if(!point[temp_ptx][temp_pty]){
crossroads[m][n] = point[temp_ptx][temp_pty];
crossroads[m][n+1] = temp_ptx;
crossroads[m][n+2] = temp_pty;
k++;
}
}
// 第二种情况:右路
if((pty+1)>0 && (pty+1)<=9){
temp_ptx = ptx;
temp_pty = pty + 1;
if(!point[temp_ptx][temp_pty]){
if(k!=0){ // 在m++前,别忘了判断 k 的值,
m++; //否则程序怎么知道crossroads[0][0] 有没有元素。
}
crossroads[m][n] = point[temp_ptx][temp_pty];
crossroads[m][n+1] = temp_ptx;
crossroads[m][n+2] = temp_pty;
k++;
}
}
// 第三种情况:北上
if((ptx-1)>=0 && (ptx-1)<10){
temp_ptx = ptx - 1;
temp_pty = pty;
if(!point[temp_ptx][temp_pty]){
if(k!=0){
m++;
}
crossroads[m][n] = point[temp_ptx][temp_pty];
crossroads[m][n+1] = temp_ptx;
crossroads[m][n+2] = temp_pty;
k++;
}
}
// 第四种情况:左路
if((pty-1)>=0 && (pty-1)<10){
temp_ptx = ptx;
temp_pty = pty - 1;
if(!point[temp_ptx][temp_pty]){
if(k!=0){
m++;
}
crossroads[m][n] = point[temp_ptx][temp_pty];
crossroads[m][n+1] = temp_ptx;
crossroads[m][n+2] = temp_pty;
k++;
}
}
if(k == 0 ){
break;
}else{
letusgo = (int)(rand() % k ); // 根据k得知有几条路可选,随机选择一条路
temp_ptx = crossroads[letusgo][1];
temp_pty = crossroads[letusgo][2];
point[temp_ptx][temp_pty] = 1; // 确定下一个点,赋值为true,这个点下次就不能再经过了
ch[temp_ptx][temp_pty] = ch[ptx][pty]+1 ;// 按字母表顺序,确定下一个字母
ptx = temp_ptx; // 把上一个点的位置覆盖,然后进入下一个循环
pty = temp_pty;
}
}
//********** 打印最终结果 ***************
for(int i =0 ; i < N ; i++){
for(int j = 0; j < N ;j++){
printf("%c ", ch[i][j]);
}
printf("\n");
}
//****************************************
return 0;
}