64行TCLリバース

habrには、 PythonSilverlightでゲームReversi(Othello)を書くことに関するトピックが既にあります。

Tcl / Tkで自転車を発明します。 クロスプラットフォーム(わずかな変更を加えたWindows Mobileでも動作)、わずか64行。



画像



コード、短い説明、およびhabrakatでのWinMobileの画面。





ソース(reversi.tcl):

パッケージにはTk 8.5が必要です
 for {set i 0} {$ i <64} {incr i} {lcellend icells [expr {$ i / 8}] [expr {$ i%8}]}
配列セットvs [リスト1 2 2 1 cl、1黒cl、2白pn、1黒pn、2白]
 ttk :: button .b1 -text "New game" -command {newgame 1 2}
 ttk :: button .b2 -text "Exit" -command {exit}
 ttk :: label .l1 -text「リバーシゲームへようこそ」
 canvas .cv -width 479 -height 479
グリッド行構成。  1ウェイト1
グリッド列の構成。  2-重み1
グリッド.b1 .b2 .l1 -padx 4 -pady 4 -sticky e
グリッド.cv -padx 4 -pady 4 -columnspan 3
 foreach {xy} $ icells {
   set cr1 [list [expr {$ x * 60 + 2}] [expr {$ y * 60 + 2}] [expr {$ x * 60 + 60}] [expr {$ y * 60 + 60}]]
   set cr2 [list [expr {$ x * 60 + 4}] [expr {$ y * 60 + 4}] [expr {$ x * 60 + 58}] [expr {$ y * 60 + 58}]]
   .cv createrectangle $ cr1 -fill gray -tag "cell、$ x、$ y"
   .cv create oval $ cr2 -state hidden -tag "piece $ x、$ y"
   .cv bind cell、$ x、$ y <1> [list evuser $ x $ y]}
 proc pieceset {xyp} {
   .cv itemconfigure $ x、$ y -state normal -fill $ :: vs(cl、$ p)
   incr ::スコア($ p)[expr {+($ :: board($ x、$ y)!= $ p)}]
   incr ::スコア($ :: vs($ p))[expr {-($ :: board($ x、$ y)== $ :: vs($ p))}]
  セット::ボード($ x、$ y)[リスト$ p]}
 proc newgame {p1 p2} {
   .cv itemconfigure piece-state hidden
  配列セット::スコア[リスト0 0 1 0 2 0]
  配列セット::プレーヤー[リスト1 $ p1 2 $ p2]
   foreach {xy} $ :: icells {set :: board($ x、$ y)0}
   foreach {xys} {3 3 2 4 4 2 3 4 1 4 3 1} {pieceset $ x $ y $ s}
   set :: cur 1;  waitturn}
 proc getflips {xyp} {
   if {$ :: board($ x、$ y)!= 0} return;
  設定結果{}
   foreach {ix iy} {0 -1 0 1 -1 0 1 0 -1 -1 1 1 1 -1 -1 -1 1} {
    設定温度{}
     for {set i [expr {$ x + $ ix}];  set j [expr {$ y + $ iy}]} \
         {[info exists :: board($ i、$ j)]}} {incr i $ ix;  incr j $ iy} {
        スイッチ-$ ::ボード($ i、$ j)\
           $ :: vs($ p){lappend temp $ i $ j} \
           $ p {foreach {mn} $ temp {lappend result $ m $ n}; 休憩} \
           0 {break}
   }}
   return $ result}
 proc waitturn {} {
   .l1 configure -text "Going $ :: vs(pn、$ :: cur)($ ::スコア(1):$ ::スコア(2))"
  配列セットv [list $ :: cur {} $ :: vs($ :: cur){}]  
   foreach {xy} $ :: icells {
     set l [getflips $ x $ y $ :: cur];  if {[llength $ l]} {lappend v($ :: cur)[list $ x $ y]}
     set l [getflips $ x $ y $ :: vs($ :: cur)];  if {[llength $ l]} {lappend v($ :: vs($ :: cur))[list $ x $ y]}}
   if {[llength $ v($ :: cur)] == 0 && [llength $ v($ :: vs($ :: cur))] == 0} {
     tk_messageBox -title "Reversi" -message "Game over"; 戻る}
   if {$ :: player($ :: cur)== 1 && [llength $ v($ :: cur)]} {
     set :: waituser 1; 戻る}
   if {$ :: player($ :: cur)== 2 && [llength $ v($ :: cur)]} {
    セット:: waituser 0
     set :: flip [lindex $ v($ :: cur)[expr {int([llength $ v($ :: cur)] * rand())}]]
     turn [lindex $ :: flip 0] [lindex $ :: flip 1] $ :: cur}
   set :: cur $ :: vs($ :: cur); アイドル待機後
 proc evuser {xy} {
   if {[info exists :: waituser] && $ :: waituser && [turn $ x $ y $ :: cur]} {
     set :: cur $ :: vs($ :: cur); アイドル待機後}}
 proc turn {xyp} {
  フリップの設定[getflips $ x $ y $ p]
   foreach {ij} $ flips {pieceset $ i $ j $ p}
   if {[llength $ flips]} {pieceset $ x $ y $ p;  return 1} else {return 0}}




座標を操作しやすくするために、icellsリスト(0 0 0 1 ... 1 1 1 2 ..)を作成します。

将来、ネストされたループの代わりに、 foreach {xy} $ icellsを使用できます。



次はインターフェイスの作成です。セルをクリックすると、キャンバスとイベントバインディング(evuser)が機能します。



グローバル変数:

vs-ハッシュ配列。対戦相手のID、チップの色を決定します。 vs(1)= 2; vs(2)= 1

スコア-スコア(白黒チップの数)

プレーヤー-プレーヤーの構成(1-人、2-コンピューター)

ボード-競技場

cur-現在のプレーヤー識別子

waituser-ユーザーの進行を待つためのフラグ



宣言された関数を検討してください。

newgame {p1 p2}

新しいゲームの始まり。 引数はプレーヤーのタイプを決定します:

1-男

2-コンピューター



他の問題では、ここにはAIがまったくありませんが、{2 2}を渡すことでランダムvsランダムがどのようにプレイするかを見ることができます



ピースセット{xyp}

セルx、yにプレーヤーpトークンを設定します

現在のアカウントを再計算します。 ここにちょっとした魔法があります

 incr ::スコア($ p)[expr {+($ :: board($ x、$ y)!= $ p)}]
 incr ::スコア($ :: vs($ p))[expr {-($ ::ボード($ x、$ y)== $ :: vs($ p))}]。




現在のプレイヤーpのスコアを増やし、相手の$ vs($ p)

現在のプレーヤーの場合、チップがまだケージに入れられていない場合は+1、そうでなければ+0

相手のチップが価値があった場合、彼はスコアを-1減らします。



getflips {xyp}

プレーヤー( p )がxyに移動してキャプチャできるすべての可能なチップのリストを返します



waitturn {}

移動を待っています。

各プレーヤーのすべての可能な動きの数を定義します。 ゲームがいつ終了し、誰が今すぐ行動を起こすべきかを決定します。



evuser {xy}

この手順は、人がセルの1つをクリックするたびに呼び出されます。

グローバル変数:: waituserが設定されていて、現在のユーザーに移動する機会がある場合、制御を対戦相手に転送します。

set :: cur $ :: vs($ :: cur); アイドル待機後}}



{xyp}を回す

x yで移動します。 キャプチャした敵チップを裏返し、成功した場合は1、それ以外の場合は0を返します。



参照:

ウィキペディアのリバーシ

ActiveTcl(Windows / OSX / LinuxのTclディストリビューション)

eTcl(Windows Mobile)





そして最後に、Windows Mobileの画面

画像



UPD:

Ubuntuのスクリーンショット 。 確かに、通常のビューに戻すには、 tile-gtkモジュールを接続しました



Googleコード

Windows用のStarkitとビルド(1.2 mb)




All Articles