文章

顯示從 6月, 2021 起發佈的文章

[Game] 如何安裝 S.T.A.L.K.E.R. Anomaly 插件,以及解決插件導致的 Crash

圖片
看 Reddit 裡面這麼多人 po 一些 Anomaly 的遊戲影片,突然就想玩,不過這插件真是多到可怕。 安裝 STALKER Anomaly 這步驟應該不會有什麼問題,就去 Anomaly 官網 下載,然後安裝就好了。 要安裝哪些插件 (Addons/Mods)? 這才是最困難的步驟吧,去看 Addons 有哪些赫然發現竟然有將近 1500 個 mods,我到底要選哪一個? 有沒有什麼推薦的安裝列表呢? 後來就在 reddit r/stalker 右邊側欄看到有一個人 Grok 有整理一份不錯的 Google Sheet 表單 : 打開來看雖然也是密密麻麻的看起來很恐怖,但是他其實有放上推薦度和這些插件是做什麼的,還有插件之間的衝突要如何依序解決: 我就把一些 Mandatory 和 Highly recommended 的插件裝來玩玩看。 當然你也可以自己仔細研究,或是參考別人的清單 (例如隨便 Google 一下就找到 Lazy Stalker 的推薦插件清單 )。 如何安裝插件 通常插件都是裝在壓縮檔 zip/7z/rar,打開來至少會看到 gamedata 資料夾,那你就可以複製貼上到遊戲的目錄覆蓋。 但是許多插件本身是會互相衝突,或是部分衝突的。 這樣蓋來蓋去根據以前玩可以客製化的 CS1.6 的經驗來說,走到某一個地步你的遊戲就會開始 crash、發現有材質壞掉、甚至不知道到底是裝了哪個插件造成的,也沒辦法還原。 重頭來過? 或是提心吊膽的一直把整包遊戲壓縮怕哪天突然壞掉,我們應該有更好的做法。 用 Mod Organizer 2 忘記是在哪看到的了,但好像有人推薦用這個來管理插件,所以我就來試用看看。 安裝步驟其實滿繁瑣的,所以我也不會寫整個文章就用完所有力氣只是在教你如何安裝,因為大部分的資源都是英文的,所以我也期待你應該至少看得懂一些英文。 大致上的安裝步驟如下: 先去 Mod Organizer 2 官網 看一下 裡面有 GitHub 連結,去 GitHub 找 "Mod.Organizer-x.x.x.exe" 或 .7z 下載 打開 Mod Organizer 2 創新的 Instance, 一個 Instance 通常就搭配一款遊戲 (他不只能用在 Stalker,還可以用在 Fallout, Skyrim 上...

[LeetCode][C++] 用乾淨的方式寫 #19 Remove Nth Node From End of List

圖片
又是一個資料結構練習? 但仔細一看他希望我們做 one pass 就可以輸出答案。 我 OK,你先走 n 步 如果我們用左右兩個指標,讓右邊的指標先走 n 步,會發生什麼事? 我們就先模擬看看,當右邊的人一踩到 nullptr ,左邊的指標在哪? 假設 n=2 我們看到左邊的指標正好指著要刪除的 node,好像就做完了。 問題是,現在要怎麼刪除左邊的人? 單向的 linked list 一旦往後走就不能回頭了,我們想把 2 接到 4 現在就卡死動彈不得了。 我 OK,你先走 n + 1 步 既然我們想要把左右兩邊的指標再距離寬一點,那我們就會很直覺的想把 n + 1 再模擬看看: 但如果 n 剛好等於 linked list 長度,右邊先跑 n + 1 步的話左邊的人不就會超出範圍? 所以我們就用一個常見的技巧,創一個虛擬的 node,LeetCode 上叫做 dummy ,不過我覺得叫 root 比較好,比較有起始點的感覺。 當右邊指標撞到 nullptr 左邊指標的下一個人剛好就是要刪除的對象,這時候就不會有問題。 Boundary Cases 養成好習慣我們還是要稍微想一下比較容易出問題的邊界條件: 如果 n=1 會不會有問題? 不會 如果 n=size 會不會有問題? left 會在 root 的位置,刪除下一個人也不會有問題 好讀的 C++ 程式碼 我們想要讓維護的人一看就知道程式碼在做什麼,所以我的習慣就是用小小的 function 加上很好懂得名稱告訴別人我 function 在做什麼,而且一次只做一件事。 這樣  removeNthFromEnd 就會看起來很清爽: class Solution { public: ListNode *removeNthFromEnd(ListNode *head, int n) { ListNode root(0, head); ListNode *left = &root; ListNode *right = &root; right = moveNSteps(right, n + 1); while (right != nullptr) { left = moveNSteps(left, 1); right...

[技巧] 簡單地讓 Google Analytics 排除 iOS/Android 瀏覽器上自己的流量

圖片
如果在電腦上用 插件 應該是最方便的做法,可是手機上怎麼辦? 如果我用手機上的 Safari 瀏覽我自己部落格的網站,Analytics 裡面就會出現。 想要簡單的 Filter 查了網路有 很多做法 都不太行: 用 IP,可是手機如果用 3G/4G/5G IP 位址就不固定,我可不想一直開 Analytics 調整設定 設定特殊的 cookies,可是我或許只是想用在部落格,拜託不要那麼複雜 在自己的網頁先做一次 filter,但我是部落格,我不是在寫網頁 所以我上網到處 Google,先看看別人都怎麼做的,算是有點被 這篇文章 給啟發,裡面有一個地方用 query parameter 來做 filter: ?internal=true 那我就想到一個超簡單的作法,因為我通常只是想要測試一篇文章在手機滑起來感覺如何而已,那我可以這樣做: 在手機上瀏覽自己的部落格文章前先加上  ?internal=true 去 Analytics 把含有  ?internal=true  的網址排除掉 Analytics 操作 我們打開 Analytics,去到設定頁面內找 Filter (篩選器),加上一條規則: Filter type (篩選器類型): Custom (自訂) Exclude (排除) Filter Field (篩選器欄位): Request URI (要求 URI) Filter Pattern (篩選器模式): ^.*[?&]internal=true.*$ Case Sensitive (區分大小寫): 這要不要勾選應該都可以,嚴格一點就勾起來 我的介面是英文的,不過中文的介面應該也差不多。 如果你是用 account (帳戶) 下的篩選器,別忘記要套用到 views (資料檢視),我一開始忘記套用還以為打錯 pattern: 測試有沒有排除 我就隨便找一篇我部落格文章的網址: https://shawnchang420.blogspot.com/2021/04/ynab-toolkit-for-ynab.html 加上  ?internal=true  之後變成: https://shawnchang420.blogspot.com/2021/04/ynab-toolkit-f...

[LeetCode][C++] 用乾淨的方式寫 #2 Add Two Numbers

圖片
這一題很簡單,感覺就是在練習資料結構居多,但是很容易就會寫得很亂... Function 太多行了 我自己一開始練習就寫出像下面這樣子的 C++ code: class Solution { public: ListNode *addTwoNumbers(ListNode *l1, ListNode *l2) { ListNode *curNode = new ListNode(); ListNode *head = curNode; int carry = 0; while (true) { const int sum = (l1 ? l1->val : 0) + (l2 ? l2->val : 0) + carry; carry = sum / 10; curNode->val = sum % 10; l1 = l1 ? l1->next : l1; l2 = l2 ? l2->next : l2; if (!l1 && !l2 && !carry) { break; } curNode->next = new ListNode(); curNode = curNode->next; } delete curNode->next; curNode->next = nullptr; return head; } }; 如果我不跟你說題目是什麼,看到的話會覺得這蝦米? 如果你現在上網搜尋其他解答,會發現大家解答好像都長得差不多,反正就是一個 while 裡面做一大坨事。 仔細分析一下我們會發現為什麼通常我們都會寫出很複雜的 code: 我們同時要 traverse 兩個 linked list 我們同時要輸出到一個越長越長的 linked list 我們同時又要算加法,把 carry 帶到下一位 我們把三件事混在一起,當然程式碼會很複雜。 Clean Code 如果我們把上面說的那三件事切開來處理,變成多個 functions,一個 function 專心做一件事,會不會好看一點呢...

[LeetCode] 為何不用 Two Pointers 來寫第一題? #1 Two Sum

圖片
LeetCode 有一堆題目都很愛用 two pointers,為何第一題不用一下呢? 用 Two Pointers 會遇到什麼問題 用 two pointers 前通常要確保 arrays 是排序好的,這一題的 input 並沒有排序好。(two pointers 的原理可以看 #16 前面 有做過解釋) 就算我們先排序好了,會發生什麼事? 像底下這樣: 因為題目要輸出兩個數的 indexes,看起來好像很 OK 但是馬上就會得到 wrong answer: 喔不! vector 被排序後的 indexes 和原來的不一樣了,正確答案應該是第 0 和第 2 個位置才對。 解決方法 怎麼辦? 這其實可以用一個還滿常用到的技巧,就是把 (number, index) 一起下去做 sorting: 我們把 number 和 index 綁在一起,任何人都不能拆散他們。做排序的時候就按照 number 來排序,這樣他們不管被怎麼排我們都還能知道原來的 index 是多少。 解法1: 用客製化的資料結構把他們綁在一起 這對我來說是最乾淨、不會出錯的方式,我們先定義一個 struct 叫做 Item : struct Item { int num = 0; int index = 0; }; 當我們在做 sorting 的時候就依照 num 來比較: std::sort(items.begin(), items.end(), [](const Item &item1, const Item &item2) { return item1.num < item2.num; }); 最後再用 two pointers,所以完整的 C++ 程式碼就會是這樣: struct Item { int num = 0; int index = 0; }; class Solution { public: std::vector<int> twoSum(std::vector<int> &nums, int target) { const int sz = (int)nums.size(); ...

[LeetCode] 優化 LeetCode 的解答,與 hashmap 另類解法 #18 4Sum

圖片
LeetCode 上 第一個解答 已經夠快了,一丟就 8ms,但我們有沒有辦法找出更快的解法? Profile 看看問題出在哪 用 Callgrind profile 一下發現他花了很多力氣在存取 nums array 和 destruct vector 上: 而且程式花了大部分的力氣在跑 twoSum : 看到 Self 那麼多 instructions 就代表大部分運算都卡在 twoSum 。 所以如果我們想要優化這個解法,我們可以用以下任何手段來達成: 減少 nums 被存取的次數 減少 create vectors,這樣就間接減少了 vector<>::~vector() 的機會 盡量少呼叫 twoSum 如何先刪除重複的數字? 因為 input 有可能有重複的數字,所以其實我們很常這樣寫來跳過重複的數字: if (... || nums[i - 1] != nums[i]) ... if (... || (lo > start && nums[lo] == nums[lo - 1])) ... if (... || (... && nums[hi] == nums[hi + 1])) ... 如果跑過 N 個數字,我們其實要存取 vector 2N 次,你可以用一個 variable 暫存上一個數字,可是你還是躲不過和上個數字比較。 可是我今天要介紹一個算是技巧嗎? 還是暴力解? 我們連比較都不用,因為我們把重複的數字都先刪掉了。 可是如果 input 有重複的數字,我們要怎麼輸出可能重複 2~4 次的數字? 窮舉重複數字 我們就先把這些答案先輸出就好了,想法就是我們把 4 個數字的各種多個數字重複的可能窮舉出來: a + a + a + a = target a + (b + b + b) = target (b + b + b) + a = target (a + a) + (b + b) = target (a + a) + b + c = target a + (b + b) + c = target a + b + (c + c) = target a + b + c + d = target 而且有一個條件 (requirement) 就是 a < b < c <...

此網誌的熱門文章

[試算表] 追蹤台股 Google Spreadsheet (未實現損益/已實現損益)

[Side Project] 互動式教學神經網路反向傳播 Interactive Computational Graph

[插件] 在 Chrome 網頁做區分大小寫的搜尋