生命游戏的代码很优美,大家看我的注释像不像现代诗

fmddlmyy 2008-01-03 12:19:53
...
Grid map; // square array holding cells 二维数组的,四周有一圈篱笆的世界
Gridcount numNeighbors; // square array holding neighbor counts 二维数组的邻居数量
List newlive, // cells that have just been vivified 新出生的队列
newdie, // cells that have just died 刚死掉的队列
maylive, // candidates to vivify in next generation 可能即将出生的队列
maydie; // candidates to kill in next generation 可能即将死掉的队列
...

int main(int argc, char* argv[])
{
...
Initialize(map, numNeighbors, &newlive, &newdie, &maylive, &maydie, fName, &gens, &c1, &c2);
while (gencount < gens) {//如果没有结束
gencount++;
TraverseList(&maylive, Vivify);// 就让可能即将出生的队列中确实应该出生的出生
TraverseList(&maydie, Kill); // 让可能即将死掉的队列中确实应该死掉的死掉
ClearList(&maylive); // 清除即将出生的队列
ClearList(&maydie); // 清除即将死掉的队列
TraverseList(&newlive, AddNeighbors); // 根据新生的队列调整邻居的数量,调整可能即将生的队列和可能即将死的队列
TraverseList(&newdie, SubtractNeighbors); // 根据刚死的队列调整邻居的数量,调整可能即将生的队列和可能即将死的队列
ClearList(&newlive); // 清除新出生的队列
ClearList(&newdie); // 清除刚死掉的队列
}
WriteMap(map, gencount, c1, c2); // 输出要输出的
return 0;
}

void AddNeighbors(Cell cell)
{// Check neighbors around cell that has recently come to life
// Update neighbor counts of cells around cell of interest; add to appropriate list
int nbrrow, // loop index for row of neighbor loops
nbrcol; // column loop index
Cell neighbor; // structure form of a neighbor

for (nbrrow = cell.row-1; nbrrow <=cell.row+1; nbrrow++)//3次循环
for (nbrcol = cell.col-1; nbrcol <=cell.col+1; nbrcol++)//3次循环
if (nbrrow != cell.row || nbrcol != cell.col) { //skip cell itself跳过自己,只处理周围8个
numNeighbors[nbrrow][nbrcol]++;// 刚出生的我是周围8个单元的新邻居
switch(numNeighbors[nbrrow][nbrcol]) {
case 0:
Error("Impossible case in AddNeighbors.");//刚加过1,怎么可能
break;
case 3: //如果有3个邻居
if (map[nbrrow][nbrcol] == DEAD) {//而且原来是死的
neighbor.row = nbrrow;
neighbor.col = nbrcol;
AddList(neighbor, &maylive);//下一次就可能生了
}
break;
case 4://如果有4个邻居
if (map[nbrrow][nbrcol] == ALIVE) {//而且原来是活的
neighbor.row = nbrrow;
neighbor.col = nbrcol;
AddList(neighbor, &maydie);//下一次就可能死了
}
break;
} // switch

}
}


void Vivify(Cell cell)
{// Determine if conditions are right for cell to be brought to life
if (map[cell.row][cell.col] == DEAD &&// 如果原来是死的而且
numNeighbors[cell.row][cell.col] == 3)// 有3个邻居
if (cell.row >= 1 && cell.row <= MAXROW &&
cell.col >= 1 && cell.col <= MAXCOL) {// 如果在篱笆里面
map[cell.row][cell.col] = ALIVE;// 让他生
AddList(cell, &newlive);// 加入新生的队列
}
}

void SubtractNeighbors(Cell cell)
{// Check number of neighbors around cell that has recently died
// Update neighbor counts of cells around cell of interest; add to appropriate list
int nbrrow, // loop index for row of neighbor loops
nbrcol; // column loop index
Cell neighbor; // structure form of a neighbor

for (nbrrow = cell.row-1; nbrrow <=cell.row+1; nbrrow++)//3行
for (nbrcol = cell.col-1; nbrcol <=cell.col+1; nbrcol++)//3列
if (nbrrow != cell.row || nbrcol != cell.col) { //skip cell itself去掉自己
numNeighbors[nbrrow][nbrcol]--;// 自己死掉了,周围的8个单元少了一个邻居
switch(numNeighbors[nbrrow][nbrcol]) {
case 8:
Error("Impossible case in SubtractNeighbors.");//刚减掉一个,怎么可能
break;
case 3: //如果有3个邻居
if (map[nbrrow][nbrcol] == DEAD) {//而且原来是死的
neighbor.row = nbrrow;
neighbor.col = nbrcol;
AddList(neighbor, &maylive);//下次可能生了
}
break;
case 1://如果有1个邻居
if (map[nbrrow][nbrcol] == ALIVE) {//而且原来是活的
neighbor.row = nbrrow;
neighbor.col = nbrcol;
AddList(neighbor, &maydie);//下次可能死了
}
break;
} // switch

}
}

void Kill(Cell cell)
{// Determine if conditions are right for cell to be killed
if (map[cell.row][cell.col] == ALIVE &&// 如果原来是生的
(numNeighbors[cell.row][cell.col] > 3 ||//如果邻居多于3个
numNeighbors[cell.row][cell.col] < 2))//或者少于2个
if (cell.row >= 1 && cell.row <= MAXROW &&
cell.col >= 1 && cell.col <= MAXCOL) {// 如果在篱笆里面
map[cell.row][cell.col] = DEAD;//让他死
AddList(cell, &newdie);// 加入刚死的队列
}
}

void Initialize(Grid map, Gridcount numNeighbors,
List *newlive, List *newdie,
List *maylive, List *maydie,
char *fName, int *gens, Cell *c1, Cell *c2)
{
int row, col;

CreateList(newlive); // 创建4个空队列
CreateList(newdie);
CreateList(maylive);
CreateList(maydie);

// Obtain the initial configuration
ReadMap(newlive, map, fName, gens, c1, c2);// 读输入文件,建立了刚出生队列

// Set all entries in numNeighbors to 0
for (row=0; row <= MAXROW+1; row++)
for (col=0; col <= MAXCOL+1; col++)
numNeighbors[row][col] = 0;// 清空邻居数数组

// Put the candidates to live into maylive
TraverseList(newlive, AddNeighbors);// 根据新生的队列调整邻居数,调整可能即将生的队列和可能即将死的队列

// Check all living cells to see which may die
CopyList(maydie, newlive);// 将新生的队列复制到可能即将死的队列
ClearList(newlive);//清除新生的队列
}
...
void ReadMap(List *newlive, Grid map, char *fName, int *gens, Cell *c1, Cell *c2)
{//Read in the initial configuration of cells, number of generations to simulate,
// and the region to be printed after the final generation
...

for (row=0; row <= MAXROW+1; row++)
for (col=0; col <= MAXCOL+1; col++)
map[row][col] = DEAD; // Set all cells empty, including the hedge连四周的篱笆都设成空

if ((fp = fopen(fName, "r")) == NULL) Error("Input file not found");
printf("Reading input data from %s...",fName);
fscanf(fp,"%d %d",&row, &col);// 读一个单元的行列值
//Read row,col pairs until 0,0 marker read
while (row != 0 || col != 0) { // 直到行列值都是0
if (row >= 1 && row <= MAXROW && col >= 1 && col <= MAXCOL) {
newcell.row = row;
newcell.col = col;
if (map[row][col] == DEAD) {
AddList(newcell, newlive); // no dups夹到刚出生的队列,他们是第一代出生的
good++;// 累计有效的
}
else {
dup++; // 累计重复的
}
map[row][col] = ALIVE;// 让他生
}
else {
bad++;// 累计错误的
}
fscanf(fp,"%d %d",&row, &col);// 读下一个
}
// Get number of generations to be simulated
fscanf(fp,"%d", gens);// 0 0后面是要繁衍的代数
// Get region bounds for final print
fscanf(fp,"%d %d %d %d",&(c1->row), &(c1->col), &(c2->row), &(c2->col));// 再后面是输出的范围

printf("Done.\n %d Cells created",good);// 打印读到的东西
...
}
...全文
2764 51 打赏 收藏 转发到动态 举报
写回复
用AI写文章
51 条回复
切换为时间正序
请发表友善的回复…
发表回复
killgxlin 2008-01-20
  • 打赏
  • 举报
回复
fmddlmyy 是个精力充沛的小伙子
killgxlin 2008-01-14
  • 打赏
  • 举报
回复
fmddlmyy 给了跟大启发,就此谢过,看来这回的图书会有希望了。
huzhenqi2008 2008-01-13
  • 打赏
  • 举报
回复
真的很强大 不顶不行
pure_sky 2008-01-13
  • 打赏
  • 举报
回复
我新手,怎么看不出你的多线程用到tbb,有研究过的,
能否大概讲解一下,intel网站上都是英文的<看不懂>
wangwei8888 2008-01-13
  • 打赏
  • 举报
回复
mark...
godss 2008-01-13
  • 打赏
  • 举报
回复
for (i=0; i < (MAXCOL/2-7); i++) putchar(' ');

这行有什么用?在WriteMap里面的。完全是废代码啊,还浪费好多时间的
rouqu 2008-01-12
  • 打赏
  • 举报
回复
真的很强大 不顶不行
antimatterworld 2008-01-11
  • 打赏
  • 举报
回复
很强大
killgxlin 2008-01-11
  • 打赏
  • 举报
回复
icl /O2 /MD /S GameOfLife.cpp
查看GameOfLife.asm 534行——542行

$B5$9: ; Preds $B5$7 $B5$5
; numNeighbors[][]=>esi
mov esi, DWORD PTR ?numNeighbors@@3PAY0BDIK@HA[ebx+ebp*4] ;58.13

; esi+=1
add esi, 1 ;58.13

; esi=>numNeighbors[][]
mov DWORD PTR ?numNeighbors@@3PAY0BDIK@HA[ebx+ebp*4], esi ;58.13
;switch(esi)
;case 0:
je $B5$16 ; Prob 25% ;59.13
; LOE eax edx ecx ebx ebp esi edi
$B5$10: ; Preds $B5$9
;case 3:
cmp esi, 3 ;59.13
jne $B5$14 ; Prob 67% ;59.13

可见switch括号中的numNeighbors[][]并不是最新的值,而是esi保存的副本
因此即使不采用楼主在30楼的方法也不会出错
不过换一种编译方式或者换一种编译器汇编代码不同,可能会出问题。
wooden954 2008-01-11
  • 打赏
  • 举报
回复
源代码质量的确不错,如果我们也做到这样的水平,那多好呀。。。。。。
ximi82878 2008-01-11
  • 打赏
  • 举报
回复
都这么强了啊,真厉害,得多学习学习
ccdd14 2008-01-10
  • 打赏
  • 举报
回复
直言说,注释的不尽如人意。
注释的职责应该是提高代码的可读性。

以上代码的质量也并非想象的那么优美。
在某些变量和函数的命名上还是有些随意,
好的命名应该是让人一看就大概知道是做什么的。

在代码风格上,并没有做到完全的统一。

在代码的结构上,产生了内容耦合,
虽然耦合是不可避免的,
但在这里,可以将耦合度降为数据耦合。

当然并没有完美的代码。
fmddlmyy 2008-01-10
  • 打赏
  • 举报
回复
解1:每个线程向独立的队列加元素就不会冲突。
解2:对要处理的单元分组,如果每个线程处理的单元没有相同的邻居就不会冲突。如果有边界单元,就拉出来在单线程里完成。
解3:在给线程分组时,去掉重复的单元,就不用给Vivify和Kill加锁了。
那么怎么分组呢?应该不难吧。不过要使分组算法的开销尽可能小,各组单元数还要尽量相近。既然是比着玩,就不多说了。
说了一种可能的思路,相信大家能想到更好、更快的去锁方法吧。
fmddlmyy 2008-01-10
  • 打赏
  • 举报
回复
串行改并行后有3个地方需要加锁
1、AddList中加元素的地方
2、AddNeighbors和SubtractNeighbors中需要增减邻居数的地方
3、由于maylive和maydie有重复项,如果不去掉重复项,就要在Vivify和Kill中加锁
只要解决这3个问题就可以不加锁
fmddlmyy 2008-01-10
  • 打赏
  • 举报
回复
不加锁的算法其实也很容易想到,我来说说吧
denghui0815 2008-01-10
  • 打赏
  • 举报
回复
呵呵 分块也有边界问题需要处理 我已经完成不加锁的算法了 竞赛结束后会公开给大家
瓶盒 2008-01-10
  • 打赏
  • 举报
回复
我觉得按地图分块来划分任务要好一些
fmddlmyy 2008-01-10
  • 打赏
  • 举报
回复
下次我在发帖时一定要在顶楼就把事情解释清楚,不能在15楼才解释:)否则会产生很多误会

看来参加这个线程比赛的人很少啊,我只看到denghui0815 。其实当作智力游戏还是有点意思的。

我后来想想还是尽量不要加锁。否则很难让并行的速度超过串行速度。
怎样不加锁,又不出错,而且算法的运算量还要尽可能小呢?
fmddlmyy 2008-01-09
  • 打赏
  • 举报
回复
这种场合使用InterlockedIncrement太慢了,还是使用循环锁只锁冲突地址更合理些。
denghui0815 2008-01-08
  • 打赏
  • 举报
回复
把循环展开应该可以吧
加载更多回复(31)

566

社区成员

发帖
与我相关
我的任务
社区描述
英特尔® 边缘计算,聚焦于边缘计算、AI、IoT等领域,为开发者提供丰富的开发资源、创新技术、解决方案与行业活动。
社区管理员
  • 英特尔技术社区
  • shere_lin
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧