リバースエンジニアリングを取り入れた詩的な談話

「古いアセンブラーは私たちに気づきました、

そして墓に降りて、彼は祝福した”







画像






一度詩を書くプログラムを書くことにしました。 アルゴリズムはすぐに登場しました-韻を踏む単語をコンパイルされたスタンザの最後に置き、韻、リズム、および既製の一貫したテキストから得られた他の単語の隣の発見の可能性を考慮した単語でスタンザの残りを埋めます。 押された韻を持つ一種のマルコフ連鎖。







アルゴリズムを実装する前に、他の人がすでに作成したものを確認することにしました。 最初のYandex検索が見つかりました(誰が疑うでしょう!) Yandex.Autopoet 、古典の詩で訓練されたニューラルネットワークを使用して。 2番目の項目は、プログラム「Assistant Poet」でした。このプログラムは、詳しく調べると、韻の通常の辞書であることが判明しました。 しかし、3位には有名な作家であり、フィドシュニックのレオ、別名レオニード・カガノフのサイトがありました。







なぜ彼はそこにたどり着いたのですか? 彼が鉱山研究所の学生だったとき、Lleoは論文として詩プログラムを書いたからです。 そのような卒業証書の弁護がどれほど詩的であったかはわかりませんが、プログラムはどうやらうまくいったようです-彼女が書いた詩は著者のサイトに投稿されました。 プログラム自体もそこで発見され、MS-DOSおよび32ビットDOS / 4GWエクステンダーで動作しました。 このバージョンのソースコードもアップロードされました。 卒業証書の説明文から、OS / 2のバージョンもあり、明らかにグラフィカルインターフェイスを備えていたが、そのソースコードが見つからなかったことを学びました。 しかし、MS-DOSバージョンはDOSBoxで実行でき、動作を確認できます。意味のあるものではありませんが、韻を踏んだ、かなり一貫した詩を実際に作成しました。 1996年、Lleoがこのプログラムを書いたとき、このレベルの自動生成された詩は非常にクールでした。 私の意見では、それらはYandex.Autopopoetの詩よりも悪くはありません。 または、Lleoは彼のプログラムの修正版の助けを借りて有名な作家になったのかもしれません。 (スキャンダル、陰謀、調査!もちろん冗談ですが、誰が知っていますか...)。







このプログラムがどのように機能するかを研究し始めました。 詩を作成するために、彼女は2つのファイルが必要でした-韻のための単語ベースとマークアップ、そして彼女が作成した詩のサイズ。 ソースはアセンブラーにあり、TASMの下では約3,500行のソースコードでした。 プログラムの作成者はこれについて次のように書いています。「アセンブラーのほとんどのタスクを選択しました。 その上で、プログラミング言語を選択できるようにするためのすべての教育作業を実行しました。 主に、この言語でプログラムをより迅速かつ簡単に記述およびデバッグできるため、マシンとより柔軟に対話できるようになります。」 そして、ここで私は完全に同意します-アセンブラーは非常に柔軟であり、プログラミングのパラダイムを課しません。 もちろん、最新の言語でプログラムを作成し、既製のサイコロライブラリから収集する方が高速です。 ソースコードには、当時のアセンブラープログラムのすべての特徴的な兆候が含まれていました-短く、常に理解できるとは限らない、著者のみが明らかにした変数と関数の名前。 「おそらく十分」というコメント付きの使用済み配列の固定サイズ。 多数のグローバル変数、およびいくつかの場所では、プログラムが韻を選択するための単語を使い果たした瞬間に「Creative Crisis !!!」のような機知に富んだ著者のコメントとエラーメッセージ この精神で:







@@punkt13: ;call io ;db 13,10,'{{F_LEVEL}}=',0 ;movzx eax,[F_LEVEL] ;call pr_dec cmp [nomer_LEVEL],0 ;13)     ■  16 jne @@punkt16 ;call io ;db 13,10,'  ',0 ;call key cmp [F_LEVEL],0 ;13.0)  ■ ■ =   jne @@punkt14 cmp [FREE_RHYME],0 ;13.1)     ,  je @@error_twor ;■ ■,  stc ret ;   @@punkt14: cmp [F_LEVEL],1 ;14) ; ■ ■ = ■ ■,  je @@565656 ;call io ;db 13,10,'   ,    ',0
      
      





それがすべての始まりです-ソースを研究することによって持ち去られ、私はもともとアルゴリズムをゼロから実装するつもりだったことを忘れていました。自分のアセンブラープログラムを覚えて、Lleoアルゴリズムを最新のプログラミング言語に移植することにしました。 さらに、このアルゴリズムは、私が念頭に置いていたものと非常に似ていました。 移植言語としてPythonを選択しました。Pythonでテキストを操作すると非常に便利です。







プログラムの分析は、コードを詳しく調べてコメント付きのコードをすべて削除したことから始まりました。多くのコードがありました。 彼はコメントアウトされたデバッグ出力のみを残しました-プログラムのこの場所で何が起こっているのかを理解するのに役立ちました。 次に、コマンドラインキーやファイルI / Oの取得など、純粋にユーティリティコールをすべて削除しました。 さて、アルゴリズムに関するコードしかなかったとき、私はそれを理解し、Pythonに移植し始めました。 目的が明確な関数については、名前をすぐに明確な名前に置き換えるか、Pythonで書き直してアセンブラーコードを削除しました。 残り-行ごとにPythonに翻訳し始めました。 もちろん、行ごとに、プログラムはグローバル状態変数を広​​く使用し、Pythonコードでこれが発生しないように、多くの場所で、元のプログラムの行に関係なく、アルゴリズムを完全に書き換える必要があると言われました。 この時点で、コードは次のようになりました。まだPythonではなく、アセンブラーではありません。







 randomValue = init random(777) if curMode=='C': print' ',13,10,' : ',0 BASEname NAME_SHABLON call loadBASE call CREATE else if curMode=='U': print'  ',13,10,' : ',0 call loadBASE call stat call setUdarenie_N call saveBASE # call automat -    # jmp @@udara1 return
      
      





残念なことに、経済的正当性について標準的ながらくたが書かれていると確信して、卒業証書の説明文のテキストをすぐに調べることはしませんでした。 このため、詩アルゴリズム自体と単語のデータベースのフォーマットは、文字通りリバースエンジニアリングしました。変数と関数の名前がわかりやすいため、プログラムのソースコードは逆アセンブラーのリストからそれほど遠くはありませんでした。 一般に、詩のアルゴリズムと言語ベースの形式は卒業証書に記載されています。 私は悔い改め、頭に灰を振りかけます。 彼らの分析にかかるのはたった数晩でした。 さらに、形式とアルゴリズムのすべての詳細がドキュメントに記載されているわけではないため、後のリバースエンジニアリングが継続されました。 バイナリデータを処理するために、Pythonは非常に便利なunpack関数を見つけました。 そして、データ内のデータのバイトの順序を少しいじっています(もちろん、プログラムはIntelプロセッサ用に書かれているので、ここではリトルエンディアンです)。ワードベースを読み込むことができました。 詩のリズムを含むファイル形式はテキスト形式で非常にシンプルで、ダウンロードするためにコードを分解する必要はありませんでした。







ここで、詩を書くための実際のアルゴリズムを理解する必要がありました。 上で書いたように、一般的に、それは説明的なメモで説明されましたが、いくつかの詳細はそこにありませんでした。 たとえば、詩のテンプレートが逆の順序で設定されているという事実-スタンザの終わりから始まりまで。 ラテン文字「p」はどこでもロシア語「p」に置き換えられているという事実-ロシア語「p」でグリッチがあり、どこでもラテン語に置き換えられたため、FIDO「p」からダウンロードされたロシア語のテキストでは「どこでもラテン語だったし、ロシア語に戻されるべきだった。 まあ、他の同様のささいなこと。 一般的に、アルゴリズムは記事の冒頭で説明した韻を伴うマルコフ連鎖に似ていましたが、スタンザの作成中に状態を保存するためにスタックを使用したという事実と、アルゴリズムが単語を見つけることなく行き止まりになった場合に状態をロールバックする機能によって区別されました必要なストレスと音節の数。 このコードは、特定のトピックの詩を構成する試みも示しました。このトピックの最初の単語が選択され、その後、関連する単語で検索が行われました。 しかし、この機能は機能しなかったようであり、 make_RND_FIELD_TEMA



関数では、ワードのハードコーディングされたインデックスが1つだけmake_RND_FIELD_TEMA



make_RND_FIELD_TEMA



からプログラムがワードのマッチングを開始します。







プログラムを解析する過程で、面白い瞬間がありました。

たとえば、プログラムの最初に次のような断片がありました。







 jmp @@skip ; ... db 'WATCOM' ;     ,    DOS4GW @@skip:
      
      





実際のところ、32ビットDOS / 4GWエクステンダーは、Watcom商用コンパイラーでコンパイルされたプログラム用に作成されており、それ自体が商用製品でした。 そして、プログラムがWatcomコンパイラーによってコンパイルされたという事実は、プログラムコードの先頭にある行「Watcom」によって決定されました。 この行が存在しない場合、DOS / 4GWは動作を拒否しました。 公平を期すと、当時の上級者はTranエキスパンダーによるPMODE / Wを使用していました。このナンセンスは、サイズが著しく小さく、無料で、プログラムに割り当てることができますが、DOS / 4GWは通常、個別の実行可能ファイル。







別のコードがありました:







 proc bswap_eax ;   , ,   386   bswap! mov [bswap_mes],eax ; ...
      
      





実際、80386プロセッサにはbswapコマンドはありませんでした。80486から開始され、たとえばバイトオーダーリトルエンディアン->ビッグエンディアンの変換に非常に便利であることが判明しました。 それで、人々はそのような機能とコメントを書きました。







私が詩を書くためのアルゴリズムをテストしたとき、別の面白いことが起こりました。 テストのために、「busy」という単語が韻に確実に挿入されるように、スタンザの終わりを尋ねました。これは、wordsデータベースファイルで間違いなく見ました。 しかし、何らかの理由でこの韻は見つかりませんでした。 「ビジー」という単語がデータベースに書き込まれ、最後の「o」はサービスデータの一部であり、それに関連付けられた単語へのポインタであることが判明しました。 「o」という文字であったことは単なる偶然です。







詩の執筆がうまくいったとき、私はすぐに散文(通常のマルコフ連鎖)を削減し、私のプログラムがオリジナルのプログラムの既製のものを使用するだけでなく、テキストから単語ベースを生成できるようにしました。 プログラムのほとんどは、ベースの生成に専念することが判明し、よく考え抜かれたアルゴリズムのおかげで、この部分は詩を構成するものよりも印象的でした。 実際、彼女は詩を構成するための準備作業をすべて行います。入力テキストから単語を解析し、それらを音節に分割し、音節の強勢の手動配置に関する以前に収集された統計に基づいて強勢を自動的に配置することさえできます。 ただし、強調は常に正しいとはほど遠い。 そして、私が知る限り、ロシア語ではストレスを置くための安定したルールはありません。 強調ベースは別個のファイル$$$$ SLOG.BSYに保存されていましたが、その形式は卒業証書に記載されていませんでした。 ここでも、少しリバースエンジニアリングを行う必要がありました。







単語データベースの生成が機能し始めたとき、すでにさまざまなテキストの実験を開始できました。 実験の結果、プログラムから取得した単語を音節に分解するアルゴリズムが常に正しく機能するとは限らないことが判明したため、最初から書き直しました。 これにより、押韻の終りを得るためのアルゴリズムを改良することもできました-今では音節とアクセントで機能し、母音に順番に行くだけでなく、この属性に基づいて正しい音節を見つけます。







その後、すべての機能をオブジェクトにパックし、モジュールに分解し、これらのモジュールを使用してPythonスクリプトをすばやく書き留め、コマンドラインから作業し、同じキーから始めて、元のプログラムと同じことを実行できるようにしました。 彼は、オリジナルのプログラムからデータベースをロードする方法も知っていますが、独自の形式で保存します-Python pickleによるデータのシリアル化。 元のプログラムのアルゴリズムはかなり粗末ですが、多くの場所で私は元のコメントを残しました-それらを読むのは面白いです、そしてそれらはその時代の精神を保持します。 さらに、-oldschoolスイッチを使用して起動すると、スクリプトは元のプログラムをヘルプコンソールに表示します。このプログラムでは、さまざまな人や船への挨拶の束があります。







詩を構成する例は次のとおりです。







 ***                            
      
      





 ***                                           
      
      





その結果、私たちはグラフォマの詩を構成するプログラムを手にしました。その助けを借りて、さまざまなテキストを実験することは非常に興味深いものです。







それに対して他にできること:









実際、この記事で説明したいことはこれだけです。

労働の成果をGithubに投稿しました。







ご清聴ありがとうございました!








All Articles