2

ちょっとした学習演習として、Clojureでオーバーハンドシャッフルを実装しようとしています

だから私はこのコードを持っています...

(defn overhand [cards]
    (let [ card_count (count cards)
          _new_cards '()
         _rand_ceiling (if (> card_count 4) (int (* 0.2 card_count)) 1)]
      (take card_count
            (reduce into (mapcat
                           (fn [c]
                             (-> (inc (rand-int _rand_ceiling))
                                 (take cards)
                                 (cons _new_cards)))
                           cards)))))

それは私がやりたいことをするのに非常に近いです、しかしそれは最初の(ランダムな)N枚のカードを前面から繰り返し取り除いています、しかし私はそれがリストを通して進歩することを望みます...

として呼び出す

(overhand [1 2 3 4 5 6 7 8 9])

で終わる代わりに

(1 2 3 1 2 1 2 3 4)

で終わりたい

(7 8 9 5 6 1 2 3 4)

また、補足として、これはこの関数をインデント/整理するための本当に醜い方法のように感じますが、もっと明白な方法はありますか?

4

3 に答える 3

3

この関数は、リストのリストを作成し、それぞれを変換して、一緒に戻します。問題は、毎回同じものからプルして固定値に追加することです。基本的には毎回同じ操作を実行しているため、リストを進めずに出力を繰り返します。問題を別の方法で分類し、ランダムなサイズのチャンクの作成をそれらをつなぎ合わせることから分割すると、正しく機能させる方法を少し簡単に確認できます。

シーケンスを分割するいくつかの方法:

(defn random-partitions [cards]
  (let [card_count (count cards)
        rand_ceiling (if (> card_count 4) (inc (int (* 0.2 card_count))) 1)]
   (partition-by (ƒ [_](= 0 (rand-int rand_ceiling))) cards)))

パーティションを長さ4未満に保つ

(defn random-partitions [cards]
  (let [[h t] (split-at (inc (rand-int 4)) cards)]
    (when (not-empty h) (lazy-seq (cons h (random-partition t))))))

または、パーティションを元の質問のサイズに保つ

(defn random-partitions [cards]
  (let [card_count (count cards)
        rand_ceiling (if (> card_count 4) (inc (int (* 0.2 card_count))) 1)
        [h t] (split-at (inc (rand-int rand_ceiling)) cards)]
    (when (not-empty h) (lazy-seq (cons h (random-partition t))))))

(random-partitions [1 2 3 4 5 6 7 8 9 10])
((1 2 3 4) (5) (6 7 8 9) (10))

これは、lazy-seqを直接使用せずに記述することもできます。

(defn random-partitions [cards]
  (->> [[] cards]
       (iterate
        (ƒ [[h t]]
          (split-at (inc (rand-int 4)) t)))
       rest ;iterate returns its input as the first argument, drop it.
       (map first)
       (take-while not-empty)))

その後、これを1つのシーケンスに戻すことができます。

(reduce  into (random-partitions [1 2 3 4 5 6 7 8 9 10]))
(10 9 8 7 6 5 4 3 1 2)

引数を逆にすると、はるかに優れたシャッフルのように見えます

 (reduce #(into %2 %1) (random-partitions [1 2 3 4 5 6 7 8 9 10]))
(8 7 1 2 3 4 5 6 9 10)
于 2012-11-29T22:31:09.023 に答える
0

インデントの質問に答えると、関数をリファクタリングできます。たとえば、mapcatからラムダ式を取り出して定義し、mapcatの呼び出しでその名前を使用します。インデントを支援するだけでなく、mapcatがより明確になります。

たとえば、リファクタリングされた元のプログラムは次のとおりです。プログラムの問題は修正されていないことに注意してください。レイアウトを改善するためのリファクタリングの例を示しています。

(defn overhand [cards]
    (let [ card_count (count cards)
          _new_cards '()
         _rand_ceiling (if (> card_count 4) (int (* 0.2 card_count)) 1)]

        (defn f [c]
            (-> (inc (rand-int _rand_ceiling))
                (take cards)
                (cons _new_cards)))

        (take card_count (reduce into (mapcat f cards)))))

これらの原則を固定コードに適用できます。

複雑な式を単純に除外することで、多くのインデントの問題を解決できます。また、一般的に読みやすさにも役立ちます。

于 2012-11-30T13:50:16.347 に答える
0

関数を整理するためのより良い方法は、シャッフルアクションを、それを駆動する分割ポイントのランダムな選択から分離することです。次に、予測可能なスプリッターを使用してシャッフラーをテストできます。

シャッフルアクションは次のように表すことができます

(defn shuffle [deck splitter]
  (if (empty? deck)
    ()
    (let [[taken left] (split-at (splitter (count deck)) deck)]
      (concat (shuffle left splitter) taken))))

どこ

  • deckシャッフルされるシーケンスです
  • splitterdeckサイズを指定して、分割する場所を選択する関数です。

shuffleいくつかの簡単なものをテストできますsplitter

=> (shuffle (range 10) (constantly 3))
(9 6 7 8 3 4 5 0 1 2)
=> (shuffle (range 10) (constantly 2))
(8 9 6 7 4 5 2 3 0 1)
=> (shuffle (range 10) (constantly 1))
(9 8 7 6 5 4 3 2 1 0)

できます。

次に、分割点を選択する方法を見てみましょう。このようにあなたの選択を説明することができます_rand_ceiling

=> (map
     (fn [card_count] (if (> card_count 4) (int (* 0.2 card_count)) 1))
     (range 20))
(1 1 1 1 1 1 1 1 1 1 2 2 2 2 2 3 3 3 3 3)

これは、10枚未満のデッキから1枚か2枚のカードを取ることを意味します。ちなみに、関数を表現する簡単な方法は次のとおりです。

(fn [card_count] (max (quot card_count 5) 1))

したがって、スプリッター関数を次のように表すことができます

(fn [card_count] (inc (rand-int (max (quot card_count 5) 1))))

だから私たちが欲しいシャッフラーは

(defn overhand [deck]
  (let [splitter (fn [card_count] (inc (rand-int (max (quot card_count 5) 1))))]
    (shuffle deck splitter)))
于 2014-02-03T18:37:52.373 に答える