《此文章是作者嘔心瀝血的財產,若要引用請附註引用自本網址,請尊重教學創作智慧財產權》
對寫程式的新手而言,能寫出一個遊戲是最重要的成就
而一款好的遊戲在於不可預知性,無法預測之後會發生什麼,有變化才好玩
而這個特性就和亂數、亂數表有很大的關係
Java有個叫出亂數的指令:Math.random()
不過這個亂數的範圍是0~1(不含1,即小數的意思)
0<=Math.random()<1
如果是要做猜數字、樂透號碼的遊戲,就得用整數才行,那其實可以用簡單的數學把指令改造成整數的亂數,
甚至可以改成自由調整亂數的範圍
----------------------------------------
接下來要做的就是推導、一般化,這個步驟其實有接觸寫程式的同學,很多老師都有教過
只是教的步驟能不能讓人聽懂的問題,我記得國中的電腦老師在這個部份根本是......說瞎掰有點太過份了,
但他的講解非常牽強,省略一堆東西,害我都懷疑他到底懂不懂這個推導的真諦,
所以我將會用符合大家以前解數學的解法,把這個謎團給解開:
關鍵:同乘是擴大區間,同加是位移
目標:今天我們要把亂數,由小數的範圍改成任意整數
學習進程:
1.用0~1、0~2了解同乘同加的意義
2.Java(int)&了解不等式小於、小於等於的意義
3.建構:一般化的嘗試n
4.建構:一般化的嘗試n+1
5.建構:一般化的嘗試m
6.建構:一般化的嘗試n-m
----------------------------------------
1.用0~1、0~2了解同乘同加的意義:
令Math.random()是R,所以R是0到1之間的小數
我們先做簡單的更改,如果要作出1~3之間的亂數要怎麼做?
0<=R<1
0<=R*2<2
1<=R*2+1<3
放心,以下會有詳細圖解:
首先來看R在數線上的意義
0<=R<1 ......R是0~1的小數
如果我們同乘2的話,區間就會變大
0<=R*2<2 ......同乘2
為什麼要乘2,把區間變大?
因為原本R是0~1,裡面除了0之外都是小數;我們今天的目標是「能顯示整數的亂數」,
那這個亂數的範圍內要有很多整數存在,對吧?
所以同乘數字的理由是把區間(就是範圍的意思)變大,使其中能包含更多整數
現在R*2的範圍變成0~2了,即成了一個 範圍0到2的亂數,包含0、0.001、1、1.999等等
如果我們同加1會發生位移,整體移動1單位
1<=R*2+1<3 ...同加1
現在R*2+1的範圍變成1~3了,即成了一個 範圍1到3的亂數,包含1、1.001、2、2.999等等
2.Java(int)&了解不等式小於、小於等於的意義
令(int)(Math.random())是R',Java中,在數字前加(int),是只留住整數部分,小數部分無條件捨去
所以現在R'是一個整數亂數了,不過範圍是[0,1),包含0但不包含1,所以只有0一個整數,嚴格來講不能叫亂數XD
0<=R'<1
0<=R'*2<2 ...同乘2,變成一個0~2之間的整數,但不包含2
0<=R'*2<=1 ...既然R'已經代表一個隨機的整數,小於2 其實就是 小於等於1的意思
現在R'*2是一個有0和1的隨機整數了
3.建構:一般化的嘗試n
什麼是一般化?簡單來說就是以未知數來表達,讓特定數字代入都能使用;此處特定數字是任意整數
什麼是建構?不斷嘗試,在錯誤中學習,累積失敗經驗,逐漸推導出完美的真理,即失敗為成功之母。
現在來思考怎麼推出0~n(包含n)的隨機整數
0<=R'<1 ...繼續用R'囉!我們直接來推導隨機整數
0<=R'*n<n ...先照原本算法同乘n,現在得出0~n但不包含n的隨機整數
0<=R'*n<=n-1 ...然後換成小於等於
诶?得出0到n-1的隨機整數?這不是我們要的。
會得出這個結果是因為同乘n得出的結果是[0,n)不是[0.n],一個沒包含n,一個有包含n
那我們會發現同乘n,是得到n-1
這是我腦中的思考圖 (゚∀。)
4.建構:一般化的嘗試n+1
所以就調整一下,想得到結果是n,改成同乘n+1
現在算式改成這樣:
0<=R'<1
0<=R'*(n+1)<(n+1) ...同乘n+1
0<=R'*(n+1)<=n ...變號
這樣R'*(n+1)就是一個[0,n]、0~n(包含n)的隨機整數了
5.建構:一般化的嘗試m
現在我們來思考怎麼把0~n改成m~n
按照上面所講的,只要位移+m就可以輕鬆解決了 (ゝ∀・)b ?
當然沒那麼簡單,但可以先算算看同加m會發生什麼是事,再做調整即可
0<=R'*(n+1)<=n
m<=R'*(n+1)+m<=n+m
好......是不是蠻笨的?同加m,右邊一定會變成n+m阿!!! -`д´-
分析一下,我們希望同加m,然後最右邊只剩n,那如果右邊原本是(n-m)就搞定了
如果要把右邊原本就是(n-m),那就會牽扯到最一開始同乘一個數字的問題
6.建構:一般化的嘗試n-m
目標:m<=???+m<=(n-m)+m
想得到結果是(n-m),改成同乘(n-m+1)即可
0<=R'<1
0<=R'*(n-m+1)<(n-m+1) ...同乘(n-m+1)
0<=R'*(n-m+1)<=n-m ...變號
m<=R'*(n-m+1)+m<=n-m+m ...同加m
m<=R'*(n-m+1)+m<=n
終於完成了,R'*(n-m+1)+m就是我們所要的,任意範圍m,n的隨機整數
放回Java就是:(int)(Math.random()*(n-m+1)+m);
----------------------------------------
我認為這是一個做研究的心態,不斷從過去經驗中做嘗試。問題發生時,依新的結果,往回做調整。
這樣才能真正了解以前學習的漏洞在哪裡,有什麼地方是忽略或誤解的。
這樣的數學才好玩,合情合理有根有據,這邊附上以前國中老師的解法:http://vincent7421.pixnet.net/blog/post/305047870
謝謝指教~
《此文章是作者嘔心瀝血的財產,若要引用請附註引用自本網址,請尊重教學創作智慧財產權》