摘要:如果多核的機(jī)器如何優(yōu)化因?yàn)槭嵌嗪耍覀兛梢杂镁€程來(lái)實(shí)現(xiàn)并行計(jì)算。如果線程變多分塊變多,邊緣信息也會(huì)變多,開(kāi)銷會(huì)增大。所以選取線程的數(shù)量是這個(gè)開(kāi)銷和并行計(jì)算能力的折衷。
Game of Life I
編解碼法 復(fù)雜度According to the Wikipedia"s article: "The Game of Life, also known simply as Life, is a cellular automaton devised by the British mathematician John Horton Conway in 1970."
Given a board with m by n cells, each cell has an initial state live (1) or dead (0). Each cell interacts with its eight neighbors (horizontal, vertical, diagonal) using the following four rules (taken from the above Wikipedia article):
Any live cell with fewer than two live neighbors dies, as if caused by under-population. Any live cell with two or three live neighbors lives on to the next generation. Any live cell with more than three live neighbors dies, as if by over-population.. Any dead cell with exactly three live neighbors becomes a live cell, as if by reproduction. Write a function to compute the next state (after one update) of the board given its current state.
Follow up: Could you solve it in-place? Remember that the board needs to be updated at the same time: You cannot update some cells first and then use their updated values to update other cells. In this question, we represent the board using a 2D array. In principle, the board is infinite, which would cause problems when the active area encroaches the border of the array. How would you address these problems?
時(shí)間 O(NN) 空間 O(1)
思路最簡(jiǎn)單的方法是再建一個(gè)矩陣保存,不過(guò)當(dāng)inplace解時(shí),如果我們直接根據(jù)每個(gè)點(diǎn)周圍的存活數(shù)量來(lái)修改當(dāng)前值,由于矩陣是順序遍歷的,這樣會(huì)影響到下一個(gè)點(diǎn)的計(jì)算。如何在修改值的同時(shí)又保證下一個(gè)點(diǎn)的計(jì)算不會(huì)被影響呢?實(shí)際上我們只要將值稍作編碼就行了,因?yàn)轭}目給出的是一個(gè)int矩陣,大有空間可以利用。這里我們假設(shè)對(duì)于某個(gè)點(diǎn),值的含義為
0 : 上一輪是0,這一輪過(guò)后還是0 1 : 上一輪是1,這一輪過(guò)后還是1 2 : 上一輪是1,這一輪過(guò)后變?yōu)? 3 : 上一輪是0,這一輪過(guò)后變?yōu)?
這樣,對(duì)于一個(gè)節(jié)點(diǎn)來(lái)說(shuō),如果它周邊的點(diǎn)是1或者2,就說(shuō)明那個(gè)點(diǎn)上一輪是活的。最后,在遍歷一遍數(shù)組,把我們編碼再解回去,即0和2都變回0,1和3都變回1,就行了。
注意注意編碼方式,1和3都是這一輪過(guò)后為1,這樣就可以用一個(gè)模2操作來(lái)直接解碼了
我實(shí)現(xiàn)的時(shí)候并沒(méi)有預(yù)先建立一個(gè)對(duì)應(yīng)周圍8個(gè)點(diǎn)的數(shù)組,因?yàn)閷?shí)際復(fù)雜度是一樣,多加幾個(gè)數(shù)組反而程序可讀性下降
代碼public class Solution { public void gameOfLife(int[][] board) { int m = board.length, n = board[0].length; for(int i = 0; i < m; i++){ for(int j = 0; j < n; j++){ int lives = 0; // 判斷上邊 if(i > 0){ lives += board[i - 1][j] == 1 || board[i - 1][j] == 2 ? 1 : 0; } // 判斷左邊 if(j > 0){ lives += board[i][j - 1] == 1 || board[i][j - 1] == 2 ? 1 : 0; } // 判斷下邊 if(i < m - 1){ lives += board[i + 1][j] == 1 || board[i + 1][j] == 2 ? 1 : 0; } // 判斷右邊 if(j < n - 1){ lives += board[i][j + 1] == 1 || board[i][j + 1] == 2 ? 1 : 0; } // 判斷左上角 if(i > 0 && j > 0){ lives += board[i - 1][j - 1] == 1 || board[i - 1][j - 1] == 2 ? 1 : 0; } //判斷右下角 if(i < m - 1 && j < n - 1){ lives += board[i + 1][j + 1] == 1 || board[i + 1][j + 1] == 2 ? 1 : 0; } // 判斷右上角 if(i > 0 && j < n - 1){ lives += board[i - 1][j + 1] == 1 || board[i - 1][j + 1] == 2 ? 1 : 0; } // 判斷左下角 if(i < m - 1 && j > 0){ lives += board[i + 1][j - 1] == 1 || board[i + 1][j - 1] == 2 ? 1 : 0; } // 根據(jù)周邊存活數(shù)量更新當(dāng)前點(diǎn),結(jié)果是0和1的情況不用更新 if(board[i][j] == 0 && lives == 3){ board[i][j] = 3; } else if(board[i][j] == 1){ if(lives < 2 || lives > 3) board[i][j] = 2; } } } // 解碼 for(int i = 0; i < m; i++){ for(int j = 0; j < n; j++){ board[i][j] = board[i][j] % 2; } } } }
另一種編碼方式是位操作,將下輪該cell要變的值存入bit2中,然后還原的時(shí)候右移就行了。
public void solveInplaceBit(int[][] board){ int m = board.length, n = board[0].length; for(int i = 0; i < m; i++){ for(int j = 0; j < n; j++){ int lives = 0; // 累加上下左右及四個(gè)角還有自身的值 for(int y = Math.max(i - 1, 0); y <= Math.min(i + 1, m - 1); y++){ for(int x = Math.max(j - 1, 0); x <= Math.min(j + 1, n - 1); x++){ // 累加bit1的值 lives += board[y][x] & 1; } } // 如果自己是活的,周邊有兩個(gè)活的,lives是3 // 如果自己是死的,周邊有三個(gè)活的,lives是3 // 如果自己是活的,周邊有三個(gè)活的,lives減自己是3 if(lives == 3 || lives - board[i][j] == 3){ board[i][j] |= 2; } } } // 右移就是新的值 for(int i = 0; i < m; i++){ for(int j = 0; j < n; j++){ board[i][j] >>>= 1; } } }表優(yōu)化法 復(fù)雜度
時(shí)間 O(NN) 空間 O(512)
思路上面的方法實(shí)測(cè)都比較慢,對(duì)于5000*5000的矩陣計(jì)算時(shí)間都在600-1000ms,甚至比簡(jiǎn)單的用buffer的方法慢,我們?cè)俳榻B一個(gè)能將速度提高一倍的方法。一般來(lái)說(shuō),優(yōu)化程序有這么幾個(gè)思路:
盡量減少嵌套的循環(huán)
減少對(duì)內(nèi)存的讀寫操作
上個(gè)解法中,使用多個(gè)for循環(huán)的就比較慢,如果我們能夠直接計(jì)算出該點(diǎn)的值而不用for循環(huán)就好了。這里我們可以用一個(gè)“環(huán)境”變量,表示該點(diǎn)所處的環(huán)境,這樣我們根據(jù)它以及它周圍八個(gè)點(diǎn)的值就可以直接算出它的環(huán)境值,而不需要用for循環(huán)來(lái)檢查周圍8個(gè)點(diǎn)。有人說(shuō),這不就只是把讀取操作放到循環(huán)外面來(lái)了嗎?其實(shí)這只是用了優(yōu)化了第一點(diǎn),減少循環(huán),對(duì)于第二點(diǎn)我們也有優(yōu)化,我們計(jì)算環(huán)境值這樣計(jì)算,對(duì)于以n4為中心的點(diǎn),其環(huán)境為
n8 n5 n2 n7 n4 n1 n6 n3 n0
則環(huán)境值environment = n8 * 256 + n7 * 128 + n6 * 64 + n5 * 32 + n4 * 16 + n3 * 8 + n2 * 4 + n1 * 2 + n0 * 1,這么做的好處是把每一個(gè)格子的死活信息都用一個(gè)bit來(lái)表示,更巧妙地是當(dāng)我們計(jì)算以n1為中心的環(huán)境時(shí),是可以復(fù)用這些信息的,我們不用再讀取一遍n5, n4, n3, n2, n1, n0的值,直接將上一次的環(huán)境值模上64后再乘以8,就是可以將他們都向左平移一格,這時(shí)候再讀取三個(gè)新的值a, b, c就行了。
n8 n5 n2 a n7 n4 n1 b n6 n3 n0 c
通過(guò)這種方法,我們將內(nèi)存的讀取次數(shù)從每個(gè)點(diǎn)九次,變成了每個(gè)點(diǎn)三次。另外我們還要預(yù)先制作一個(gè)表,來(lái)映射環(huán)境值和結(jié)果的關(guān)系。比如環(huán)境值為7時(shí),說(shuō)明n2, n1, n0都是活的,結(jié)果應(yīng)該為1(下一輪活過(guò)來(lái))。這里制作表的程序可以這么寫:
int[] table = new int[512]; for(int i = 0; i < 512; i++){ int lives = Integer.bitCount(i); if(lives == 3 || (lives - ((i & 16) > 0 ? 1 : 0) == 3)){ table[i] = 1; } }代碼
public void solveWithTable(int rounds, int[][] board){ // 映射表 int[] lookupTable = {0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 1, 1, 0, 0, 0, 0, 1, 0, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 0, 1, 0, 0, 0, 0, 1, 1, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 0, 1, 0, 0, 0, 0, 1, 1, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 0, 1, 0, 0, 0, 0, 1, 1, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; int m = board.length, n = board[0].length; if(n == 0) return; int[][] buffer = new int[m][n]; for(int i = 0; i < m; i++){ // 每一行開(kāi)始時(shí),先計(jì)算初始的環(huán)境值(左邊兩列) int environment = (i - 1 >= 0 && board[i - 1][0] == 1? 4 : 0) + (board[i][0] == 1 ? 2 : 0) + (i + 1 < m && board[i + 1][0] == 1 ? 1 : 0); // 對(duì)該行的每一列,通過(guò)加入右邊新的一列,來(lái)計(jì)算該點(diǎn)的環(huán)境值 for(int j = 0; j < n; j++){ // 將之前的環(huán)境值模64再乘以8,然后加上右邊新的三列 environment = (environment % 64) * 8 + (i - 1 >= 0 && j + 1 < n && board[i - 1][j + 1] == 1 ? 4 : 0) + (j + 1 < n && board[i][j + 1] == 1 ? 2 : 0) + (i + 1 < m && j + 1 < n && board[i + 1][j + 1] == 1 ? 1 : 0); buffer[i][j] = lookupTable[environment]; } } for(int i = 0; i < m; i++){ for(int j = 0; j < n; j++){ board[i][j] = buffer[i][j]; } } }后續(xù) Follow Up
如果循環(huán)矩陣如何解決?循環(huán)的意思是假設(shè)一個(gè)3x3的矩陣,則a[0][0]的左邊是a[0][1],其左上是a[2][2]
這樣我們的坐標(biāo)要多加一個(gè)數(shù)組長(zhǎng)度,使用坐標(biāo)時(shí)還要取模
public void solveInplaceCircular(int rounds, int[][] board){ for(int round = 0; round < rounds; round++){ int m = board.length, n = board[0].length; for(int i = 0; i < m; i++){ for(int j = 0; j < n; j++){ int lives = 0; // 多加一個(gè)數(shù)組長(zhǎng)度 for(int y = i + m - 1; y <= i + m + 1; y++){ for(int x = j + n - 1; x <= j + n + 1; x++){ // 使用的時(shí)候要取模 lives += board[y % m][x % n] & 1; } } if(lives == 3 || lives - board[i][j] == 3){ board[i][j] |= 2; } } } for(int i = 0; i < m; i++){ for(int j = 0; j < n; j++){ board[i][j] >>>= 1; } } } }
如果矩陣很大如何優(yōu)化?
我們可以只記錄存活節(jié)點(diǎn)的信息,存入一個(gè)live的list中,這里active代表著存活節(jié)點(diǎn),或者存活節(jié)點(diǎn)的鄰居。每次只計(jì)算這個(gè)list中節(jié)點(diǎn)和其鄰居的情況。進(jìn)一步優(yōu)化的話,我們可以用一個(gè)active的list,只記錄上次更新的節(jié)點(diǎn),或者該節(jié)點(diǎn)的鄰居。等計(jì)算完這個(gè)列表后,將產(chǎn)生更新的節(jié)點(diǎn)和它的鄰居們存入一個(gè)新列表中,再用這個(gè)新列表里節(jié)點(diǎn)的值來(lái)更新矩陣。下一輪時(shí),就計(jì)算這個(gè)新列表,再產(chǎn)生一個(gè)新列表。
如果多核的機(jī)器如何優(yōu)化?
因?yàn)槭嵌嗪耍覀兛梢杂镁€程來(lái)實(shí)現(xiàn)并行計(jì)算。如圖,將矩陣分塊后,每個(gè)線程只負(fù)責(zé)其所在的分塊的計(jì)算,不過(guò)主線程每一輪都要更新一下這些分塊的邊緣,并提供給相鄰分塊。所以這里的開(kāi)銷就是主線程和子線程通信這個(gè)邊緣信息的開(kāi)銷。如果線程變多分塊變多,邊緣信息也會(huì)變多,開(kāi)銷會(huì)增大。所以選取線程的數(shù)量是這個(gè)開(kāi)銷和并行計(jì)算能力的折衷。
如果是多臺(tái)機(jī)器如何優(yōu)化?
同樣的,我們可以用一個(gè)主機(jī)器負(fù)責(zé)處理邊緣信息,而多個(gè)子機(jī)器處理每個(gè)分塊的信息,因?yàn)槭欠植际降模覀兊木仃嚳梢苑謮K的存儲(chǔ)在不同機(jī)器的內(nèi)存中,這樣矩陣就可以很大。而主機(jī)在每一輪開(kāi)始時(shí),將邊緣信息通過(guò)網(wǎng)絡(luò)發(fā)送給哥哥分塊機(jī)器,然后分塊機(jī)器計(jì)算好自己的分塊后,把新自己內(nèi)邊緣信息反饋給主機(jī)器。下一輪,等主機(jī)器收集齊所有邊緣后,就可以繼續(xù)重復(fù)。
不過(guò)多臺(tái)機(jī)器時(shí)還有一個(gè)更好的方法,就是使用Map Reduce。Map Reduce的簡(jiǎn)單版本是這樣的,首先我們的Mapper讀入一個(gè)file,這個(gè)file中每一行代表一個(gè)存活的節(jié)點(diǎn)的坐標(biāo),然后Mapper做出9個(gè)Key-Value對(duì),對(duì)這個(gè)存活節(jié)點(diǎn)的鄰居cell,分發(fā)出一個(gè)1。而對(duì)于節(jié)點(diǎn)自身,也要分發(fā)出一個(gè)1。這里Reducer是對(duì)應(yīng)每個(gè)cell的,每個(gè)reducer累加自己cell得到了多少個(gè)1,就知道自己的cell周圍有多少存活cell,就能知道該cell下一輪是否可以存活,如果可以存活則分發(fā)回mapper的文件中,等待下次讀取,如果不能則舍棄。
如果要進(jìn)一步優(yōu)化Map Reduce,那我們主要優(yōu)化的地方則是mapper和reducer通信的開(kāi)銷,因?yàn)閷?duì)于每個(gè)存活節(jié)點(diǎn),mapper都要向9個(gè)reducer發(fā)一次信息。我們可以在mapper中用一個(gè)哈希表,當(dāng)mapper讀取文件的某一行時(shí),先不向9個(gè)reducer發(fā)送信息,而是以這9個(gè)cell作為key,將1累加入哈希表中。這樣等mapper讀完文件后,再把哈希表中的cell和該cell對(duì)應(yīng)的累加1次數(shù),分發(fā)給相應(yīng)cell的reducer,這樣就可以減少一些通信開(kāi)銷。相當(dāng)于是現(xiàn)在mapper內(nèi)做了一次累加。這種優(yōu)化在只有一個(gè)mapper是無(wú)效的,因?yàn)檫@就等于直接在mapper中統(tǒng)計(jì)完了,但是如果多個(gè)mapper同時(shí)執(zhí)行時(shí),相當(dāng)于在每個(gè)mapper里先統(tǒng)計(jì)一會(huì),再交給reducer一起統(tǒng)計(jì)每個(gè)mapper的統(tǒng)計(jì)結(jié)果。
1: class Mapper: 2: method Map (): 3: hash = ? 4: for line ∈ stdin: 5: cell, state = Parse (line) 6: hash[cell] += state 7: for neighbor in Neighborhood (cell): 8: hash[neighbor] += 2*state 9: for cell in hash: 10: strip-number = cell.row / strip-length 11: Emit (cell, strip-number, hash[cell]) 1: class Reducer: 2: method Reduce (): 3: H = 0; last-cell = None 4: for line ∈ stdin: 5: strip-number, current-cell, in-value = Parse (line); 6: if current-cell ≠ last-cell : 7: if last-cell ≠ None: 8: Emit (last-cell, state=F(E(H)) 9: H = 0; last-cell = current-cell 10: H += in_value 11: Emit (last-cell, state=F(E(xi))
如果整個(gè)圖都會(huì)變,有沒(méi)有更快的方法?
參見(jiàn)Hashlife,大意是用哈希記錄一下會(huì)重復(fù)循環(huán)的pattern
編解碼法 復(fù)雜度In Conway"s Game of Life, cells in a grid are used to simulate biological cells. Each cell is considered to be either alive or dead. At each step of the simulation each cell"s current status and number of living neighbors is used to determine the status of the cell during the following step of the simulation.
In this one-dimensional version, there are N cells numbered 0 through N-1. The number of cells does not change at any point in the simulation. Each cell i is adjacent to cells i-1 and i+1. Here, the indices are taken modulo N meaning cells 0 and N-1 are also adjacent to eachother. At each step of the simulation, cells with exactly one living neighbor change their status (alive cells become dead, dead cells become alive).
For example, if we represent dead cells with a "0" and living cells with a "1", consider the state with 8 cells: 01100101 Cells 0 and 6 have two living neighbors. Cells 1, 2, 3, and 4 have one living neighbor. Cells 5 and 7 have no living neighbors. Thus, at the next step of the simulation, the state would be: 00011101
時(shí)間 O(N) 空間 O()
思路一維數(shù)組需要考慮的情況更少,要注意的是這里頭和尾是相連的,所以在判斷其左右兩邊時(shí)要取模。
代碼public void solveOneD(int[] board){ int n = board.length; int[] buffer = new int[n]; // 根據(jù)每個(gè)點(diǎn)左右鄰居更新該節(jié)點(diǎn)情況。 for(int i = 0; i < n; i++){ int lives = board[(i + n + 1) % n] + board[(i + n - 1) % n]; if(lives == 1){ buffer[i] = (board[i] + 1) % 2; } else { buffer[i] = board[i]; } } for(int i = 0; i < n; i++){ board[i] = buffer[i]; } }
In Place 一維解法
public void solveOneD(int rounds, int[] board){ int n = board.length; for(int i = 0; i < n; i++){ int lives = board[(i + n + 1) % n] % 2 + board[(i + n - 1) % n] % 2; if(lives == 1){ board[i] = board[i] % 2 + 2; } else { board[i] = board[i]; } } for(int i = 0; i < n; i++){ board[i] = board[i] >= 2 ? (board[i] + 1) % 2 : board[i] % 2; } }表優(yōu)化法 復(fù)雜度
時(shí)間 O(N) 空間 O()
思路和上題的表優(yōu)化一個(gè)意思,不過(guò)這里用到了循環(huán)數(shù)組,并且規(guī)則不太一樣。
代碼public void solveOneDWithTable(int[] board){ int n = board.length; int[] lookupTable = {0, 1, 0, 1, 1, 0, 1, 0}; int[] buffer = new int[n]; int env = board[n - 1] * 2 + board[0] * 1; for(int i = 0; i < n; i++){ env = (env % 4) * 2 + board[(i + n + 1) % n] * 1; buffer[i] = (lookupTable[env] + board[i]) % 2; System.out.println(env); } for(int i = 0; i < n; i++){ board[i] = buffer[i]; } }
文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請(qǐng)注明本文地址:http://specialneedsforspecialkids.com/yun/64643.html
摘要:思路普通解法,遍歷每一個(gè)細(xì)胞求值,用一個(gè)的矩陣存放結(jié)果。求值過(guò)程,稍微分析一下可知,其實(shí)就是按照以下的矩陣進(jìn)行結(jié)果是可數(shù)的。 According to the Wikipedias article: The Game of Life, also knownsimply as Life, is a cellular automaton devised by the Britishmath...
摘要:板上的每個(gè)小格子有兩種狀態(tài),或。而根據(jù)游戲規(guī)則,每一次這個(gè)板上的內(nèi)容將會(huì)隨著前一次板上的內(nèi)容發(fā)生變化。然后再根據(jù)當(dāng)前格子的狀態(tài)計(jì)算當(dāng)前格子的下一個(gè)狀態(tài)。當(dāng)然最后別忘了將原始狀態(tài)傳遞出去。 題目要求 According to the Wikipedias article: The Game of Life, also known simply as Life, is a cellular...
吃豆人和削蘋果這兩個(gè)游戲想必大家都知道吧,本文運(yùn)用Python里的Pygame控制模塊編寫出一個(gè)融合吃豆人+切水果的新手游:玩命吃蘋果,有興趣的話可以認(rèn)識(shí)一下 引言 哈哈哈!木木子今天浮現(xiàn)——早已來(lái)給大家看了不少具體內(nèi)容啦~ 涉及到的人工智能、新手、網(wǎng)絡(luò)爬蟲、數(shù)據(jù)統(tǒng)計(jì)分析(這一塊的通常但是審批)手機(jī)游戲... PS: 吃豆人我寫過(guò)了哈 Python+Pygame實(shí)戰(zhàn)之吃豆豆游戲的實(shí)...
摘要:生命游戲,數(shù)學(xué)家發(fā)明的一個(gè)游戲,又稱康威生命演化,生命棋,細(xì)胞自動(dòng)機(jī)。康威有許多好玩有趣的發(fā)明,最廣為人知的一個(gè)是外觀數(shù)列,這里不多說(shuō),另一個(gè)就是生命游戲。生命游戲模擬的是二維平面上生命的演化過(guò)程。 生命游戲,數(shù)學(xué)家 John Conway 發(fā)明的一個(gè)游戲,又稱康威生命演化,生命棋,細(xì)胞自動(dòng)機(jī)。 康威有許多好玩有趣的發(fā)明,最廣為人知的一個(gè)是外觀數(shù)列(Look-and-Say),這里不多...
Problem According to the Wikipedias article: The Game of Life, also known simply as Life, is a cellular automaton devised by the British mathematician John Horton Conway in 1970. Given a board with m ...
閱讀 1297·2021-11-22 09:34
閱讀 2162·2021-10-08 10:18
閱讀 1724·2021-09-29 09:35
閱讀 2453·2019-08-29 17:20
閱讀 2137·2019-08-29 15:36
閱讀 3398·2019-08-29 13:52
閱讀 775·2019-08-29 12:29
閱讀 1183·2019-08-28 18:10