| Piscine | 2020同時唸42+大學心得

Leo Fu
台灣人 @ Ecole42
19 min readMay 16, 2021

嗨大家好我是話很多但程式碼短的Leo,我在2020年8月正式開始在里昂三大Universtié Lyon 3就讀L1(相當於大學一年級),也很不要命同時參加了8月到9月的Piscine,最後幸運被錄取,所以目前是同時在兩邊就讀,在此跟大家分享我蠟燭兩頭燒的心得。

(如果不清楚école 42 / school 42或piscine是什麼的,請先看看其他前輩們的介紹,熱心的大神學長姐們已經有詳細的介紹了。)

我Piscine前的程度

我在高二升高三的暑假時第一次學習了C++的語法,高三時進入資訊校隊後開始學習演算法(主要是自己看書+上網看文章刷題自學)並參加了一些比賽(TOI, NPSC),進大學前Codeforces的ratings在2000左右,接著我進入數學系後忙於課業便沒繼續寫程式了。

後來我大學休學了,便在2019年9月來法國唸語言學校,2020年2月同時申請上了里昂三大和42。

總之,我其實是在有一定的法文和程式基礎下參加Piscine的,才可以在2者兼顧的狀況下通關。

結論

因為我話很多,所以先給沒時間看的人講結論了

  1. 我不推薦同時讀大學跟42,我明年大學大概也會休學。為了兩邊兼顧,我其實大幅減少了待在42的時間(一個星期我只能待大概5、6小時),一方面影響了我在42的社交生活(我在42的朋友一隻手數得出來QQ),另一方面我也失去了很多參與校內活動的機會,像是校內有辦hackathon,codingame,或是42trading、42blockchain的座談會等,我常常因為跟學校時間衝突必須二擇一,到頭來我身為42的學生卻沒辦法完整享受學校資源實屬可惜。
  2. 會法文是個優勢,不會法文至少要會英文,跟同學溝通與討論在Piscine或入學後都非常重要。
  3. 在Piscine期間會用到shell, git的基本還有 C,其中C大部分都是寫些簡易函式,可能跟leetcode的easy, medium題蠻像的,可以先去練點題目熟悉一下(但不會用到太多書上的或大學學的那些演算法,只要把迴圈能解的題目練一練就差不多)。
  4. 會寫程式的人一樣能在Piscine學到蠻多東西,尤其是自學的人。

常見問題

  1. 在Piscine要做多少projects?

shell00~shell01, C00 ~ C13: 這些是照順序,要做多久都可以,隨時只要做完一個就可以開始做下一個(我通過shell00~01, C00~C08而已,C09是Makefile我來不及學好QQ)

以下的project時間都有限制,開始之前沒申請就沒得做,時間到了沒做完也沒辦法再修改

rush00 ~ rush02: 這些是每個週末可以申請,然後被隨機分配到另外兩個組員的group project(我通過rush02)

BSQ: 這是自己找一個組員,3天時間做的project

然後還有考試

exam00, exam01, exam02 :前三週每週五下午考4小時,全部都是C的題目,exam00會有個資料夾trace,能看到自己每次failure是哪裡有錯,但之後就沒有了,要把握跟珍惜(我通過exam01,02)

Final exam: 在 Piscine 的最後一個活動,8小時考試,一樣都是C的題目,之後Piscine就正式結束(我有通過)

總之,這25天非常密集,有非常多東西要做,盡可能一到兩天就通過一個project吧,一天花個8小時做寫code是很正常的。

如果成功撐完了Piscine 而且有好好做(到至少C07吧),就可以大概掌握C語言了

2. 有沒有學過寫程式重要嗎?

如果你就是想專心過Piscine,那沒那麼重要,因為只要夠認真而且懂學習方法,很多人也是零基礎成功通關。Piscine的設計是讓零基礎的人在學校25天,前幾天先學會使用基本的shell, git, 接著寫大概3星期的C語言,通常完場後認真參與的同學已經對C語言掌握不錯,也看不太出來哪些是完全新人,哪些來之前有偷學一下語法。

但如果你想要跟我一樣腳踏兩條船(? 零基礎基本上是不可能!!即便你有學過C語言也可能不太夠,最好是對於陣列、指標、結構、基本演算法(至少dfs, dp)都夠熟悉,因為42的設計讓我們必須花大量時間在學校:project數量多,大概每兩天得做一個project、每個project都要找兩位同學做correction,同時自己也要改另外2位同學的程式碼來賺取correction points,光是這兩件事情每個project至少要花1小時。

身為一個大學生其實很難每天在學校待5、6小時(我個人平均一週在學校待10小時),所以大學生的策略只能是無論身在何方有空檔就趕快寫code,放學或是沒課時就去學校做correction,非常緊湊而且沒太多失敗的空間(一旦失敗相當於自己好不容易抽出來的時間完全被浪費掉了)。因此,要有穩固的基礎還有足夠的自信自己能寫出沒bug的code。總之,時間管理很重要,會寫程式可以很快寫完project,不代表可以很快通過。

歐對,有在打競賽或練OJ的同學請注意:42跟比賽不一樣,輸入範圍未知,請好好做好protection,還有leaks也是一定要避免的,所以不用搶快,把細節處理到位比較重要。

舉個例:如果我今天要做個

size_t ft_strlen(char*);

來計算字串的長度。

有些人(我)看到這種題可能會想直接寫

size_t ft_strlen(char *str)
{
return (*str ? 1 + ft_strlen(str + 1) : 0);
}

size_t ft_strlen(char *str)
{
size_t i = 0;
while (str[i])
++i;
return (i);
}

這樣(norm規定C語言不能用for迴圈所以我用while)

但其實在42,有人(或是tester)有時會要求必須要處理 str == NULL的情形,來確保一個不合法的輸入不會導致segmentation fault,這種實作上的細節一定要處理好,或是malloc完後不要忘記free等,不要看輸出正確就急著往前衝,以免之後用到以前做的函式庫時還出現未知的bug。

3. 要先學演算法嗎?

個人認為在Piscine的重要技能排行榜大概是 毅力>社交能力>查資料能力>C語法>外語能力>shell,git等知識>>演算法

基本上,演算法在Piscine真的用不太到,而且就算遇到了通常也不要求最佳複雜度,再加上題目都well-known所以可以查到很多資料或直接問同學就好,但為了某些好奇寶寶我還是具體點把會用到的東西講一下。

C01 : sorting algorithm (實做sort一堆整數,不准用external function like qsort),但複雜度沒要求O(N log N),所以直接bubble sort, selection sort等最基本的O(N²) 算法就好(強者我朋友說bogo sort過不了)

C03 : 實做strstr,會kmp算法最好,但我後來發現大家用一般迴圈都會過,所以複雜度 O(N*M) 開下去沒問題

C04 : 不同進位的轉換

C05 : 演算法日!這個 project 會正式學到iterative, recursive的不同,然後還會用到質數判定、質數表和backtracing。聽起來好多東西要做?在這邊為想太多的同學們提供些節省時間的資訊:00到03都有指定方法所以很明顯不用最佳複雜度,照他說的用迴圈或遞迴就好(memorization也不用),04的費氏數列保證不overflow,所以一般 dp就好,準備寫矩陣快速冪的同學麻煩別衝動。05求根號向下取整也很鬆,O(sqrt(N)) 算法即可通關,寫二分搜、牛頓迭代、Carmack算法的還得幾分鐘內想辦法解釋,會逼死自己QQ。接著兩題質數稍微比較嚴格,請用線性篩法好好寫,最後一題 N-queens 字典序輸出,裸backtracing就好。

C12 : linked list day !!

C13 : B-tree day !!

講到這裡應該可以發現,piscine求的是易懂好解釋且堪用的算法,所以大家不用對時間複雜度有過多追求,有學過基本演算法的同學(可能大學上過DSA或是自己看過書)就不必擔心要不要學更深入了。

接著就是我Piscine時期的流水帳囉

流水帳

第一週:成事不足,敗事有餘

剛搬完家到LYON不久,還在心力交瘁時Piscine就開始了。這時我完全還在懶人模式,心態也是把參加Piscine當經驗,並沒有「非錄取不可」的想法,再加上我根本完全不知道terminal, shell, git這些東西是什麼(雖然自學了演算法,但我其實是個隱性電腦白痴),所以我只能靠著對同學死纏爛打,才順利做完了shell00(這時已經過了5天了)。

此時,發生了一件很低能的事情 : 我沒有成功報名exam00 !! 於是我就0分了QQ,在此奉勸各位同學要好好看公告或多跟同學問資訊,就算很混也得知道必須register exam的project,還要在agenda裡面報名。

然後我就學到教訓了…嗎?沒有,我也忘記register我的rush00了… 於是這週我大概該做的都沒做,能搞砸的都搞砸了,完全是場大災難。(題外話:我們有記錄待在學校的時間長短(log time),而我這星期只有在學校3小時多,各方面來說完全就是整個Piscine的墊底…)

第一週週日,我給了自己沈澱的時間,並且重新下定了決心:我不能讓這次Piscine只是浪費時間,於是我告訴自己不能再掉漆了。

當晚,我在自己電腦裡裝了ubuntu,做完了shell 01,發現只要好好學習其實這並不難,並且也準備好隔天去學校上傳。

第二週:開始反省,步入正軌

開始做C了,但同時大學也開學了,於是我就邊在大學聽課,邊在課餘時間或老師講廢話時寫code,放學後再趕去42賺correction point和上傳projects。就這樣燃燒生命到了週四,順利傳完了C02,也同時在自己電腦中把C06做完了,而且我這一次有好好報名了exam和rush,所以週五到週末就把時間心力放在考試和rush了。

週五考試從一開始就很卡,畢竟是我第一次考(?,一開始又差點想不出密碼而錯過登入時間(10分鐘內沒登入就會直接失去資格),壓線登入後又發生題目看不懂的慘劇…(不是我要嘴砲但有些題敘真的是丟到解題網站會被倒讚到下架的那種爛,絕對不是我語言能力匱乏(x,總之大家最好是考試前先去github看看題目確定自己看得懂啦)。

於是前面兩題我就狂失敗,每次失敗又要隔更久才能重傳(第一次失敗要等5分鐘,第二次失敗要等10分鐘,以此類推),最後好不容易通靈過這兩題時,時間已經只剩一小時不到了…這時候先去廁所洗一下臉冷靜一下,然後分析情勢跟思考策略:我已經完全沒有失敗的本錢了,所以我不該搶快,接下來每次都得傳正確答案才是最重要的。於是我接下來一題一題慢慢寫,好好測,通通一傳就過,直到最後將給我滿分的那題在考試結束前一分鐘送了出去…結果…沒過QQ,但反正也還是個不錯的分數啦,事實證明心態不崩、保持冷靜就有機會完成自我救贖(?。

週末便到了第一次rush與兩位同學合作,似乎是兩位我從來沒見過的同學,看得出來其中一位是完全初學,來自法國的隊友C,另一位是有些基礎但不太會演算法,來自阿爾及利亞的隊友A,所以自然由我來主導這次rush。

題目應該不是機密所以我就暴個雷:做一個解skyscraper遊戲的程式(https://www.puzzle-skyscrapers.com/),所以算是以演算法為主軸,最簡單的演算法就是backtracing(可以搭配next_permutation來加速,但其實是由人工測的所以並不嚴格要求程式運行速度)

總之我就將工作分配成隊友C製作我們所需的函式+測試,隊友A負責io + parsing,而我做演算法,在3人的搭配下我們很快完成各自的任務,合起來時也沒出什麼bug,就很愉快完成了rush01 … 但最後還是0分了XD

我們在輸入行數或長度不對時會出現segmentation fault,所以可能算做白工了吧?但至少跟兩位隊友合作愉快(朋友+2)

總之第二週雖然挺累,但還挺充實愉快的,也覺得自己有在慢慢往上爬(加上我發現我的考試成績其實算不錯,就蠻爽哈哈),比較大的缺點是log time還是嚴重不足(大概12小時左右)。

第三週:持續投入,補上進度

這時的我已經對42的運作比較熟悉了,也在學校有認識更多朋友了( 我也在這時幸運認識了在我現在的搭檔,來自中國的X同學),有了這樣的自信後處理大小事還是更加得心應手的,所以我的生活重心逐漸變成了在42賺correction point還有submit projects(微放生大學),並且同學開始注意到我,我就也幫忙提點一下卡住的同學,還有幫忙debug(其實初學者的確比較不會除錯,這我也理解,畢竟很多bug真的是靠經驗看出來的),這樣從被幫助者到給與幫助者的轉變還是令人蠻開心的。

不過我也第一次在C的project吃了個不及格…一開始蠻嘔的,覺得自己虧了correction point和時間,但也讓我發現了自己在錯誤處理中不夠嚴謹的問題(高中在比賽時通常只會給valid test cases,但是42其實很注重有沒有處理好例外的安全性問題,像是malloc必須有protection,傳的字串可能是NULL等),也讓我知道了其實我的程式還是有不夠完美的地方,同時我也體會到即便是有基礎的人,也該仔細、認真對待每個看似簡單的題目。

總之,我在這週挺深刻感受到同儕間互相學習的樂趣和效率,這正是我一直以來最喜歡的學習方式,也發現在piscine的日子比想像中還快樂,學到比想像中還多,我也在此時越來越堅定要進到42的決心。

接著又是週五的歡樂考試,同樣的題意誤解,再次問了工作人員卻沒人理我,再次試誤法試到時間差點被噴光,於是最後又是一樣的差一題滿分…這時也不得不感慨:我的實做能力真的是低落,以前的我還是練習的太少了,來piscine後還是有提升不少實做能力的。

接著是週末的rush,題目是給定一個數字(最大好像到thousands of trillions),還有一個字典(大概就是1:one, 2:two, … 1000:thousand這種數字與單字對照的表),然後要輸出這個數字根據字典要怎麼翻譯,像是1000在標準字典裡我們就要輸出one thousand,如果字典裡有行87:idiot,1087就要輸出one thousand idiot這樣

組員的話這次有位初學者M,更另一位很高效的大哥J,我剛到學校時J已經做好Makefile跟一堆函式了…那我當然就不出鋒頭給他領導囉XD 於是我又去我的角落刻演算法:把數字分成三個三個一組就輕鬆解決了,所以我做完後就去逛大街跟幫助M完成任務~最後我們三個一天不到就全部做完了,合在一起也沒問題,我們就自主放假囉

於是到了correction的時候,我們又被測出parsing有問題QQ最後驚險拿了50分通關…實在是挺幸運的。而且我也明白了一件事情:原來rush真正難做的不是演算法,而是parsing,因為42的測試真的挺嚴格的(corrector都會拿奇怪的數據來測,像我們這次就是在字典裡加了一行亂碼時會出現seg fault)。

此外這週還有個為期三天的BSQ,我跟上週Rush的搭檔:朋友A 組隊,我們兩個前兩天都蠻忙的(他要工作,我要上學),但是在最後一天的傍晚我們相約在學校一起處理BSQ。

BSQ的題目不難,大概就是一個矩形地圖有些地方是牆壁有些地方是空地,我們要在其中尋找由空地組成的最大正方形,就是個非常經典的dp(dynamic programming)題,所以我就將parsing交給他,我負責處理演算法。最後在23h左右,我們終於讓code順利運作了,但此時學校電腦突然重開,飽受驚嚇之餘我們趕快在重開後把損失的程式碼復原,此時時間是23h20,還剩22分鐘截止,但還有個致命的問題: norm還沒有修好。

此時我們兩人將我們的檔案分別修改,經過10分鐘後我先修完了,也測試過程式運行沒問題,就趕緊把我的部份push上去,幾分鐘後他也改完了,這時大概還剩5分鐘,測試沒問題後他也趕緊把程式碼push上去…結果push不上去?!

「Hey ! Git doesn’t work」

「What? Just give it to me」

這時我真的是差點嚇死,幾分鐘後就要結束了啊… 雖然我很霸道的接手了,但我也根本不知道問題是什麼,只好跟他如法炮製後google了下錯誤訊息…然後我突然發現,原來隊友A並沒有git pull,就在千鈞一髮之際,git pull,東西都拉回來後確定過該commit都commit了,然後git push…這次終於成功了,時間還在23h41

23h42!幾秒鐘後時間到,我很確定我們是最後一個完成的隊伍,經過這次經驗我實在是差點心臟病,以後絕對不會把projects拖到最後一分鐘了(立flag)

第四週 : 最後階段,狂看歐冠

如標題,因為疫情的關係這時正好在踢被延期的歐冠,我就跟我同學一起看爆(里昂熱血淘汰曼城進4強大家都爽爆,外面還有人放煙火,最後被拜仁淘汰真的可惜,里昂開場有3個大好機會都沒把握住)

然後,BSQ的correction是由同樣在Piscine的同學們來評,最後我們雖然拿了45/100沒順利通關(n = 1000時segmentation fault),但我相信這還是有加分效果啦。

接著便是壓軸好戲,Final exam

整整8小時的考試,16題,前15題一題6分,最後一題10分。

「聽說里昂校期末考沒人拿過滿分」朋友X如是說

「哈,這次考完就會有了」我隨口唬爛了一下

這時心裡大概有個底了,最後一題應該難度很高

沒多久考試開始,前面都不難,跟之前的考試題型很像。這次大概有個底,所以前面很順利,前五題都是一次通過,這時大概才過半小時而已。身為一個心浮氣躁的少年,順風時必定膨脹,第六題是我曾經做過的ft_range,測都沒測直接一傳,拿了個failure。之後自己測發現我的程式碼根本不能compile,改好後又趕緊傳了一次…還是failure。

這時候趕緊去廁所洗個臉冷靜一下,提醒自己無論如何不要慌。

再讀一次自己的code,still no clue, 這時候我再仔細看了一次題目,發現…我拿到的題目是ft_rrange(reverse range),不是ft_range,當場想把自己眼鏡砸爛,但我沒砸,很平靜改完後輕鬆通過。

之後拿了題ft_atoi_base (還是ft_atoi,我忘了),雖然自己寫過但我有好好讀題目,就發現原來跟Projects裡做的不一樣,我頓時明白,或許前面的失敗也讓我成長,變更加沉穩了。(但還是建議大家從一開始就好好讀題,前面的失誤都是後面要還的債)

之後還是挺順利的,雖然到大概第10題後都是我沒寫過的題目(第一次看到函數指標ㄏㄏ),但還是蠻幸運都一次通關了,就這樣過了第15題,此時時間還剩:1小時。

「好吧,一小時應該夠吧,拜託別是什麼大型實做題」

“ft_infinite_table”

這啥?聽起來太嚇人了吧

“You will have two potentially infinite numbers as arguments, print the product of these two numbers. That’s all, no cheat.”

??所以是無上界的兩個數相乘?那不就大數乘法嗎?

這時候我的腦海裡出現了小天使與小惡魔

小天使:「太棒了,大數乘法你只要把他們當直式乘法就能輕鬆時做了呢,20分鐘游刃有餘吧!」

小惡魔:「你以為最後一題會那麼簡單嗎?要是你刻完一般作法後拿了個Failure怎麼辦?你怎麼知道是*TLE 還是其他問題?你現在就該趕快開始刻O(n * log(n)) 的 *FFT演算法」

  • TLE : Time limit exceeded,通常是演算法不夠有效率或是實作得不好導致常數大程式跑太久
  • FFT : Fast Fourier Transformation,可用於實做大數乘法的演算法

這時我陷入了掙扎,我知道以我悲慘的實做能力沒辦法在時限內完成兩種演算法,一分鐘後我下了決定:我要開始刻我從來沒寫過的FFT演算法。

老實說,此時的我已經不只是為了考試成績在寫。我在42的這一個月找回了我以前寫code時那種興奮的感覺。每一次看到自己的程式碼成功通過,自己好像又變強了一點點,這種不斷進步的感覺,滿足的感覺,好像是我開始coding的原因,也或許是這樣,我告訴自己就算寫不完也沒關係,我想要嘗試把這題用最好的作法做好,我想用我喜歡的演算法,完美成為第一個滿分。

心情的悸動很強烈,感性鞭策著理性追逐近在咫尺的目標,但燃燒7個多小時的腦袋已經幾乎停止運作,我第一次提筆勉強在紙上寫出本該簡單直覺的算式。

最後30分鐘我開啟vim,這估計100到200行的程式碼並沒有給我太多的容錯空間,我沒鼓起勇氣用簡單的除法計算我每秒要打多少單字,我只告訴我自己:不要犯錯、不要停滯。

打完最後一行程式碼,撇了眼時鐘,我還有最後10分鐘。緊張的時刻,

$> gcc -Wall -Werror -Wextra -fsanitize=address *.c
$> ./a.out 9848676874 68468486

此時我只能祈禱一切運作正常。

674323994665992764

恩…看似很合理的數字,趕緊打開python一驗

>>> print(9848676874 * 68468486)
674323994665992764

「噫!好了!我中了!」我簡直不敢相信自己的眼睛

我二話不說直接push…

$> grademe
$> (y/n) y

FAILURE

「蛤?」還來不及膨脹的我馬上被戳爆

「歐我沒處理負數啦,太低能了吧」此時我是唯一能吐槽自己的人(還有考官啦但這樣太白目了)。

於是我一分鐘內處理好負數,然後重新上傳

$> grademe
$> (y/n) y
You need to wait for 10 minutes 53 seconds to ...

唉,每次的失誤都會增加我等待的時間,所以對我而言,剩下這5分鐘已經沒用了,很遺憾,我每一次考試都是差一題滿分。

我略感失落,雖然沒有劃上完美的句點,但至少還能接受,就出校園跟朋友們一起去吃晚餐了。(大家也都考得還不錯)

不過故事的最後,我跟朋友X講的屁話竟然成真了,我們這屆出現了第一個Final Exam滿分的同學!!但我沒問他有沒有用FFT做最後的大數乘法,有機會再說

--

--

Leo Fu
台灣人 @ Ecole42

Taiwanese in school 42 Lyon. 現居於法國里昂的台灣人,不喜歡傳統大學教育模式後休學來到法國唸 school 42 ,程式、數學、商管、語言的知識通吃。