ドナドナされるプログラマのメモ

Windows用アプリのプログラミングメモ

Factorioでエッジカウンタ

Factorioでヒステリシスつきエッジカウンタ。

入力信号がリセット状態からセット状態になると1パルスだけ信号を出力します。

f:id:donadonasan:20200609231241p:plain

Factorio用ヒステリシス付きエッジ抽出回路 概要

f:id:donadonasan:20200609232021p:plain

Factorio用ヒステリシス付きエッジ抽出回路 詳細


以下、BluePrint.

Edge Counter for Factorio

Ryzen搭載14インチノートPCの検討

今まで使っていたThinkPad X240のキーボードが不具合をおこした。修理しようかと思ったけどかなり古いPCでもあったので、買い替えることに。そこで、何を買うか検討してみた・・・が、比較表を作っただけで時間切れ。なんで各社とも、発表内容と仕様が食い違うなどのミスが多いのだ。ノートPC業界はいい加減なんだろうか?

要求仕様

  • 本体サイズ:13~14インチノートPC
  • ディスプレイ:フルHD以上
  • OS:Windows10 64bit 可能ならProf.
  • CPU:AMD Ryzen 5 4600Hまたは4650U
  • RAM:8GB以上(ただし換装可ならそれ以下もOK)
  • 電源:USB Type-C優先
  • SSD:256GB以上(M.2スロット)
  • WiFi:必須、種別問わず
  • USBポート:2以上(電源用は別カウント)
  • 有線LAN:あったほうがよい

予算

4年間使用、毎月¥3,000相当の価値があるとして¥144,000程度まで

各社PCの比較(2020/06/06現在)

メーカー Lenovo Lenovo Lenovo Lenovo Lenovo Lenovo Lenovo DELL ASUS ASUS MSI MSI
ブランド ThinkPad ThinkPad ThinkPad ThinkPad ThinkPad ThinkPad Legion G5 ROG ROG    
シリーズ L14 Gen 1 L15 Gen 1 L15 Gen 1 X13 Gen 1 T14s Gen 1 T14 Gen 1 Legion 550 15プレミアム TUF A15 Zephyrus G14 Bravo 15 Modern 14
ステータス 発売日未定 発売日未定 発売日未定 発売中 発売中 発売中 7/17 発売中 6月中旬発売 6/26発売予定 6/22発売予定 6/15発売予定
納期目安 未発売 未発売 未発売 1-2週間 1-2週間 1-2週間 不明 3-5日? 不明 不明 不明 不明
標準価格 未公表 ¥170,000 ¥150,000 ¥227,700 ¥222,200 ¥199,100 ¥130,000 ¥152,980 ¥108,909 ¥118,164 不明 不明
実売価格(2020/06/06) 不明 不明 不明 ¥122,958 ¥124,432 ¥103,532 不明 ¥115,984 ¥98,909 ¥106,347 ¥119,800 ¥98,800
OS Win10Prof64bit Win10Prof64bit Win10Prof64bit Win10Prof64bit Win10Prof64bit Win10Prof64bit Win10Home64bit Win10Prof64bit Win10Home64bit Win10Home64bit Win10Home64bit
Win10Home64bit
CPU Ryzen5PRO 4650U Ryzen5PRO 4650U Ryzen5 4500U Ryzen5PRO 4650U Ryzen5PRO 4650U Ryzen5PRO 4650U Ryzen5 4600H Ryzen5 4600H Ryzen5 4600H Ryzen5 4600HS Ryzen5 4600H Ryzen5 4500U
定格クロック 2.1GHz 2.1GHz 2.3GHz 2.1GHz 2.1GHz 2.1GHz 3.0GHz 3.0GHz 3.0GHz 3.0GHz 3.0GHz 2.3GHz
最大クロック 4.0GHz 4.0GHz 4.0GHz 4.0GHz 4.0GHz 4.0GHz 4.0GHz 4.0GHz 4.0GHz 4.0GHz 4.0GHz 4.0GHz
TDP 10-25W 10-25W 15W 10-25W 10-25W 10-25W 45W 45W 45W 35W? 45W 15W
電池容量 未公開 未公開 48Wh 48Wh 57Wh 50Wh 不明 51Wh 48Wh 76Wh? 51Wh  
追加GPU なし なし なし なし なし なし GTX1650Ti RadeonRX5600M GeForceGTX1650 GeForceGTX1650 RadeonRX5300M なし
RAM容量 最大64GB 8GB 8GB 8GB 8GB 8GB 16GB 8GB 8GB 8GB 16GB 16GB
RAM仕様 PC4-25600 PC4-25600 PC4-25600 PC4-25600 PC4-25600 PC4-25600 PC4-25600 PC4-25600 PC4-25600 PC4-25600 DDR4 DDR4
RAMスロット数 2 2 2 0(オンボード) 0(オンボード) 1(+オンボード×1) 2 2 2?(信用できない) 1 2  
SSDタイプ 未公表 M.2 PCIe NVME M.2 PCIe NVME M.2 PCIe NVME M.2 PCIe NVME M.2 PCIe NVME M.2 PCIe NVME M.2 PCIe NVME M.2 PCIe NVME M.2 PCIe NVME M.2 PCIe NVME M.2
SSD容量 未公表 256GB 256GB 256GB 256GB 256GB 512GB 512GB 512GB 512GB 512GB 512GB
画面サイズ 14 15.6 15.6 13.3 14 14 15.6 15.6 15.6 14 15.6 14
解像度 HD or FHD HD HD FHD FHD FHD FHD FHD FHD FHD FHD FHD
ノングレア yes yes yes yes yes yes yes yes yes yes yes yes
本体サイズ 331×235×20.4 366.5×250×21.7 366.5×250×21.7 311.9×217.2×16.9 329×226.15×16.7 329×227×17.9 363.1×259.6×23.6 365.5×254×21.6 359.8×256×24.7 324×222×18.9 359×254×21.7 319×220.2×16.9
重量 1.61 1.98 1.98 1.28 1.33 1.57 2.3 2.5 2.3 1.65 1.96 1.3
有線LAN 1 1 1 0 0 1 1 1 1 0 0 0
USB3.1 Type-C 1 1 1 2 2 2 0 0 1 2 0 1
USB3.0 Type-C 1 1 1 0 0 0 1 1 0 0 1 0
USB3.0 Type-A 2 2 2 2 2 2 4 1 2 2 3 0
USB2.0 Type-A 0 0 0 0 0 0 0 2 1 0 0 2
電源コネクタ USB3.1 Type-C USB3.1 Type-C USB3.1 Type-C USB3.1 Type-C USB3.1 Type-C USB3.1 Type-C 独自 独自 独自+USB Type-C 独自+USB Type-C 独自 独自
HDMIポート 1 1 1 1 1 1 1 1 1 1 1 1
DisplayPort 0 0 0 0 0 0 0 MiniDP×1 0 0 0 0
趣味でつけたオプション       IRカメラ IRカメラ IRカメラ            
備考 6/5発売予定が
発売日未定に
6/5発売予定が
発売日未定に
6/5発売予定が
発売日未定に
          Win10Pro,
RTX2060、
バッテリ90Whを
謳うも存在しない
KingSoft Office USB-PD非対応  

 

 

各社PCへのリンク

Lenovo

ThinkPad L14 Gen 1(AMD) | 豊富な拡張性と接続性を備えた14型メインストリームPC | レノボジャパン

ThinkPad L15 Gen 1 (AMD) | 豊富な拡張性と接続性を備えた15.6型メインストリームPC | レノボジャパン

ThinkPad X13 Gen 1 (AMD)| コンパクトでパワフルな13.3型モバイルノート | レノボジャパン

ThinkPad T14s Gen 1 (AMD) | 14型ハイパフォーマンス・スリム・ノート | レノボジャパン

ThinkPad T14 Gen 1 (AMD) | 14型ハイパフォーマンス・ノート | レノボジャパン

Lenovo Legion 550 | AMD Ryzen搭載15.6型ゲーミングノート | レノボジャパン

DELL

Dell G5 15インチ ゲーミング ノートパソコン(AMD Radeon CPU搭載) | Dell 日本

ASUS

ASUS TUF Gaming A15 | ASUS TUF Gaming | ノートパソコン | ASUS日本

ROG Zephyrus G14 | Gaming | ノートパソコン | ASUS日本

MSI

MSI - AMD Ryzen 搭載ゲーミングノートPC Bravo 15

MSI ビジネス・クリエイターノートPC Modern 14 - B4M

1日1時間Factorio

Factorio Space Explorationの進捗。

  • とりあえず宇宙まで行った
  • 地上で作れるアイテムは、ほぼ全て生産自動化した
  • ディープ・スペース・サイエンスパックを毎秒1個作れるラインを構築中
  • 拡張総合生物カタログ、総合生物カタログ、大域生物カタログ、重要なバイオマス、実験バイオマスは構築完了。
  • 生物カタログとバイオマスを構築すれば生物系のラインはきっと完成。

以下詳細。

続きを読む

Factorio Space Explorationメモ:貨物ロケットの自動準備

FactorioのSpace Exploration Modをプレイしていると、そのうち母星の資源が枯渇してくる。そうなると他の惑星へ資源を奪いに行く必要がある。Factorioの醍醐味は様々な工夫による作業の自動化にあるので、できれば奪った資源の輸送も自動化したい。しかし、ここで問題になるのは貨物ロケットの発射準備方法。貨物ロケットを発射するには、発射台に以下をセットする必要がある。

  • 宇宙カプセル×1
  • 貨物ロケットセクション×100
  • 液体燃料×(目的地までの距離により異なるらしい)

このうち、液体燃料は生産・貯蔵設備からパイプを発射台に繋げておけば勝手に必要量だけ重点されるので楽なのだが、残りの2つが曲者。発射台にはロケットに載せる貨物もセットできるのだが、貨物のセット先も上記ロケットの部品のセット先も共通なのだ。そのため、何も考えずにインサーターで宇宙カプセルや貨物ロケットセクションを発射台にセットする構成にすると、必要量以上がセットされてしまい貨物ロケットがこれら部品で埋まってしまう。そのため、以下の仕掛けが必要になる。

  • 発射準備中であることを認識する
  • 発射準備中ならば部品を必要量だけセットする

発射準備中かどうかは発射台から出てくる信号で識別ができ、0が準備中、1が準備完了である。またFactorioでは信号の比較、信号の加減乗除ができ、ラッチ回路等も作れる。以上の道具立てからすると、実現方法は・・いくつもあるなあ。思いついた各方式の概要を列挙してみる。

  • 1->0の信号変化をトリガーに所定の個数をセットする。
  • 1のときはセットせず、0の間だけ所定の個数をセットする。
  • 宇宙カプセルを1個だけセット後、信号が1になるまで貨物ロケットセクションをぶちこむ。
  • 打ち上げに必要な部品はセットと同時に消滅する(発射台に吸収される)ことを利用し、各部品をひたすらセットするインサーターとひたすら取り除くインサーターを設置する(信号は使わない)

・・・あれ?ラッチとかが必須かと思ったけど、一番最後のをちょっぴり改良して、セットするインサーターを発射台からの信号で直接制御してあげれば行けるんじゃない?つまり、こうだ。

f:id:donadonasan:20200526180659p:plain

ひたすら部品のセットと除去をする例(失敗)

でも、これは失敗。セットする方にスタックフィルタインサータを使ったにも関わらず、なぜか普通のフィルタインサータが全てを瞬時に除去してしまうのだ。

ということで、他の方式を検討する。まずラッチ方式だが、リセット信号のエッジ検出がめんどくさそうなのでパス。そこで、信号が1の間は部品をセットせず、信号が0の間だけ所定の個数セットする方式にする。所定の個数をカウントする回路のクリアは、信号=1を条件とすればタイミングチャート的に大丈夫なはず・・。

f:id:donadonasan:20200526184841p:plain

3個だけインサータでセットする場合のタイミングチャート

などと思いながら回路を組んでいたら、発射台からセット済みアイテムの個数も出力されていたことが発覚。ラッキー。(でも考えたり記事書いたりしたのにかかった数時間は無駄に)

f:id:donadonasan:20200526191705p:plain

発射台からの出力信号例。Lは発射先までの距離、Eは空いている貨物スロット数、Fは埋まっている貨物スロット数

 

Factorio スペース・エクスプローラーでのアイテム制作メモ

Factorio スペース・エクスプローラーでディープ・スペース・サイエンス・パックを含む各種パックを作ろうとすると、拡張総合~カタログのレイヤーまではそれぞれが絡み合っているため必要な工場数がよくわからない。そこで、毎秒1個生産する場合に必要な工場の数を整理した。コンピュータは量子スーパーコンピュータを基本とした。

 

  流速 設備 設備数
天文学サイエンスパック 1 宇宙工場 3
生物化学パック 1 宇宙工場 3
エネルギー科学パック 1 宇宙工場 3
材料科学パック 1 宇宙工場 3
ディープ・スペース・サイエンス・パック 1 宇宙工場 2
重要なデータ 24 量子 288
天文学インサイト 44.2 ニューラル 24
生物学的インサイト 44.2 ニューラル 24
エナジーインサイト 44.2 ニューラル 24
材質インサイト 44.2 ニューラル 24
拡張総合天体カタログ 2.02 ニューラル 27
拡張総合生物カタログ 2.02 ニューラル 27
拡張エネルギーカタログ 2.02 ニューラル 27
拡張総合材質カタログ 2.02 ニューラル 27

 

重要なデータ・・まじか・・

 

Factorioでアイテム生産に必要な工場の数を試算するツール(FactorioFactoryCalculator)

Factorioでアイテム生産に必要な工場の数を試算するためのツール, FactorioFactoryCalculatorを公開しました。これを使えば、例えば製造サイエンスパックを毎秒3個作るために必要な、生産力モジュール1の工場の数やそのための発展基板工場の数などが試算できます。

  • プロジェクトページ

github.com

  • バイナリ公開場所

Releases · nibasya/FactorioFactoryCalculator · GitHub

重い処理中にステータス(状態)を表示するダイアログの実装(ユーザーインターフェーススレッド)

解決したい課題

MFCを使ったソフトにおいて重い処理をしている最中に、進捗等を表示するダイアログを表示したくなることは多々ある。しかし、単純にダイアログを作って表示しようとしても、以下のようにうまく行かないことが多い。

  • 重い処理が終わるまでダイアログが表示されない
  • ダイアログは表示されるが、表示内容が更新されない

何が原因か

これらが起きるのは、今の処理が終わらないとダイアログを表示するための処理が実行されないためである。ダイアログの表示やコントロールの変更を処理するメッセージはダイアログのメッセージプロシージャで処理されるのだが、困ったことにこのメッセージプロシージャは、デフォルトではメインウィンドウのメッセージプロシージャに接続されてしまうようなのだ。そのため、メインウィンドウのメッセージプロシージャが重い処理によって応答しなくなった場合、ダイアログの方も応答が止まり上記の症状が発生する。

一般的な解決方法

一般的な解決方法は、重い処理を別スレッド化してしまい、メインのメッセージプロシージャの応答性を確保することである。すなわち、AfxBeginThread()を使ってワーカースレッドを生成し、そのスレッド上で重い処理を実行する。AfxBeginThreadの第1引数はワーカースレッドの関数、第2引数はその関数への引数である。多くの場合、第2引数はワーカースレッドに渡したいオブジェクト、すなわちその関数が属するオブジェクトへのポインタである。そしてメインのウィンドウまたはダイアログでは、適宜ワーカースレッドの状態などを覗いてGUI上の表示を更新する。

Example of creating worker thread

この方法にて注意すべき点は、通常はワーカースレッドからはメイン側のMFC関数を直接呼び出せないことである。例えば、SetWindowText()を直接呼び出すことはできない。これは、ワーカースレッドにはMFCオブジェクト生成時に自動保存されるHWND情報が無いためである。詳しくは以下を参照。

マルチスレッド: MFC プログラミングのヒント | Microsoft Docs

そのため、前述のようにダイアログ側から適宜覗いて表示を更新するか、上記リンクにあるようにPostMessage()等を使ってメイン側ウィンドウに表示の更新を促すメッセージを送る必要がある。なお、上記リンクには FromHandle()を使ってメイン側オブジェクトへのポインタを取得してアクセスすることも書かれているが、これによりアクセスできるのは各MFCオブジェクトであり、MFCから派生したユーザー定義のクラスではないため実用的ではない。

ワーカースレッドに処理を移せない場合の解決方法

「重い処理」の内容によっては、処理をワーカースレッドに移すことができない。たとえば、CTreeCtrlに数万、数十万のノードを追加する処理は非常に重いのでワーカースレッドに移したくなるが、前述の通りワーカースレッドからはメイン側のMFC関数を呼び出せないため移せない。

このような場合は、例えばメインウィンドウとは別のスレッドを生成し、ダイアログのメッセージプロシージャをそちらのスレッドに接続すればよい。このようにすれば、メインウィンドウは重い処理のために応答しなくなるが、状態を表示するダイアログは応答を継続できる。MFCにおいて、メッセージプロシージャを有するスレッドはユーザーインターフェーススレッドと呼ばれ、単純なスレッドであるワーカースレッドとは区別される。ユーザーインターフェーススレッドもAfxBeginThreadで生成できるが、ワーカースレッド生成時とは引数が異なり以下の引数の方を使う。

CWinThread* AfxBeginThread(
  CRuntimeClass* pThreadClass,
  int nPriority = THREAD_PRIORITY_NORMAL,
  UINT nStackSize = 0,
  DWORD dwCreateFlags = 0,
  LPSECURITY_ATTRIBUTES lpSecurityAttrs = NULL);

使用例は以下の通り。

CStatusDlgThread* pThread = DYNAMIC_DOWNCAST(CStatusDlgThread, AfxBeginThread(RUNTIME_CLASS(CStatusDlgThread)));

ここで、CStatusDlgThreadはCWndThreadクラスの派生であり、ユーザーインターフェーススレッドの実体である。また、DYNAMIC_DOWNCASTは単なるdynamic_castでもよいはずだが、ここではMFCの流儀に則っている。

作成したユーザーインターフェーススレッドにダイアログのメッセージプロシージャを接続するには、CWndThread::m_pMainWndにダイアログへのポインタをセットすればよい。

ダイアログに表示する内容を変更する場合は、メインウィンドウからダイアログに対しユーザー定義のメッセージをSend / PostMessageする。

状態を表示するためのエディットボックスと処理を中止するキャンセルボタンを有するダイアログの実装例を以下に示す。この例では、以下のような構成となっている。

  • CFactorioFactoryCalculatorDlg:メインウィンドウのダイアログ。OnCbnSelchangeComboTarget()が呼び出された際に、AddNode()を呼び出してCTreeCtrl m_CtrlTreeに大量のアイテムを追加する。追加処理中に状態表示ダイアログを表示し、ユーザーに進捗を示す。
  • CStatusDlg:状態表示ダイアログ。ユーザー定義のメッセージ:ID_UPDATE_STATUSを受け取ると、メンバ変数:m_Statusにセットされた文字列をエディットボックスに表示する。
  • CStatusDlgThread:状態表示ダイアログのユーザーインターフェーススレッド。状態表示ダイアログを所有し、InitInstance時にDoModal()を呼び出す。ダイアログが閉じられるとm_Validがfalseとなり、メインウィンドウ側は処理を中止すべき状態になったことを知ることができる。UpdateStatusを呼び出すことでダイアログに文字列を表示できる。

f:id:donadonasan:20200505102718p:plain

実装したダイアログの外観

A dialog with independent User Interface thread (C ...