close

《此文章是作者嘔心瀝血的財產,若要引用請附註引用自本網址,請尊重教學創作智慧財產權》

對寫程式的新手而言,能寫出一個遊戲是最重要的成就
而一款好的遊戲在於不可預知性,無法預測之後會發生什麼,有變化才好玩
而這個特性就和亂數、亂數表有很大的關係

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在數線上的意義

n1.png
0<=R<1  ......R是0~1的小數
如果我們同乘2的話,區間就會變大
n2
0<=R*2<2  ......同乘2
為什麼要乘2,把區間變大?
因為原本R是0~1,裡面除了0之外都是小數;我們今天的目標是「能顯示整數的亂數」,
那這個亂數的範圍內要有很多整數存在,對吧?
所以同乘數字的理由是把區間(就是範圍的意思)變大,使其中能包含更多整數

現在R*2的範圍變成0~2了,即成了一個 範圍0到2的亂數,包含0、0.001、1、1.999等等

如果我們同加1會發生位移,整體移動1單位
n3
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

n2.png這是我腦中的思考圖 (゚∀。) 

4.建構:一般化的嘗試n+1
所以就調整一下,想得到結果是n,改成同乘n+1
n2.png
現在算式改成這樣:
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)就搞定了

n2.png
n2.png
n2.png
如果要把右邊原本就是(n-m),那就會牽扯到最一開始同乘一個數字的問題

6.建構:一般化的嘗試n-m
目標:m
<=???+m<=(n-m)+m
想得到結果是(n-m),改成同乘(n-m+1)即可

n2.png
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

謝謝指教~

《此文章是作者嘔心瀝血的財產,若要引用請附註引用自本網址,請尊重教學創作智慧財產權》

arrow
arrow
    全站熱搜
    創作者介紹
    創作者 Kuihao 的頭像
    Kuihao

    溫暖午後的金針田__孕育有趣的創新

    Kuihao 發表在 痞客邦 留言(0) 人氣()