iT邦幫忙

第 12 屆 iThome 鐵人賽

DAY 3
1
自我挑戰組

30天找回寫程式手感計劃!!!系列 第 3

Day3 - 第幾個 100 天還是很有感覺之久違的寫程式由簡單數學題目切入吧!( 1/3 )

  • 分享至 

  • xImage
  •  

各位觀眾!!!!!
不好意思讓大家久等啦~~~~ (醒醒,沒有人在等吧)
本系列的正片終於要開始啦XD
但怕耽誤到大家時間,
開始前還是有幾個溫馨小提醒要跟大家說個:

  • 本系列適合收看對象為跟我一樣算是有寫過很基礎的程式,
    只是平常不(太)寫 code,久了荒廢想要找回寫程式手感的人。
  • 本系列不會有語法教學之類的(我相信隨便 Google 都可以找到一堆教學文XD),
    因此若是有完全從 0 開始想學程式的迷途小綿羊,看到這裡可以左轉出去了XD
    本人在下我還是弱到爆的菜鳥一枚,所以我也不覺得我能教學什麼orz
    本系列是側重在我復健的過程。
  • 但若經過的大大們不嫌棄的話,也不怕耽誤時間的話,還是歡迎厲害的大大們來鞭策在下XD

好,前言到這結束,就讓我們正式進入主題吧!
(※溫馨提醒:下面很落落長, 沒時間的人可以用 Ctrl + F 搜尋 [快速回顧] 就好XD)

正片開始前還是一堆碎碎念

(對不起應該只有這一篇會一堆前言QQ 大家忍耐一下QQ)

之前文章有提過我出身於資管系,
不知道資訊科系相關的夥伴們跟我經驗像不像,
就是人生第一次學的程式語言就是 C 語言,
然後人生第一次程式語言期中考試一定有數學題?
是的,我一直都記得,
當年我的 C 語言期中考題是質數XD
(說來慚愧,我當年的 C 是低空飛過的orz 謝謝老師當年不殺之恩QQ)

挑選合適的復健起手式

因為我們都不是完全的程式新手了,
拜託複習寫程式起手式請不要從 Hello World 開始XD

我們是要練習寫程式的思考邏輯跟感覺,
因此我覺得用數學題目來當開頭難易度正好!
既不會簡單到像 Hello World 一樣,
又不會難到要你馬上進入指標之類的。
(其實 C 語言的指標概念我從以前到現在沒弄懂過orz)

正好我記得今年的 3 月 20 日有一則新聞:

https://news.cts.com.tw/cts/life/202003/202003201994343.html
今天是「超級整除日」! 本世紀僅有9天
今天除了是二十四節氣中的「春分」,也是「超級整除日」,意思就是今天的日期「20200320」剛好都是數字1、2、3、4、5、6、7、8、9、10的倍數,而這樣特別的日子,過了今天,下一次可就得等到5年後囉!

沒錯,所以現在就讓我們就用程式找出本世紀的「超級整除日」有哪些吧!

這邊我是用 JavaScript 實作,
如同我前兩天的文章提到的,
因為我後來幾乎都在寫 JavaScript,所以對它的語法最熟,
當然看到的夥伴們也可以用其他語言挑戰這是絕對沒有問題的!
例如:Python, Perl...... All OK, if you like, and you can!!!!!!!

工欲善其事,必先利其器

首先我們要準備的材料(?)有:

  • Visual Studio Code (或你用的順手的程式編輯器)
  • html 檔
  • js 檔

相信有在寫的人就知道,JavaScript 起手式就是要有 .html 檔跟 .js 檔XD
我在這個挑戰開始以前真的完全沒有偷打開 Visual Studio Code 寫程式,
就真的是如實將我復健的過程一一寫下來XD
真的可以把本系列文章當記錄片看的概念XD

準備好了就讓我們開始吧XD

正片真的要開始了

  1. 首先,打開先前 create 好的 html 檔 & js 檔,
    將 js 檔引到 html 檔裡面去。
    https://ithelp.ithome.com.tw/upload/images/20200909/201298733dCusOx0E6.png
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>超級整除日</title>
</head>
<body>
    <script src="js/FullDivided.js"></script>
</body>
</html>
  1. 為了確保有正確引到 js 檔,
    在 js 檔我寫了 console.log,如下:
console.log("HIHI");

確定 html 有顯示 console log 就可以往下個步驟進行。
https://ithelp.ithome.com.tw/upload/images/20200909/20129873yalQkMKDu0.png
3. 然後因為真的是久違的寫程式,
對自己的記性實在沒太大把握,
知道這個題目一定會用到迴圈,
於是用簡單的語法搭配 console 看看自己的記性有沒有問題XD

for ( let i=0;i<3;i++){
    console.log(`我是${i}`);
}

(PS. ${i} 為 JavaScript ES6 寫法,有興趣的可以 Google 個~)
https://ithelp.ithome.com.tw/upload/images/20200909/20129873qjHSBgjDCm.png

  1. 基本的迴圈語法搞定,
    終於可以寫本日的正題囉~
    但剛起步,還是先不要太快就納入迴圈寫法,
    讓我們先回到前面提到的 「20200320」剛好都是數字1、2、3、4、5、6、7、8、9、10的倍數
    對,先讓我們乖乖的用 20200320 寫超級整除日的判斷吧!
    一開始想法不要太複雜,
    就是用迴圈判斷 20200320 可不可以被 1~10 整除,
    可以的話就將被整除次數+1,
    最後印出 20200320 的被整除次數是不是為 10。
let cnt = 0; // 整除次數
let basicNum = 20200320;
for ( let i=1; i<=10; i++ ){
    // console.log(`我是${i}`);
    if ( basicNum%i == 0 ){
        cnt++;
    }
}
console.log(`被整除次數為 ${cnt}`);

https://ithelp.ithome.com.tw/upload/images/20200909/20129873VsVyFRcCaR.png
(我知道以上這幾句程式應該會有很多路過的大大看不過去XD
但這是復健,請大家再耐心等待個XD)

  1. 以上已經簡單寫出超級整除日的判斷邏輯了,
    外層加個迴圈
    於是再加個 if 判斷,
    如果被整除次數為 10,
    表示該數字為超級整除日。
if ( cnt == 10 ){
        console.log(`${basicNum} 是超級整除數!`);
    }
  1. 此時再讓我們回到新聞一下,
    本世紀只有 9 個超級整除日,
    為了要找出本世紀全部的超級整除日,
    外圈勢必還要再加迴圈,
    再執行裡面的超級整除數邏輯判斷,
    但還是不要太過心急一口氣將本世紀的數字範圍給進去,
    因為如果裡面邏輯有寫錯,會無限迴圈XD
    (雖然無限迴圈導致網頁跑不出來頂多把網頁暴力關掉而已,但良好習慣要從小(?)養成)
    所以一開始我只給 20250101 ~ 20251231 而已。
let cnt;
// let basicNum = 20200320;

for ( let basicNum=20250101; basicNum<=20251231; basicNum++ ){
    cnt = 0;
    for ( let j=1; j<=10; j++ ){
        if ( basicNum%j == 0 ){
            cnt++;
        }
    }
    if ( cnt == 10 ){
        console.log(`${basicNum} 是超級整除數!`);
    }
}

https://ithelp.ithome.com.tw/upload/images/20200909/201298734L0aPoOIPP.png
到這裡找出 20250720 是超級整除數,
這邊我有稍微暫停調整一下程式,
例如裡面的迴圈改由 10 開始,遞減到 2,
因為如果一開始就不能被 10 整除,
表示該數字一定不可能是超級整除數了XD
因此不能被 10 整除,
就可以不用再繼續往下執行,
用 break bypass掉內層迴圈再回到外層迴圈一開始繼續往下做)

let cnt; // 整除次數
// let basicNum = 20200320;
let execTimes = 0; // 計算次數(只是比較效能用)

for ( let basicNum=20250101; basicNum<=20251231; basicNum++ ){
    cnt = 1;
    for ( let j=10; j>=2; j-- ){
        if ( basicNum%j != 0 ){
            break;
        }
        cnt++;
        execTimes++;
    }
    if ( cnt == 10 ){
        console.log(`${basicNum} 是超級整除數!`);
    }
}
console.log(`計算次數為 ${execTimes}`);
  1. 上個步驟弄完我就開心的繼續往後改了,
    殊不知我漏掉重要細節XD
    我將外層迴圈範圍改成本世紀範圍~ (2001年1月1日至2100年12月31日)
    https://ithelp.ithome.com.tw/upload/images/20200909/20129873nZfVtOwAse.png
let cnt; // 整除次數
// let basicNum = 20200320;
let execTimes = 0; // 計算次數(只是比較效能用)

for ( let basicNum=20010101; basicNum<=21001231; basicNum++ ){
    cnt = 1;
    for ( let j=10; j>=2; j-- ){
        if ( basicNum%j != 0 ){
            break;
        }
        cnt++;
        execTimes++;
    }
    if ( cnt == 10 ){
        console.log(`${basicNum} 是超級整除數!`);
    }
}
console.log(`計算次數為 ${execTimes}`);

結果跑出了我意想不到的結果:
https://ithelp.ithome.com.tw/upload/images/20200909/20129873R2SLv5IZFl.png
不是說本世紀只有 9 個超級整除日嗎?為什麼跑出一堆?
看到這裡相信聰明的你一定知道發生什麼事了!

因為我忘記考慮月日的概念..........

所以連 20018880 這種不為正常日期的數字都被算出來了......=口=

  1. 看來本關最大魔王就是這個了!
    這邊我有 2 個想法:1) 加上判斷數字是不是正常日期的邏輯 2) 將年/月/日的數字串在一起弄成正常日期的數字,再執行後面超級整除數邏輯的判斷
    嗯,當然是 2) 的做法比較簡單啊XD
    好,所以我要先把正常日期的數字生出來,
    這邊開支線解決一下這個問題~
    (容我接下來快轉一下,因為快 12 點了Q口Q 詳細的等我交出去再容後補充QQ)

-先寫年月日字串連在一起
(PS. 這邊不判斷大月小月,太麻煩了,而且 31 也不會被 10 整除,所以可以忽略不計XD)

let dateStr = "";

for ( let year=2001; year<=2001; year++ ){
    for ( let month=1; month<=12; month++ ){
        for ( let date=1; date<=31; date++ ){
            dateStr = `${year}${month}${date}`;
            console.log(`dateStr: ${dateStr}`);
        }
    }
}

https://ithelp.ithome.com.tw/upload/images/20200909/20129873EroerAUyb0.png

-因為要計算 記得將字串轉數字

let dateStr = "";

for ( let year=2001; year<=2100; year++ ){
    for ( let month=1; month<=12; month++ ){
        month = month.toString(); // 將月份數字轉字串
        if ( month.length == 1 ){ month = "0"+month; } // 月如果只有1碼要補0
        for ( let date=1; date<=30; date++ ){
            date = date.toString(); // 將日子數字轉字串
            if ( date.length == 1 ){ date = "0"+date; } // 日如果只有1碼要補0
            dateStr = `${year}${month}${date}`; // 將年月日用字串的方式串在一起
            basicNum = parseInt(dateStr); // 最後再將組出來的日期字串轉數字型態
        }
    }
}

-再把上述組出來的日期數字跟先前寫好的超級整除數判斷邏輯組起來,大功告成!

let cnt; // 整除次數
let basicNum = 20200320;

let dateStr = ""; // 日期字串

for ( let year=2001; year<=2100; year++ ){
    for ( let month=1; month<=12; month++ ){
        month = month.toString(); // 將月份數字轉字串
        if ( month.length == 1 ){ month = "0"+month; } // 月如果只有1碼要補0
        for ( let date=1; date<=30; date++ ){
            if ( date % 10 != 0 ){
                continue; // 如果 date 不能被 10 整除就直接跳過後面不做回到迴圈開始處
            }
            date = date.toString(); // 將日子數字轉字串
            if ( date.length == 1 ){ date = "0"+date; } // 日如果只有1碼要補0
            dateStr = `${year}${month}${date}`; // 將年月日用字串的方式串在一起
            basicNum = parseInt(dateStr); // 最後再將組出來的日期字串轉數字型態

            cnt = 1; 
            for ( let j=10; j>=2; j-- ){ // 1可以整除任何數,所以直接從2開始
                if ( basicNum%j != 0 ){
                    break;
                }
                cnt++;
            }
            if ( cnt == 10 ){
                console.log(`${basicNum} 是超級整除數!`);
            }
        }
    }
}

https://ithelp.ithome.com.tw/upload/images/20200909/20129873hyTkb1m4qW.png
耶~~~~~~ 我終於成功用程式找出本世紀 9 個超級整除日了~~~~~~(灑花)

[快速回顧]

我知道上面太落落長,因此這邊讓我們快速 review 一下本日重點XD

  1. 寫 JavaScript 的起手式:html 檔, js 檔
  2. 用 console log 看自己有沒有耍北七
  3. 小小試一下迴圈語法
  4. 不貪心,先用 1 個數字寫超級整除日的邏輯
  5. 不貪心,不一口氣將迴圈範圍改成本世紀範圍,而是一年內日期範圍
  6. 將年月日用字串串起來,再轉成數字型態
  7. 再將 6) 跟 4) 的邏輯合在一起,大功告成!

[後記]
後續應該還可以再 tune 一下程式,
但我沒時間了先這樣XD
(前幾天都可以保持第2名交文章的......今天變成本團最晚交的QQ)


上一篇
Day2 - 「 三日不讀書,便覺面目可憎」── 那 100 天沒寫程式呢?(下篇)
下一篇
Day4 - 第幾個 100 天還是很有感覺之久違的寫程式由簡單數學題目切入吧!( 2/3 )
系列文
30天找回寫程式手感計劃!!!36
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

1 則留言

0
NoobTW
iT邦新手 5 級 ‧ 2020-09-10 10:31:38

在 JavaScript 比較值的時候,請愛用 === instead of ==,比較不會遇到意想不到的 bug XD

供參考的比較表:https://dorey.github.io/JavaScript-Equality-Table/

我要留言

立即登入留言