在这个函数中,程序从列表中获取之前生成的四个随机单词,并将它们随机放入10x10矩阵中。
问题是,有时水平/垂直/倾斜的单词会重叠(但同一类别的单词不会重叠)。我不希望它们以这种方式重叠
void outputMatrix() {
char matrix[10][10];
for (int i = 0; i<10; i++) {
for (int j = 0; j<10; j++) {
matrix[i][j] = '-';
}
}
getRandomWord();
srand(time(NULL));
int randPosY = (rand() % 9);
int randPosX = (rand() % 9);
int incr = 0;
bool amend;
char r;
for (int x = 0; x < 4; x++) {
char randCase = (rand() % 3) + 65;
switch (randCase) {
case 'A': //to input words horizontally
if (incr == 1) {
r1 = r2;
}
if (incr == 2) {
r1 = r3;
}
if (incr == 3) {
r1 = r4;
}
reCheck:
amend = false;
if ((randPosX + strlen(dictionary[r1]) > 10)) {
randPosX--;
goto reCheck;
}
for (int i = 0; i < strlen(dictionary[r1]); i++) {
matrix[randPosY][randPosX + i] = dictionary[r1][i];
}
for (int i = 0; i < strlen(dictionary[r1]); i++) {
reRand:
if (matrix[randPosY][randPosX + i] != '-') {
randPosY = (rand() % 9);
randPosX = (rand() % 9);
goto reRand;
amend = true;
}if ((i == (strlen(dictionary[r1]) - 1)) && (amend == true)) goto reCheck;
}
break;
case 'B': //to input words vertically
if (incr == 1) {
r1 = r2;
}
if (incr == 2) {
r1 = r3;
}
if (incr == 3) {
r1 = r4;
}
reCheck2:
amend = false;
if ((randPosY + strlen(dictionary[r1]) > 10)) {
randPosY--;
goto reCheck2;
}
for (int i = 0; i < strlen(dictionary[r1]); i++) {
matrix[randPosY + i][randPosX] = dictionary[r1][i];
}
for (int i = 0; i < strlen(dictionary[r1]); i++) {
reRand2:
if (matrix[randPosY + i][randPosX] != '-') {
randPosY = (rand() % 9);
randPosX = (rand() % 9);
goto reRand2;
amend = true;
}if ((i == (strlen(dictionary[r1]) - 1)) && (amend == true)) goto reCheck2;
}
break;
case 'C': //to input words slanting
if (incr == 1) {
r1 = r2;
}
if (incr == 2) {
r1 = r3;
}
if (incr == 3) {
r1 = r4;
}
reCheck3:
amend = false;
if ((randPosY + strlen(dictionary[r1]) > 10)) {
randPosY--;
goto reCheck3;
}
reCheck4:
if ((randPosX + strlen(dictionary[r1]) > 10)) {
randPosX--;
goto reCheck4;
}
for (int i = 0; i < strlen(dictionary[r1]); i++) {
matrix[randPosY + i][randPosX + i] = dictionary[r1][i];
}
for (int i = 0; i < strlen(dictionary[r1]); i++) {
reRand3:
if (matrix[randPosY + i][randPosX + i] != '-') {
randPosY = (rand() % 9);
randPosX = (rand() % 9);
amend == true;
goto reRand3;
}if ((i == (strlen(dictionary[r1]) - 1)) && (amend == true)) goto reCheck3;
}
break;
} incr++;
}
//for (int i = 0; i<10; i++) {
//for (int j = 0; j < 10; j++) {
//if (matrix[i][j] == '-') {
//r = (rand() % 26) + 65;
//matrix[i][j] = r;
//}
//}
//}
printf("nt A B C D E F G H I Jnnnt");
for (int a = 0; a <10; a++) {
printf("%d", a);
printf(" ");
for (int b = 0; b < 10; b++) {
printf("%c ", matrix[a][b]);
}
printf("nnt");
}
}
当您决定将单词放置在一个位置时,首先扫描放置单词的所有位置,看看是否还有其他单词。如果存在,则中止并尝试新位置。
如果它经常失败,你可能也想有某种"重置"选项,以防没有有效的位置。
放置单词的逻辑应该是:
- 选一个词
- 选择随机坐标和方向,直到单词可以放置在这些坐标和该方向
- 放置单词
相反,您放置第一个单词而不检查碰撞(这没关系,您有一个空网格),并在放置单词后选择新的坐标。那时,您不知道要放置哪个单词,将其放置在哪个方向,以及是否必须调整坐标以防止单词溢出网格边界。
您的代码显示其他问题:
-
您对
goto
s的使用使代码几乎无法读取。您可以用公共控件构造替换所有goto
。例如,reCheck4: if ((randPosX + strlen(dictionary[r1]) > 10)) { randPosX--; goto reCheck4; }
可以写成
while (randPosX + strlen(dictionary[r1]) > 10) randPosX--;
某些
goto
使语句无法访问,例如:goto reRand2; amend = true;
这里
amend = true
将永远不会被执行。(奇怪的是,你到处都在使用Fortran77式的gotos,但它们可能更清晰的地方,你使用了Pascal式的真值变量。) -
您在四个单词上的循环使用
x
,但您从未使用该变量。相反,您保留另一个变量incr
,其值与x
的值相同。更换int incr = 0; for (int x = 0; x < 4; x++) { // Do stuff with incr, but not with x incr++; }
带有:
for (int incr = 0; incr < 4; incr++) { // Do stuff with incr, but not with x }
-
您有四个单词索引,
r1
到r4
。类似的代码if (incr == 1) { r1 = r2; } if (incr == 2) { r1 = r3; } if (incr == 3) { r1 = r4; }
你甚至在所有三种定向情况下都重复,这表明你想要一个数组:
r1 = index[incr];
-
仅在
main
开始时调用srand
一次。使用低粒度种子(如以秒为单位的时间)反复调用srand
将减少程序的随机性。 -
strlen
是一个函数,它通过遍历字符串直到找到空终止符来确定每次调用字符串时字符串的长度。您总是在循环中查看相同的字符串,因此可以将字符串长度存储在变量中。(您的字符串很短,开销可以忽略不计,但仍然如此。)
您可以通过提前ptting测试来更正代码。这将意味着对第一个单词进行零测试,但至少逻辑是清楚的。
您可以通过以下几种方式改进代码:
-
尽量消除代码的重复。目前,你的三个案例几乎相同。找到共同的部分并将它们合并为一个共同的函数。例如,方向实际上只是指通过网格的其他"运动矢量",即(0,1)表示oriental,(0,1,垂直)和(1,1)表示对角线。
-
一旦你有了这个,你就可以计算出前面位置的有效范围。没有必要调整坐标。
-
不要害羞地使用函数。将任务分离为函数意味着您必须传递一些数据,但这也意味着您可以在必要时立即跳出带有返回值的函数。这为您节省了大量
goto
和真值变量,也是C的流量控制方式。检查是否可以放置单词是函数的一个很好的候选者。也放置单词。
-
蒂姆B建议重新设置。这是个好主意,因为如果你的话太长,你可能会把自己逼到墙角。
以下是您代码的修订版(或者更确切地说是重写版),它不会随机选择单词:
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <time.h>
int isvalid(char matrix[10][10], int x, int y, int dx, int dy, int len)
{
for (int i = 0; i < len; i++) {
if (matrix[y][x] != '-') return 0;
x += dx;
y += dy;
}
return 1;
}
void matrix_fill(char matrix[10][10], const char *words[4])
{
int dx[3] = {1, 0, 1}; // horizontal strides
int dy[3] = {0, 1, 1}; // vertical strides
startover:
for (int i = 0; i < 10; i++) {
for (int j = 0; j < 10; j++) {
matrix[j][i] = '-';
}
}
for (int i = 0; i < 4; i++) {
const char *word = words[i];
int len = strlen(word);
int orient, x, y;
int tries = 0;
int valid;
if (len > 8) break; // just to be sure
do {
orient = rand() % 3;
x = rand() % (10 - dx[orient] * len);
y = rand() % (10 - dy[orient] * len);
valid = isvalid(matrix, x, y,
dx[orient], dy[orient], len);
tries++;
} while (!valid && tries < 100);
if (!valid) goto startover;
for (int i = 0; i < len; i++) {
matrix[y][x] = word[i];
x += dx[orient];
y += dy[orient];
}
}
}
void matrix_print(char matrix[10][10])
{
printf("%4s ", "");
for (int i = 0; i < 10; i++) {
printf("%4c", 'A' + i);
}
printf("nn");
for (int j = 0; j < 10; j++) {
printf("%4d ", j);
for (int i = 0; i < 10; i++) {
printf("%4c", matrix[j][i]);
}
printf("nn");
}
}
int main()
{
const char *dictionary[4] = {"apple", "pear", "cherry", "lemon"};
char matrix[10][10];
srand(time(NULL));
matrix_fill(matrix, dictionary);
matrix_print(matrix);
return 0;
}