0

Rubyで絞首刑執行人のアプリケーションを構築するチュートリアルをフォローしています。ファイルからインポートされた国名である単語を非表示にするマスカレード機能があります。問題は、これが実際にどのように単語を偽装しているのか、または三項演算子がどのように注入で機能しているのかを理解していないことです。文字が空白(つまり "")であるかどうかをチェックし、空白である場合(つまり "")に設定しますが、空白でない場合は&nbspになります。この関数は、単語に実際の文字、つまり文字が含まれているという事実を処理していないようです。

誰かがこの種の初心者について説明できますか、私が誤解していることは何ですか?また、なぜ最後に(閉じる前に}'変装'を再び追加するのですか?

def masquerade(word)

      word.each_char.inject([]) { |disguise, char| disguise << (char == " " ? " " : "&nbsp;"); disguise }

end

ゲームワードの例

Afghanistan
Albania
Algeria
Andorra
Angola
Antigua & Deps
Argentina
Armenia

Wordクラス全体

class Word

  class << self
    def get_random
      content = File.read("countries.txt")
      words = content.split("\n")
      words[rand(words.size)].upcase
    end

    def masquerade(word)
      word.each_char.inject([]) { |disguise, char| disguise << (char == " " ? " " : "&nbsp;"); disguise }
    end

    def reveal(last_revealed_word, char_clicked, final_word)
      chars = final_word.each_char.to_a

      last_revealed_word.each_index do |i|
        last_revealed_word[i] = chars[i] if last_revealed_word[i] == "&nbsp;" and chars[i] == char_clicked
      end
    end

    def chars_left(revealed_word)
      revealed_word.count { |c| c == "&nbsp;" }
    end

  end

end
4

2 に答える 2

1

単語='アルバニア'と仮定しましょう。word.each_charは、Enumerableオブジェクトを返します。ここで、各「アイテム」は単語内の文字です。

#injectではなく#eachを使用することを想像してみてください

word.each_char.each { |letter| puts letter }
A
l
b
...

#injectは、列挙可能なすべてのアイテムを取得し、それらを何らかの方法で組み合わせるためのものです。この場合、それらが結合されているのは配列です。空の配列が.inject([])の引数としてinjectに渡されているため、これがわかります。inject(Array.new)である可能性もあります。渡されたものは何でも、インジェクトの「メモ」のデフォルト値になります。これは、アイテムを通過するときに最終結果を追跡するために使用するオブジェクトです。この場合、そのメモオブジェクトは変装と呼ばれます。

インジェクトループ中に、変装メモは1つの反復から次の反復に持ち越されます。各反復は、injectが呼び出された列挙型の項目(文字)の1つを処理します。ブロック内では、そのアイテムはcharと呼ばれます。

ブロックが返すものはすべて、注入の次の反復のメモ(偽装)の新しい値になります。

したがって、ここでは、最初の反復にはdisguise=[]とchar='A'が含まれます。if / elseは、「charが単一のスペースの場合は、変装配列に単一のスペースを追加します。それ以外の場合は、変装配列に改行しないスペースを追加します。

Array#push()(<<がここで行っていること)の結果は、新しいアイテムがプッシュされた後の配列です。したがって、[1,2] .push(3)がある場合は、[1,2,3]が返されます。このインジェクトの場合、プッシュオーバーの結果を次の反復に持ち越したいので、基本的に、配列が変装してブロックが返すものであることを確認します。最後に。今のところ、必要ありません。プッシュとブロックの終わりの間に他の操作が発生した場合は、変装配列を明示的に返す必要があります。そうでない場合、2番目の操作の結果がメモに保存されます。

if / elseが単語の文字をどのように処理するかについては、基本的に、文字であるときはいつでも&nbsp文字列に入れます。

したがって、その最初の反復では、char ='A'は単一のスペースではないため、nbspは空の配列にプッシュされ、その配列["&nbsp"]がブロックによって返されます。変装は["&nbsp"]に等しくなります。2回目の反復では、char ='l'であり、スペースではないため、別の&nbspが配列にプッシュされ、["&nbsp"、 "&nbsp"]になります。これは、3回目の反復でのブロックと変装の値の結果です。

インジェクトはすべての文字に対してそのように続行され、その後、変装の最終値を返します。

ほとんどの場合、これは["&nbsp"、 "&nbsp"、 "&nbsp"など]になります。または、国名にスペースが含まれている場合は、["&nbsp"、 ""、&nbsp "、"&nbsp "、 ""など]。結果の配列がビューでどのように使用されているか、または何らかの方法でユーザーに提示されているかを確認しないと、そのポイントが何であるかを判断するのは困難です。

  • ;を削除しました nbspから表示されるようにします。
于 2012-10-02T20:54:48.157 に答える
1

最後に追加するdisguise必要はありません。は<<すでにオブジェクトを変更しています。

違いはわかりません。

[1] pry(main)> "wor d".each_char.inject([]) { |d, c| d << ( c == " " ? " " : "&nbsp;"); d }
=> ["&nbsp;", "&nbsp;", "&nbsp;", " ", "&nbsp;"]

[2] pry(main)> "wor d".each_char.inject([]) { |d, c| d << ( c == " " ? " " : "&nbsp;") }
=> ["&nbsp;", "&nbsp;", "&nbsp;", " ", "&nbsp;"]

upd:ここでのマスキングは、文字を改行しないスペースに置き換えることです

于 2012-10-02T20:31:43.840 に答える