題目來源: Alpha Camp 學期一作業
這是第一個讓我覺得”卡卡”的題目,也是一個讓我在寫出來後深刻認知到: “想不到解決問題的方法,會寫程式也沒用“的題目。
藉著記錄解題的過程,把當初解決問題的方法和思考方式寫下來,達成再次深入複習的目的。
解題工具
- Math.random() 會回傳一個偽隨機小數介於0到1之間(包含0,不包含1)
- Math.floor() 會回傳小於等於所給數字的最大整數(無條件捨去)。
- while 迴圈
- if statement
基本題
題目要求
- 指定介於 1-100 之間的數字,存在
answer
變數裡
- 設定一個
guess
變數,代表挑戰者 (電腦) 猜的數字
- 電腦可重覆「猜數字」,比對
guess
和 answer
,判斷太大或太小
- 若兩者相等(猜對)則結束遊戲,且結束時須計算電腦猜了幾次
解題過程
使用 Math.random() 和 Math.floor() 指定一個介於 1-100 之間的數字,存在 answer
變數裡。
原本想要直接用 Math.ceil() 無條件進位,但後來發現 Math.random() 有可能產生 “0”。所以如果直接用 Math.ceil() 可能會發生 guess === 0
的問題(不符合猜數範圍)。
先用 Math.random() * 100 取得一個介於0到100之間(包含0,不包含100)的隨機小數。把這個小數套進 Math.floor() 裡面進行無條件捨去再加1,就能取得一個介於1到100之間(包含1,包含100)的隨機整數了。
這裡還犯過一個非常不應該的錯誤,我把 Math 寫成 math ,然後就又跳錯誤了……
到目前為止,條件一和條件二都可以達成了。
1 2 3 4 5
| const answer = Math.floor(Math.random() * 100) + 1
let guess = Math.floor(Math.random() * 100) + 1
|
for / while 的選擇—-因為這次的比大小是條件判斷,所以選擇 while 迴圈。
先把邏輯寫出來:
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| 宣告 anwer
while (猜數 不等於 答案) ,則進入迴圈
猜一次數字,並且回合數 + 1 (接著進入結果判斷) IF 猜數 > 答案 則 印出回合數、印出猜數、印出莊家回答:太大了 ELSE IF 猜數 < 答案 則 印出回合數、印出猜數、印出莊家回答:太小了 ELSE (猜數 = 答案) 則 印出回合數、印出猜數、印出莊家回答:恭喜答對! 結束迴圈
|
好像差不多了,條件三和條件四也都可以達成了。但跟著邏輯再想一遍以後又發現了問題:
- 迴圈裡回合數每次 + 1,但不知道是從多少開始加,所以要先宣告回合數 = 0
- 一開始只生成答案無法達成進入迴圈條件,為了達成條件,先宣告猜數 = 0
以上問題都解決了,可以組合起來寫出程式碼了!
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25
| const answer = Math.floor(Math.random() * 100) + 1 let guess = 0 let count = 0
console.log(`正確答案為 ${answer}`)
while (guess !== answer) { guess = Math.floor(Math.random() * 100) + 1 count += 1
if (guess > answer) { console.log(`第 ${count} 回合,挑戰者猜 ${guess},莊家回答:太大了,再猜一次`) } else if (guess < answer) { console.log(`第 ${count} 回合,挑戰者猜 ${guess},莊家回答:太小了,再猜一次`) } else { console.log(`第 ${count} 回合,挑戰者猜 ${guess},莊家回答:恭喜答對!`) console.log('===============遊戲結束===============') } }
|
進階題
題目要求
解題過程
花了三個小時都沒想出來,最後決定上網找找靈感,幸運發現一個前輩的解題思路。認真看完一遍,發現就跟以前玩終極密碼一樣,最快的方式就是縮小範圍,砍半再砍半。如果用對半切的方式,已知 2 的 10 次方為 1024,即範圍 1~1024 內的數字用砍半方式一定可以在 10 次內猜到,符合題目要求。
知道方法後要做的事只有2件:
- 設定猜數的上限和下限
- 讓猜數取上限和下限的中位數
1 2 3 4 5 6 7 8 9 10 11
| let rangeMax = 100 let rangeMin = 1
rangeMax = guess - 1 rangeMin = guess + 1
guess = Math.floor((rangeMin + rangeMax) / 2)
|
該作的變數調整都完成了,接下來就是把它們塞進該放的位置。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25
| const answer = Math.floor(Math.random() * 100) + 1
let guess = 0 let count = 0 let rangeMax = 100 let rangeMin = 1
console.log(`莊家數字是 ${answer}`)
while (guess !== answer) { guess = Math.floor((rangeMin + rangeMax) / 2) count += 1
if (guess > answer) { rangeMax = guess - 1 console.log(`第 ${count} 局|電腦猜 ${guess} ,太大,再猜一次! 範圍 ${rangeMin} ~ ${rangeMax} 。`) } else if (guess < answer) { rangeMin = guess + 1 console.log(`第 ${count} 局|電腦猜 ${guess} ,太小,再猜一次! 範圍 ${rangeMin} ~ ${rangeMax} 。`) } else { console.log(`第 ${count} 局|電腦猜 ${guess} ,恭喜答對!`) } }
|
終於成功了!! 這也是文章開頭說的: 如果知道解決問題的方法,只要能正確地把程式碼寫出來就好;如果不知道解決問題的方法,就算程式語言再精深都沒用,因為連怎麼開始都不知道。
其他小題目還好,就不特別寫解題筆記了。預計下一篇會寫更卡一點的期末考 😅
文章內容如有錯誤,歡迎留言討論!