如何将许多 if 语句压缩成更小且更易读的内容?
How to condense many if-statements into something smaller and more readable?
我正在为生活游戏编写代码。其中一个功能应该是 "evolve" 当前的一组单元格。这意味着我必须有一些条件,如果 if 语句满足条件,则单元格将变为 DEAD 或 ALIVE 单元格。
但是,只有一些下一个单元格正在初始化,所以我必须将其余下一个单元格设置为 DEAD,这些单元格不受条件影响。
由于有四个条件,我想将我的 if 语句压缩到尽可能少的数量。
条件是:
- 具有 0 或 1 个存活邻居的细胞在下一代死亡。
- 有 2 或 3 个存活邻居的细胞会存活到下一代。
- 具有 4 个或更多存活邻居的细胞会在下一代死亡。
- 刚好有 3 个活着的邻居的空牢房变成了活牢房
下一代细胞。
我已经尝试将尽可能多的条件拟合到一个 if 语句和一个 else 语句中,这意味着如果没有单元格满足条件,它将自动设置为 DEAD。这样 field[i][j].next
中的所有细胞要么死要么活。
我想提一下,数组 field[i][j].current
已经用 DEAD 和 ALIVE 单元格进行了初始化。
void evolve(const int rows,const int cols,cell field[rows][cols], int
NeighbourCounter[i][j]){
CellNeighbour(rows, cols,field,NeighbourCounter);
for(int i = 0;i<rows;i++){
for(int j =0;j<cols;j++){
if(field[i][j].current == ALIVE && NeighbourCounter[i][j] < 2){
field[i][j].next == DEAD;
}
if(field[i][j].current == ALIVE && NeighbourCounter[i][j] == ||NeighbourCounter[i][j] == 2){
field[i][j].next = ALIVE;
}
if(field[i][j].current == ALIVE && NeighbourCounter[i][j] >= 4){
field[i][j].next = DEAD;
}
if(field[i][j].current == DEAD && NeighbourCounter[i][j] == 3){
field[i][j].next = ALIVE;
}
}
else{
field[i][j].next = DEAD;
}
}
NeighbourCounter
是一个数组,用于计算每个单元格有多少个 ALIVE 邻居。
预期的输出应该是 field[rows][cols]
应该更新并且更新的版本存储在 ``field[rows][cols].next` 中。
How to condense many if-statements into something smaller and more
readable?
您使用的代码格式不正确。
例如,不清楚以下 else 语句与哪个 if 语句配对。
else{
field[i][j].next = DEAD;
}
错误的代码格式通常是许多错误(包括逻辑错误)的根源。:)
所有这些 if 语句
if(field[i][j].current == ALIVE && NeighbourCounter[i][j]<2){
field[i][j].next == DEAD;
}
if(field[i][j].current == ALIVE && NeighbourCounter[i][j] ==3
||NeighbourCounter[i][j] ==2 ){
field[i][j].next = ALIVE;
}
if(field[i][j].current == ALIVE && NeighbourCounter[i][j] >= 4
){
field[i][j].next = DEAD;
}
//...
可以改写成
if ( field[i][j].current == ALIVE )
{
if ( NeighbourCounter[i][j] < 2 )
{
field[i][j].next == DEAD;
}
else if ( NeighbourCounter[i][j] < 4 )
{
field[i][j].next = ALIVE;
}
else
{
field[i][j].next = DEAD;
}
}
else if ( field[i][j].current == DEAD )
{
if ( NeighbourCounter[i][j] == 3 )
{
field[i][j].next = ALIVE;
}
}
// ...
这使代码更具可读性。
作为替代方法,您可以使用 switch 语句,例如 this
switch ( field[i][j].current )
{
case ALIVE:
{
// ...
}
case DEAD:
{
// ...
}
default:
{
// ...
}
}
简单地 switch
邻居计数的值可能是最简单和最清楚的,如下所示:
for (int i = 0; i < rows; ++i) {
for (int j = 0; j < cols; ++j) {
switch (NeighbourCounter[i][j]) {
case 0:
case 1:
/* cell dies without enough support */
field[i][j].next = DEAD; /* I assume you meant =, not == */
break;
case 2:
/* two neighbours can support a live cell */
field[i][j].next = field[i][j].current;
break;
case 3:
/* three neighbours can resurrect a dead one */
field[i][j].next = ALIVE;
break;
case 4:
case 5:
case 6:
case 7:
case 8:
/* more than three is a crowd */
field[i][j].next = DEAD;
break;
default:
fprintf(stderr, "Invalid value %d from NeighbourCounter\n",
NeighbourCounter[i][j]);
}
}
}
您会看到 case 2
是唯一需要 current
值的;所有其他的只取决于邻居的数量。
一种强大的函数编码技术是lookup tables。邻居数限制在 0...9 范围内,状态数为 2,因此您可以使用大小为 20:
的查找 table
bool NewStateLUT[2][10] = {
{0, 0, 0, 1, 0, 0, 0, 0, 0, 0}, // new states for dead cells
{0, 0, 1, 1, 0, 0, 0, 0, 0, 0} // new states for alive cells
};
使用这个的代码table:
whatever.next = NewStateLUT[whatever.current][NeighbourCounter];
此代码假定 DEAD
为 0,ALIVE
等于 1。如果 DEAD
和 ALIVE
是枚举数,则可能需要调整语法。
由于LUT只包含0和1,所以用位图代替数组很容易:
uint32_t NewStateBitmap = 0b0000000100'0000001100;
whatever.next = (NewStateBitmap >> (whatever.current * 10 + NeighbourCounter)) & 1;
如果一个细胞有 3 个邻居,或者如果它目前还活着并且有两个邻居,那么它在下一代还活着。
这也许有点异端,但我想知道常量 ALIVE 和 DEAD 是否没有妨碍。另一种方法是将字段 current 重命名为 now_alive 并在 next_alive 旁边,然后在其中存储 0 或 1。
那么next alive的计算就可以写成
C->next_alive = (N == 3) || (C->now_alive+N) == 3;
其中 C 指向单元格,N 是它的邻居数。
我正在为生活游戏编写代码。其中一个功能应该是 "evolve" 当前的一组单元格。这意味着我必须有一些条件,如果 if 语句满足条件,则单元格将变为 DEAD 或 ALIVE 单元格。
但是,只有一些下一个单元格正在初始化,所以我必须将其余下一个单元格设置为 DEAD,这些单元格不受条件影响。
由于有四个条件,我想将我的 if 语句压缩到尽可能少的数量。
条件是:
- 具有 0 或 1 个存活邻居的细胞在下一代死亡。
- 有 2 或 3 个存活邻居的细胞会存活到下一代。
- 具有 4 个或更多存活邻居的细胞会在下一代死亡。
- 刚好有 3 个活着的邻居的空牢房变成了活牢房 下一代细胞。
我已经尝试将尽可能多的条件拟合到一个 if 语句和一个 else 语句中,这意味着如果没有单元格满足条件,它将自动设置为 DEAD。这样 field[i][j].next
中的所有细胞要么死要么活。
我想提一下,数组 field[i][j].current
已经用 DEAD 和 ALIVE 单元格进行了初始化。
void evolve(const int rows,const int cols,cell field[rows][cols], int
NeighbourCounter[i][j]){
CellNeighbour(rows, cols,field,NeighbourCounter);
for(int i = 0;i<rows;i++){
for(int j =0;j<cols;j++){
if(field[i][j].current == ALIVE && NeighbourCounter[i][j] < 2){
field[i][j].next == DEAD;
}
if(field[i][j].current == ALIVE && NeighbourCounter[i][j] == ||NeighbourCounter[i][j] == 2){
field[i][j].next = ALIVE;
}
if(field[i][j].current == ALIVE && NeighbourCounter[i][j] >= 4){
field[i][j].next = DEAD;
}
if(field[i][j].current == DEAD && NeighbourCounter[i][j] == 3){
field[i][j].next = ALIVE;
}
}
else{
field[i][j].next = DEAD;
}
}
NeighbourCounter
是一个数组,用于计算每个单元格有多少个 ALIVE 邻居。
预期的输出应该是 field[rows][cols]
应该更新并且更新的版本存储在 ``field[rows][cols].next` 中。
How to condense many if-statements into something smaller and more readable?
您使用的代码格式不正确。 例如,不清楚以下 else 语句与哪个 if 语句配对。
else{
field[i][j].next = DEAD;
}
错误的代码格式通常是许多错误(包括逻辑错误)的根源。:)
所有这些 if 语句
if(field[i][j].current == ALIVE && NeighbourCounter[i][j]<2){
field[i][j].next == DEAD;
}
if(field[i][j].current == ALIVE && NeighbourCounter[i][j] ==3
||NeighbourCounter[i][j] ==2 ){
field[i][j].next = ALIVE;
}
if(field[i][j].current == ALIVE && NeighbourCounter[i][j] >= 4
){
field[i][j].next = DEAD;
}
//...
可以改写成
if ( field[i][j].current == ALIVE )
{
if ( NeighbourCounter[i][j] < 2 )
{
field[i][j].next == DEAD;
}
else if ( NeighbourCounter[i][j] < 4 )
{
field[i][j].next = ALIVE;
}
else
{
field[i][j].next = DEAD;
}
}
else if ( field[i][j].current == DEAD )
{
if ( NeighbourCounter[i][j] == 3 )
{
field[i][j].next = ALIVE;
}
}
// ...
这使代码更具可读性。
作为替代方法,您可以使用 switch 语句,例如 this
switch ( field[i][j].current )
{
case ALIVE:
{
// ...
}
case DEAD:
{
// ...
}
default:
{
// ...
}
}
简单地 switch
邻居计数的值可能是最简单和最清楚的,如下所示:
for (int i = 0; i < rows; ++i) {
for (int j = 0; j < cols; ++j) {
switch (NeighbourCounter[i][j]) {
case 0:
case 1:
/* cell dies without enough support */
field[i][j].next = DEAD; /* I assume you meant =, not == */
break;
case 2:
/* two neighbours can support a live cell */
field[i][j].next = field[i][j].current;
break;
case 3:
/* three neighbours can resurrect a dead one */
field[i][j].next = ALIVE;
break;
case 4:
case 5:
case 6:
case 7:
case 8:
/* more than three is a crowd */
field[i][j].next = DEAD;
break;
default:
fprintf(stderr, "Invalid value %d from NeighbourCounter\n",
NeighbourCounter[i][j]);
}
}
}
您会看到 case 2
是唯一需要 current
值的;所有其他的只取决于邻居的数量。
一种强大的函数编码技术是lookup tables。邻居数限制在 0...9 范围内,状态数为 2,因此您可以使用大小为 20:
的查找 tablebool NewStateLUT[2][10] = {
{0, 0, 0, 1, 0, 0, 0, 0, 0, 0}, // new states for dead cells
{0, 0, 1, 1, 0, 0, 0, 0, 0, 0} // new states for alive cells
};
使用这个的代码table:
whatever.next = NewStateLUT[whatever.current][NeighbourCounter];
此代码假定 DEAD
为 0,ALIVE
等于 1。如果 DEAD
和 ALIVE
是枚举数,则可能需要调整语法。
由于LUT只包含0和1,所以用位图代替数组很容易:
uint32_t NewStateBitmap = 0b0000000100'0000001100;
whatever.next = (NewStateBitmap >> (whatever.current * 10 + NeighbourCounter)) & 1;
如果一个细胞有 3 个邻居,或者如果它目前还活着并且有两个邻居,那么它在下一代还活着。
这也许有点异端,但我想知道常量 ALIVE 和 DEAD 是否没有妨碍。另一种方法是将字段 current 重命名为 now_alive 并在 next_alive 旁边,然后在其中存储 0 或 1。
那么next alive的计算就可以写成
C->next_alive = (N == 3) || (C->now_alive+N) == 3;
其中 C 指向单元格,N 是它的邻居数。