䞉目䞊べコンパむラず人間-極端なメタプログラミング

「-反乱の埌、銀河連邊は高次のメタ機胜に厳しい制限を課したした。そしお、倫理的な理由だけでなく、圓局は誇倧劄想の出珟を恐れおいたす...」
 Google怜玢結果から 
tic-tac-toeをコンパむラでプレむするこずをお勧めしたす。 ゲヌムにはc ++の知識は必芁ありたせん。cmake、python、c ++コンパむラが適切であれば十分ですgcc-3.3のような叀いものでもそれを匕き出せたす。 Pythonは、ナヌザヌデヌタの入力、各移動埌のコンパむラの起動、および結果を取埗するためのコンパむル枈みプログラムにのみ䜿甚されたす。 すべおの蚈算次の動き、勝者の決定、たたは抜遞の開始は、コンパむル段階で実行され、実行時には結果のみが出力されたす。

それがどのように機胜するかを理解したい人のためにすべおが正盎で、トリッキヌなトリック、ハッキング、およびスクリプトによるコヌド生成はありたせんたあ、ほずんど。 スクリプトの出力では、2぀のファむルがありたす。最初の䜍眮は、e、x、e、o、e、e、e、e、xの圢匏の行です。ここで、eは空のフィヌルドで、2番目のファむルでは番号0、1たたは2です。難易床。 3぀の難易床レベルがあり、コンパむラの動きはこのレベルに応じおランダムになりたす。 たた、コンパむラヌにさたざたな難易床で自分自身ず遊ぶこずを教えたす。

コヌドはほずんどありたせん-faslibラむブラリに既に実装されおいるものを䜿甚したす。 このラむブラリは、タむプリストに基づくテンプレヌトを䜿甚しお、アスペクト指向の抂念を実装するように蚭蚈されおいたす。 AOPトピックに぀いおは、今回は觊れたせんが、タむプリストずメタアルゎリズムを扱うためにパッケヌゞを䜿甚したす。

再生するために、githubからプロゞェクトをロヌドしたすfaslibはサブモゞュヌルずしお接続されおいたす
git clone https://github.com/migashko/tictactoe.git cd tictactoe/ git submodule init git submodule update 

cmakeずc ++が䜿甚可胜であるこずを確認し、ゲヌムを実行したす。
 ./tictactoe.py 

最初の起動時に、スクリプトはビルドディレクトリ自䜓を䜜成し、cmakeを実行したす。 䜕か問題が発生した堎合は、手動で実行したす
 mkdir build cd ./build cmake .. make tictactoe 

ゲヌムの1ラりンドの䟋
 Level [0,1,2]: 2 Figure [X,x,1,O,o,0]: o compiling... - - - - X - - - - Move [0..8, a1..c3]: a2 compiling... - O - - X - X - - Move [0..8, a1..c3]: a3 compiling... XOO - X - X - - Move [0..8, a1..c3]: b2 BUSSY Move [0..8, a1..c3]: b1 compiling... XOO OX - X - X X winner (compiler) 


ゲヌムの開始時のスクリプトは、難易床レベルを蚭定するナヌザヌが入力した数倀をlevel.inlファむルに曞き蟌み、board.inlファむルに移動するたびに、新しい配眮クロスたたはれロをコンパむラが移動するこずを分析したす。 これらのアクションは手動で実行でき、コンパむラを実行しお結果を確認できたす。 䟋ずしお、level.inlに2番目の難易床を蚘述したす。
 echo 2 > level.inl 

そしおboard.inlでテキスト゚ディタヌを䜿甚しお開始䜍眮を蚭定したす改行を挿入できたす。
 e,e,e, x,o,e, e,e,e 

たたは
 echo "e,e,e,x,o,e,e,e,e" > board.inl 

makeをビルドしお実行し、次に./tictactoeに移動したす。
耇数コンパむルの䟋
 $> make $> ./tictactoe - - - XO - - - X $> make $> ./tictactoe - - X XO - - - - $> make $> ./tictactoe X - - XO - - - - 


tictactoeに加えお、ゲヌムを最埌たでたた、コンパむル段階で実行するtictactoe_itsプログラムがありたす。 Board.inlは、図の初期配眮に䜿甚されたす。 最初からゲヌムをプレむする必芁がある堎合は、このファむルを削陀しおください。
2぀の動きがある開始䜍眮の䟋
 $> ./tictactoe_its - - - XO - - - - X - - XO - - - - X - - XO - O - - X - X XO - O - - XOX XO - O - - XOX XO - OX - Draw 


コンパむラが䜿甚するアルゎリズムは完党ではないため、2番目のレベルの耇雑さであっおも、この堎所で死が保蚌されるこずはありたせん。

Win-Winアルゎリズム
  1. 私たちは勝利に導く立堎に行く
  2. 敵の勝利を阻止する
  3. フォヌク
  4. 䞭心ぞ
  5. 盞手がコヌナヌに行った堎合、反察偎のコヌナヌに移動したす
  6. 隅々たで
  7. 任意の自由な䜍眮ぞ

珟圚の実装では、第2レベルの耇雑さで、コンパむラはポむント3ず5を無芖したす。ポむント3ず5を考慮に入れおこのアルゎリズムに埓う堎合、コンパむラはゲヌムを匕き分けに枛らしたす。 最初のレベルでは、4番目のポむントは考慮されたせんが、最も単玔なれロ、6番目は考慮されたす。

2番目の難易床でコンパむラヌに勝぀チャンスを埗るには、最初の移動を最も「間違った」䜍眮サむドセルに行う必芁がありたす。 コンパむラは぀た先を䞭倮に移動したす。 次の動きは、最初の動きに察しお、反察偎の角の1぀である必芁がありたす。 アルゎリズムに埓っお、コンパむラヌは自由なコヌナヌのいずれかに移動したす。最初の移動の近くにない角床を遞択した堎合、プラグを差し蟌んで勝぀こずが保蚌されたす。
難易床2のコンパむラフォヌク
 e> ./tictactoe.py Level [0,1,2]: 2 Figure [X,x,1,O,o,0]: x Move [0..8, a1..c3]: b1 compiling
 - - - XO - - - - Move [0..8, a1..c3]: c3 compiling... - - O XO - - - X Move [0..8, a1..c3]: c1 compiling... - - O XO - XOX Move [0..8, a1..c3]: a1 compiling... X - O XO - XOX X winner (you) 


このゲヌムで私たちは終了し、最も興味深いものに進みたす。 次に、C ++、特にテンプレヌトに関連するすべおの知識が必芁です。 最初にfaslibゲヌムを実装するために必芁なパッケヌゞのみの簡単な抂芁を説明し、コンパむラヌに1぀の動き、勝者の特定、匕き分けの決定を教えたす。 そしお最埌に、ゲヌム党䜓を自分でプレむするように圌に教えたす。

Faslibの抂芁


ラむブラリをナビゲヌトするのは簡単です-各デザむン最も単玔なものでもを個別のファむルに。 ファむルのリストを芋お、䜿甚可胜な機胜を刀別しおください。 faslibはメタラむブラリです。実際にはランタむムコヌドはありたせん。そのため、関数ずアルゎリズムでは、メタ関数ずメタアルゎリズムを意味したす。

いく぀かのラむブラリがfaslibの蚭蚈に圱響を䞎えたした。 タむプのリスト fas / type_list 、およびタむプに察するすべおの皮類の操䜜 fas / typemanip は、もちろんLokiです。 typemanipの倚くの構成䜓は、c ++ 11の<type_traits>の察応するものに眮き換えるこずができたす。 パッケヌゞfas / mp プレヌスホルダヌ匏ずラムダメタ関数およびfas / Integral 敎数型のラッパヌずそれらの操䜜のアむデアは、boost :: mplから取られおいたす。 STLアルゎリズムに䌌たメタアルゎリズムのむンタヌフェむスを䜜成しようずしたした。

敎数型から始めたしょう。 テンプレヌトを䜿甚する堎合、数字を䜿甚するのが垞に䟿利であるずは限りたせん;これらの目的には、次のような特別なラッパヌがより䟿利です。
 typedef fas::int_<2> level; 

このコンストラクトの定矩ず、fas / integralパッケヌゞの他の敎数型の定矩。 そこで、远加などの基本的な操䜜を芋぀けるこずができたす。
 std::cout << fas::int_<1>::value << std::endl; // 1 std::cout << fas::plus< fas::int_<1>, fas::int_<2> >::value << std::endl; // 3 

ここでは、コンパむル段階で最小公倍数を芋぀ける方法の䟋を調べるこずができたす 。

fas / typemanipパッケヌゞには、さたざたなデヌタ型を操䜜するための䞀連の構成䜓が含たれおいたす。 2぀の型が同じかどうかを刀断するには、same_typeが必芁です。
 std::cout << fas::same_type<int, long>::value; // 0 std::cout << fas::same_type<int, int>::value; // 1 

特定の䜍眮から型を取埗するための型ず関数のペアずタプル
 typedef fas::pair< fas::int_<1>, fas::int_<2> > pair; typedef fas::tuple< fas::int_<3>, fas::int_<4>, fas::int_<5> > tuple; std::cout << fas::first<pair>::type::value << std::endl; // 1 std::cout << fas::second<tuple>::type::value << std::endl; // 4 std::cout << fas::third<tuple>::type::value << std::endl; // 5 

タプルは最倧5぀のタむプを取るこずができたす。 さらに必芁な堎合は、タむプリストを䜿甚する方が䟿利です。 4番目ず5番目のタむプを取埗するための関数4番目ず5番目。

条件付き操䜜
 std::cout << fas::if_< fas::true_, fas::int_<42>, fas::int_<24> >::type::value << std::endl; // 42 std::cout << fas::switch_< fas::case_< fas::false_, fas::int_<24> >, fas::case_c< 1, fas::int_<42> >, fas::default_< fas::int_<44> > >::type::value << std::endl; // 42 

タむプのリスト。 抂念の詳现は説明せず、実装の機胜のみを瀺したす。 だから、基本的な構造
 struct empty_list { typedef metalist::empty_list metatype; }; template< typename L, typename R = empty_list > struct type_list { typedef metalist::type_list metatype; typedef L left_type; typedef R right_type; }; 

4぀のタむプのリスト
 typedef fas::type_list<A, fas::type_list<B, fas::type_list<C, fas::type_list<D > > > > list_abcd; // [A,B,C,D,empty_list] 

無効なリスト
 typedef fas::type_list<A, B > list2_ab_invalid; 

faslibでは、Lokiずは異なり、型のリストは垞に型fas :: empty_listで終わる必芁がありたす。 この芏則が順守されない堎合、そのようなリストは未線成ず呌ばれたす。 fas ::組織機胜は、たずえば次のような状況を修正するのに圹立ちたす。
 typedef fas::type_list< A, B > list_ab_invalid; // [A,B] typedef fas::type_list< C, D > list_cd_invalid; // [C,D] typedef fas::type_list< list_ab_invalid, list_cd_invalid> list_abcd_invalid; // [[C,D],[C,D]] typedef fas::organize<list2_abcd_invalid>::type list_abcd; // [A,B,C,D,empty_list] 

Alexandrescuず圌のフォロワヌが#defineを䜿甚しお型のリストを䜜成する理由を私は心から理解しおいたせん。
 typedef fas::type_list_n<A,B,C>::type list; // [A,B,C,empty_list] 

C ++ 11より前は、type_list_nは最倧26個のパラメヌタヌを受け入れたすが、その埌は制限されたせんさたざたなテンプレヌト。
型リストの詳现
type_list_nは、タむプリストの䜜成に加えお、fas :: organizeを䜿甚しおそれらを敎理できたす。たずえば、次のようにパラメヌタヌの数の制限を削陀したす。
 typedef fas::type_list_n< fas::type_list_n<A,B>::type, // [A,B,empty_list] fas::type_list_n<C,D>::type // [C,D,empty_list] >::type list; // [A,B,C,D,empty_list] 

faslibのタむプリストの次の優れた機胜は、次のような構造䜓でリストを゚スケヌプできるこずです。
 struct list_bc: fas::type_list<B, fas::type_list<C> > {}; // [B,C,empty_list] struct list_abc: fas::type_list<B, list_bc > {}; // [A,list_bc] 

タむプリストで動䜜するすべおの操䜜ずアルゎリズムは、シヌルドを怜出し、可胜であればそれらを再構築しないように蚭蚈されおいたす。 リストを組み合わせお説明したしょう
 typedef fas::merge< list_bc, // [B,C,empty_list] list_abc // [A,list_bc] >::type list; // [B,C,A,list_bc] 

この操䜜を簡単に実装するず、[B、C、A、B、C、empty_list]のリストが再構築されたす。 faslibでの実装はそれほど耇雑ではありたせんが、コンパむル時間の最適化ずリストの末尟をスクリヌニングするずきに゚ラヌが発生した堎合のログの実際的な削枛ずいう点で実質的な利益はありたせん。 ただし、次のように、゚スケヌプする機胜はリストの䜜成に圹立ちたす。
 template<int A, int B, int C> struct list123: fas::type_list_n< fas::int_<A>, fas::int_<B>, fas::int_<C> >::type {}; 

さらに、シヌルドされたリストは、テンプレヌトパラメヌタヌずしお任意のクラスに枡されるず、゚ラヌログを読みやすくしたす。
 #include <fas/integral.hpp> #include <fas/type_list.hpp> typedef fas::type_list_n< fas::int_<1>, fas::int_<2> , fas::int_<2> >::type list1; struct list2: list1 {}; template<typename L> class test {}; int main() { // test<list2> tst; test<list1> tst; tst.doit(); } 

このバヌゞョンでは、コンパむラは次のようなものを生成したす。
 error: 'class test<fas::type_list<fas::int_<1>, fas::type_list<fas::int_<2>, fas::type_list<fas::int_<2>, fas::empty_list> > > >' has no member named 'doit' 

およびlist2の堎合
 error: 'class test<list2>' has no member named 'doit' 

リストに12個以䞊のアむテムがある堎合、違いを感じるでしょう。 リストの長さを決定する関数を定矩する䟋を䜿甚しお、゚スケヌプの仕組みの秘密を明らかにしたしょう。 シヌルドなしの実装
 template<typename L, typename R> struct length; template<typename L, typename R> struct length< type_list<L, R> > { enum { value = 1 + length<R>::value }; }; template<> struct length< empty_list > { enum { value = 0 }; }; 

この実装では、シヌルドされたリストが長さ関数の入力に来るず、コンパむル段階で゚ラヌが発生したす。 型のリストを他の構造ず区別するために、構造fas :: type_listおよびfas :: empty_listで定矩されおいるマゞックメタタむプを䜿甚しお、さらに宣蚀したす
 template<typename L> struct length : length_impl<typename L::metatype, L> {}; template<typename L> struct length_impl<metalist::type_list, L> { typedef typename L::right_type tail; enum { value = 1 + length< tail>::value }; }; template<typename L> struct length_impl<metalist::empty_list, L> { enum { value = 0 }; }; 

぀たり、fas :: type_listたたはfas :: empty_listによる長さの特殊化が機胜しない堎合、入力パラメヌタヌで定矩されおいるメタタむプタむプに基づいた特殊化が必芁になりたす。 定矩されおいないか、型fas :: metalist :: type_listたたはfas :: metalist :: empty_listでない堎合、コンパむル゚ラヌが発生したす。 長さ<type_list <L、R >>および長さ<empty_list>の特殊化を削陀するず、コヌドは機胜したすが、コンパむルが遅くなりたす。 コンパむラヌこの堎合はg ++は、入力タむプを「オヌプン」せずに特殊化を実行するのがはるかに簡単です。

さらに、すべおの操䜜で入力タむプリストの有効性を確認できたす。 このオプションは、デフォルトでは無効になっおいたす。 コンパむル時間が長くなりたす。 型リストを詊しおみたい堎合は、FASLIB_TYPE_LIST_CHECKを有効にしお、CMakeLists.txtの行のコメントを倖すこずをお勧めしたす。

#add_definitions-DFASLIB_TYPE_LIST_CHECK

そこで、type_listによる操䜜ずアルゎリズムの特殊化を無効にしお、メタタむプによる特殊化のみを残し、コンパむル時間の芳点から効果を評䟡できたす。

#add_definitions-DDISABLE_TYPE_LIST_SPEC

さらに、コメントでは、タむプのリストを説明するずきに、簡朔にするためにempty_listを瀺しおいたせん。 正しいタむプリストのみを䜿甚したす。
type_list_nはどのように機胜したすか
わずかに簡玠化されたが機胜する実装
 template< typename T1 = empty_list, typename T2 = empty_list, typename T3 = empty_list, typename T4 = empty_list, typename T5 = empty_list, typename T6 = empty_list, typename T7 = empty_list, typename T8 = empty_list, typename T9 = empty_list, typename T10 = empty_list, typename T11 = empty_list, typename T12 = empty_list, typename T13 = empty_list, typename T14 = empty_list, typename T15 = empty_list, typename T16 = empty_list, typename T17 = empty_list, typename T18 = empty_list, typename T19 = empty_list, typename T20 = empty_list, typename T21 = empty_list, typename T22 = empty_list, typename T23 = empty_list, typename T24 = empty_list, typename T25 = empty_list, typename T26 = empty_list > struct type_list_n { typedef type_list< T1, type_list< T2, type_list< T3, type_list< T4, type_list< T5, type_list< T6, type_list< T7, type_list< T8, type_list< T9, type_list< T10, type_list< T11, type_list< T12, type_list< T13, type_list< T14, type_list< T15, type_list< T16, type_list< T17, type_list< T18, type_list< T19, type_list< T20, type_list< T21, type_list< T22, type_list< T23, type_list< T24, type_list< T25, type_list< T26 > > > > > > > > > > > > > > > > > > > > > > > > > > bar; typedef typename organize<bar>::type type; }; 

26個すべおのテンプレヌトパラメヌタヌから型のリストを䜜成したす。明瀺的に指定されたパラメヌタヌはリストの先頭にあり、リストの末尟はfas :: empty_listのセットで構成されたす-これはfaslibのコンテキストでの型の誀ったリストです。 fas :: organize操䜜は、䞍芁なfas :: empty_listを削陀し、その結果、必芁な芁玠数から型のリストを取埗したす。

C ++ 11のオプション
 template<typename Head = fas::empty_list, typename ...Args > struct type_list_n { typedef typename fas::organize< fas::type_list< Head, typename type_list_n<Args...>::type > >::type type; }; template<> struct type_list_n<> { typedef fas::empty_list type; }; 

たた、簡玠化された実装-fas :: organiseは、その圢成の各段階でリストに適甚されたす。 良い方法では、最初にリストを䜜成し、それを䞀床敎理する必芁がありたす。 パラメヌタfas :: type_list_nで型のリストを枡すには、fas :: organiseが必芁です。


タむプリストの操䜜


型リストを操䜜するために、型Lのリストに加えお、型Tを取り、むンデックスIが敎数型である操䜜のセットがありたす。 むンデックスを䜿甚する操䜜の堎合、接尟蟞_cの代替がありたす。この代替では、むンデックスは番号で指定されたす。たずえば、
 typedef fas::erase< fas::int_<0>, fas::type_list<char> >::type empty; typedef fas::erase_c< 0, fas::type_list<char> >::type empty; 

タむプリストで利甚可胜なすべおの操䜜のリスト

Source: https://habr.com/ru/post/J228367/


All Articles