2012-01-08 10 views
1

私はClojureを学ぼうとしています。私は子供のゲーム "シュートとはしご"の非常に基本的なモデルを作った。プレーヤーが100点以上のスコアを取得した場合、ゲームは終了します。 これはプレイヤーだけにしか機能しません。クロージャのルーピング/再帰

"(プレイプレーヤー1)"でゲームを開始します。

私は、それがマルチプレイヤーになることに固執しています。リキュールと "foreach"ステートメントを使用しないでください。
これをマルチプレーヤーに変更するにはどうすればよいですか?

(defn roll [] 
(+ 1 (rand-int 6))) 

(def chutes { 10 5, 12 3, 55 38, 77 69}) 
(def ladders { 12 16, 10 25, 20 55, 77 91}) 

(defn apply_chutes [player] 
(if (contains? chutes @player) 
    (do (reset! player (chutes @player)) 
     (println "down chute! " @player)))) 

(defn apply_ladders [player] 
(if (contains? ladders @player) 
    (do (reset! player (ladders @player)) 
    (println "up ladder! " @player)))) 

(defn move [player] 
(do(swap! player + (roll)) 
    (println "p: " @player) 
    (apply_chutes player) 
    (apply_ladders player) 
    player)) 
    (if 
("done"))) 

(defn play [player] 
(move player) 
(if (>= @player 100) 
    (println "done") 
    (play player))) 

(def player1 (atom 0)) 
+1

Clojure、再帰、またはゲームデザインについて質問していますか?あなたの質問を正確にし、正確な問題を記述してください。 – ffriend

+0

実際のゲームのデザインではありませんが、私は何らかのプログラミングのヒントを教えていただければ幸いです。私はこの作業を複数のプレイヤーにする方法を知りたいですが、最初のプレーヤーが100を破ると停止します。選手。私は、dosqや高次関数マップのようなものを使うべきだと思いますが、ゲーム終了時にどのようにプレイヤーのシーケンスを繰り返すのをやめますか?私は再帰を使用して、毎回別のプレイヤーの "再生"機能を呼び出す必要がありますか?それはいくつかの助けになるのか?私はそれが本当の具体的ではないことを知っている。 –

答えて

1

[OK]を、私は関数型プログラミングに関してやClojureの中の特定のループ/再帰に優れたハイレベルなデザインの完全なコードを提供しませんが。

関数プログラミングで非常に重要な概念、つまり不変性から始めましょう。機能プログラムは、システムの状態の変化を回避しようとします。 ではなくの状態を変更すると、プログラムはになり、新しい状態になります。たとえば、ベクターv1 = [1, 2, 3, 4]があり、最後に5を挿入する場合は、v1を破棄するのではなく、v2 = [1, 2, 3, 4, 5]v1)をそのまま変更しないでください。関数プログラミングにおける不変性の詳細については、this質問を参照してください。

このようにすると、ゲームの全体的な状態を保持する特別な変数stateを作成するのが最善の方法です。

次の事項はルーピングです。再び、関数プログラミングでは、ループの概念はほとんどの再帰に置き換えられます。ループと再帰は非常によく似ています。どちらも、終了する前にいくつかのコードを何度も繰り返すことができます。ほとんどの命令型プログラミング言語(Python、Javaなど)では、再帰がスタックの成長につながりますが、関数型言語では、末尾再帰という非常に一般的な概念があります。あなたがこのコンセプトに慣れていないなら、私はあなたにそれを学ぶことを強く勧めます。今のところ、末尾の再帰は末尾の位置(制御フローの最後のステートメント)でのみ発生する可能性があり、はスタックの成長につながりません。したがって、ループ構造として使用できます。 Clojureのの末尾再帰で

recurキーワードで構成されています。ここ

(defn play [state ...] 
    ... 
    (recur new-state ...)) 

は、我々はパラメータstateplay関数を定義し、我々はあまりにも(play new-state ...)としてそれを呼び出すことができます(最後の行でキーワードrecurで再帰的に呼び出し、この場合、JVMはコードをテール再帰的に最適化しません)。 は、関数本体のどこかで定義され、それが意味するもの、つまりゲームの新しい状態を正確に表します。

最後に、ゲームのマルチプレイヤーを作成します。つまり、各繰り返しの後に現在のプレーヤーを変更します。ループ/再帰で、それだけで簡単に選手を入れ替えることにより達成することができる。

(defn play [state current-player next-player] 
    ;; do play with current-player and compute new-state 
    (recur new-state next-player current-player)) 

お知らせ、そのRECURのコールプレイヤーは自分のポジションを入れ替えたので、次のプレーヤーはplayの新しいコールで現在のプレーヤーとその逆となりました。

これを持って、あなたは、新しいバージョンにあなたのコードを変換することができるはずです。

+0

応答に感謝します - それは意味があり、私はそれを試してみましょう。 –

+0

クロージュールで国家を管理する方法を再帰的に考えるのは自然なことではありません。 –

+0

@Taylor:今では、グローバル変数に「シュート」と「はしご」という状態があります。あなたがすべきことは、それらを '{:ladders ladders、:chutes chutes}'に入れ、この地図を州にアクセスする必要があるすべての機能に渡すことです。新しい状態を作るには '(新しい状態(assoc旧状態:シュート新しいシュート:はしごの新しいはしご)] ...)'のような何かをしてください。変数の1つを変更する関数を作成し、この変数を返すだけです。州や選手を取って新しい選手だけを返すように '適用ラダー 'を作ってください。あなたは 'vars'なしで終わるはずです。 – ffriend