场景故事5 石头与钻石 5.1 场景故事 很久以前,一位好心的农夫路遇一位落魄的老人,农夫就把身上的8个铜钱送 给了这位老人。后来的某一天,农夫又遇见了他曾经帮助过的这位老人。 老人突然对他说:“我这里有8块一模一样的小石头,你整理出一块长方形的 农田,把它再划分成大小相等的一些小方块,然后把这8块石头分别放到你划分出 的小方块里,但必须要保证在有小石头的方块中,每个方块只能放一块小石头。” 农夫问:“在农田里放石头,又不会长出庄稼,你为何要让我这样做呢?” 老人说:“这些小石头是很神奇的,你一旦把它们放入农田的小方块中,农 田中的小方块就会慢慢地发生神奇的变化。” 农夫又问:“会发生什么变化啊?” 老人答道:“农田里没有放小石头的小方块,可能在第二天出现小石头或继 续没有小石头;而放有小石头的小方块,到了第二天小石头可能消失了或仍有小石 头。你的农田中每个小方块的邻居就是它旁边的8个小方块,注意至多8个。” 然后,老人说出了变化的秘密: 如果一个小方块的邻居中有3个小方块里有小石头,第二天,该小方块里有小 石头。 如果一个小方块的邻居中有两个小方块里有小石头,第二天,该小方块的状 态保持不变,即如果原来小方块有小石头就仍有小石头,小方块没有小石头就仍没 有小石头。 如果是其他情况,第二天,小方块里没有石头。 老人还在地上给农夫画了一个石头奥妙图,如图5.1所示。这个图很好地解释 了其中的奥妙(变化规律)。 接着老人告诉农夫一件让农夫更为惊讶的事情,老人对农夫说:“如果在50 天的时间里,农田里小方块的状态从某天开始不再发生变化,那么这些小石头就都 会变成钻石。而且,小石头在农田里分布得越好看,变成的钻石的质量就越大!” 石头与钻石 场 景 故 事5 场景故事5 石头与钻石21 说完,老人便消失了。 图5.1 石头奥妙图 农夫每天都在琢磨怎样把小石头放入农田的小方块里。农夫很聪明,他知道 农田里小方块的后续状态依赖于第1天的状态。农夫经过分析,认为几天之后农田 会出现以下3种可能的情况。 ① 农田里的小方块可能会进入一个稳定状态,即有部分石头不再随时间变化 而变化。 ② 农田可能在某一天进入一个周期状态,即在几个状态之间周而复始地循环 往复。 ③ 农田在某一天也许会进入一个非常糟糕的稳定状态,即农田里每个小方块 里都没有石头了! 后来,农夫想出了一个放石头的方案,最后收获了40颗钻石。假如你是这位 农夫,你能得到比他更多的钻石吗? 本故事纯属虚构,如有雷同,纯属巧合。 5.2 场景故事的目的 1. 侧重点 二维数组的复制和迭代的算法以及怎样使用控制和循环语句操作二维数组。 22 趣懂Java旋律,击破36个难点 2. 涉及的其他知识点 复制数组的方法代码如下: public static int[] copyOf (int[] original) 该方法可以把参数original指定的一维int型数组的单元的值复制到一个新的 一维int型数组中,并返回这个数组的引用,即新数组的长度等于数组original的长 度,各个单元的值也和数组original的完全相同。 3. 进一步的尝试 试输出农田里中小石头变化过程中的某个中间状态,如输出第5天和第12天的 状态。 5.3 程序运行效果与视频讲解 从一个位置开始纵向放置8个小石头。主类是StoneAndDiamond。程序运行效 果如图5.2(a)和图5.2(b)所示。 图5.2 石头与钻石的程序运行效果 5.4 阅读源代码 StoneAndDiamond.java的代码如下: 视频讲解 场景故事5 石头与钻石23 import java.util.Arrays; public class StoneAndDiamond { public static void main(String args[]){ int [][] farmland = new int[20][33]; //刻画农田状态的二维数组 int maxDays = 50; //看50天内农田的变化 for(int i=6;i<=13;i++){ farmland[i][17] = 1; //1表示方块里有石头 } System.out.println("农田的初始状态:"); //输出初始状态 for(int i=0;i<farmland.length;i++ ) { for(int j = 0;j<farmland[i].length;j++){ if(farmland[i][j] == 1) System.out.printf("%s","●"); //表示有石头 else System.out.printf("%s","□"); //表示没有石头 } System.out.println(); } int [][] copyOfFarmland = new int[farmland.length][]; for(int m = 0;m<copyOfFarmland.length;m++) { //将farmland复制到数组copyOfFarmland copyOfFarmland[m] = Arrays.copyOf(farmland[m],farmland[m]. length); } int day = 1; while(day<=maxDays) { for(int i=0;i<copyOfFarmland.length;i++ ) { for(int j = 0;j<copyOfFarmland[i].length;j++){ //检查copyOfFarmland[i][j]周围活的石头个数 int stoneCounts = 0; //石头个数 if(i<copyOfFarmland.length-1) { if(copyOfFarmland[i+1][j] == 1) //检查当前小方块的正下方 stoneCounts++; } if(i>=1) { if(copyOfFarmland[i-1][j] == 1) //检查当前小方块的正上方 stoneCounts++; } if(j<copyOfFarmland[i].length-1) { if(copyOfFarmland[i][j+1] == 1) //检查当前小方块的正右方 stoneCounts++; } if(j>=1) { if(copyOfFarmland[i][j-1] == 1) //检查当前小方块的正左方 24 趣懂Java旋律,击破36个难点 stoneCounts++; } if(i<copyOfFarmland.length-1&&j<copyOfFarmland[i]. length-1){ if(farmland[i+1][j+1] == 1) //检查当前小方块的右下方 stoneCounts++; } if(i<copyOfFarmland.length-1&&j>=1){ if(farmland[i+1][j-1] == 1) //检查当前小方块的左下方 stoneCounts++; } if(i>=1&&j>=1){ if(copyOfFarmland[i-1][j-1] == 1) //检查当前小方块的左上方 stoneCounts++; } if(i>=1&&j<copyOfFarmland[i].length-1){ if(copyOfFarmland[i-1][j+1] == 1) //检查当前小方块的右上方 stoneCounts++; } if( stoneCounts == 3){ farmland[i][j] = 1; //方块里有石头 } else if(stoneCounts == 2){ //保持不变 } else { farmland[i][j] = 0; } } } //判断农田是否进入稳定状态 boolean isStable = true; for(int m = 0;m<copyOfFarmland.length;m++) { if(!Arrays.equals(farmland[m],copyOfFarmland[m])) { isStable = false; break; } } if(isStable) { break; //结束while循环语句 } day++; //继续执行while循环语句到下一天 场景故事5 石头与钻石25 for(int m = 0;m<copyOfFarmland.length;m++) { //将farmland复制到数组copyOfFarmland copyOfFarmland[m] = Arrays.copyOf(farmland[m],farmland[m]. length); } } if(day<=maxDays){ //存在稳定状态,输出稳定状态的样子 System.out.println("在第"+day+"天进入稳定状态:"); for(int i=0;i<farmland.length;i++ ) { for(int j = 0;j<farmland[i].length;j++){ if(farmland[i][j] == 1) System.out.printf("%s","◆"); //表示农田里有钻石 else System.out.printf("%s","□"); } System.out.println(); } } else { System.out.println("在"+maxDays+"天内没进入稳定状态,目前状态是:"); for(int i=0;i<farmland.length;i++ ) { for(int j = 0;j<farmland[i].length;j++){ if(farmland[i][j] == 1) System.out.printf("%s","●"); else System.out.printf("%s","□"); } System.out.println(); } } } }