配電盤のブルートフォース


32

先日、私たちのチームは脱出室に行きました。パズルの1つには、6つの機械式スイッチのボードが含まれており、ボックスのロックを解除するには、次のような正しいオンとオフの組み合わせを見つける必要がありました。

-v-v-v-
-v-v-v-

開発者である私たちは、実際にパズルを解くよりも2 ^ 6 = 64の組み合わせを1つずつ試す方が効率的だと判断しました。そこで、貧しい人にバイナリカウントを割り当てました。

-v-v-v-
-v-v-v-

-v-v-v-
-v-v-^-

-v-v-v-
-v-^-v-

-v-v-v-
-v-^-^-

等々。

課題は
、上記のようにフォーマットされた文字列として位置オフのスイッチ全てが与えられると、そのプログラムを書いて、任意の順序でオンとオフのすべての組み合わせを生成します。

完全なプログラムまたは関数のいずれかを作成できます。したがって、プログラムは、stdin、ファイルを介して、または単一の文字列引数として入力を受け取り、出力を返すか印刷することができます。返される場合、出力はlist / array / etcにある可能性があります。単一の文字列ではなく。出力が単一の文字列の場合、ボードは改行で区切る必要があります(末尾の改行は許可されます)。

入力文字列は正規表現r'((-v)+-)(\n(-v)+-)*'と一致し、すべてのスイッチがオフになっている1つのボードを表します。これは、ゼロケースがないことを意味し、スイッチは左揃えです。各行には同じ数のスイッチがない場合があります。

各出力ボードは、入力とまったく同じ形式である必要がありますが、必要に応じてvを^に置き換えることができます。出力ボードは、任意の数の改行で区切ることができます。

ランタイムは当然、スイッチの数がO(2 ^ n)であるため、コードはどのような配置でも10を超えるスイッチではテストされません。

これはコードゴルフなので、バイト数の最も短いコードが優先されます。

サンプルの入力と出力

入力:

-v-

可能な出力:

-v-
-^-

入力:

-v-
-v-

可能な出力:

-^-
-^-
-^-
-v-

-v-
-^-


-v-
-v-

多数のスイッチについて回答を確認するのは非常に面倒なので、ここでは健全性チェックツールとしてのPythonスクリプトを示します。(テストケースをさらに増やしたい場合に備えて、特定の入力ファイルから期待される出力を生成するために、現在コメントアウトされたスニペットを含めました。)入力文字列を「input」という名前のファイルに入れ、改行で区切られた出力(申し訳ありませんが、リストのフォーマットはありません)は同じディレクトリの「output」という名前のファイルに入れて実行しpython3 sanitycheck.pyます。


8
素敵な最初の挑戦!
ジュゼッペ

12
うまくいけば、「貧しい男」はグレイコードを知っていて、各組み合わせの間で1ビットだけを反転させることができました。
エリックドゥミニル

1
時間は私たちの最も貴重な資産です。無駄に無駄にしないでください。
ペドロロビト

6
テーマを考えると、トグルの最小量を必要とする注文を必要としなかったことに失望しています(たとえば、00-> 01-> 11-> 10には3つのトグルがあり、00-> 01-> 10-> 11には4があります) )-仲間のブルートフォースエスケープャー
池上

2
@EricDuminil:メカニカルスイッチがボタンではない場合(そして場合でも)、1つ、2つ、3つの連続したスイッチ(おそらくほぼ同時に行うことができる)を切り替える間に必要な時間の差は、おそらく十分ではありませんグレイコードに従うために余分な精神的な仕事を相殺する。
tomasz

回答:


23

Haskell25 24 23 17バイト

mapM$min"^v".pure

オンラインでお試しください!

@ H.PWizのおかげで-1バイト

@nimiのおかげで-1バイト

文字列のリストを返します。TIOには、関数宣言用に2バイトの余分なバイトがあります。他の人が関数をポイントフリーで記述するときに、それをそのままにしておくのを見たことがあります。

前の回答(25バイト)

g 'v'="v^"
g x=[x]
mapM g

説明はすべて前の回答に対するものであり、私はの定義をインライン化したことを除いて、ほとんど同じように機能しgます。g現在の動作方法は、字句比較を使用^vしてv、他のすべてを同じものに置き換えて維持することです。

興味深いことに、これは任意の配電盤で機能します。

>>> mapM g "-----^-----"
  ["-----v-----", "-----^-----"]

説明(短い)

g 'v'="v^" -- for 'v', choose between 'v' or '^'
g x=[x]    -- for any other character, choose just that character
mapM g     -- find all ways to choose characters using g on the given input

説明(長い)

mapMHaskellに慣れていない人にとってはかなり怖い関数です。しかし、この文脈で理解することは難しくありません。それをStrings(Haskellでは文字のリスト)に作用させることで、リストの定義に特化しました。したがって、このコンテキストでは、そのタイプシグネチャは

mapM :: (a -> [b]) -> [a] -> [[b]]
--      ^^^^^^^^^^                  arg 1: a function from any a to a list of b
--                    ^^^           arg 2: a list of a
--                           ^^^^^ return: a list of list of b

それは実際、それの私の使用法にさらに特化されています- aそしてb両方ですChar-したがって、型シグネチャを次のように見ることができます

mapM :: (Char -> String) -> String -> [String]

gどのようにmapM機能するかを説明する前に、何を行うかを簡単に見てみましょう。

g :: Char -> String
g 'v' = "v^"
g  x  = [x]

gパターンマッチングを使用Char 'v'してを文字列に変換します"v^"。それ以外はすべてシングルトン文字列に変換されます(文字列はCharsのリストにすぎないためx、シングルトンリストに入れることができます)。REPLでテストすると、これが事実であることがわかります

>>> g 'a'
  "a"
>>> g 'b'
  "b"
>>> g 'v'
  "v^"

gは、mapM(当然のことながら!)の引数となる正しい型を持っていることに注意してください。

mapMそれとg引数を与えることによってどのように機能するかを探ります

"-v-\n-v-"

入力として。

mapM最初のマップgの上にString、そしてのでg変換CharSにはStrings、これは私たちのリストを与えますStrings

["-", "v^", "-", "\n", "-", "v^", "-"]

これは正しい出力タイプですが、mapMやや多くのことが行われます。Stringこのリストからそれぞれ1つの文字をString(順番に)選択する必要がある場合、このリストから作成できるすべてのを形成すると考えることができます。

したがって、最初の要素については、を選択する以外に選択肢はありませんChar '-'。第二の要素のために、あなたがから選ぶことができます'v'し、'^'上のように、など、。

これは、次のPythonコードとほぼ同等です。

result = []
for x1 in "-":
  for x2 in "v^":
    for x3 in "-":
      ...
        result.append(''.join([x1, x2, x3, x4, x5, x6, x7]))

HaskellはCharsとStringsを分離するので、Charsをリストに入れるとき、joinそれらは必要ありません。

最終出力は

["-v-\n-v-", "-v-\n-^", "-^-\n-v-", "-^-\n-^-"]

望んだ通りに。


ああ、私は純粋に機能的な答えを待っていました。これは、それがいかに簡潔であったかを本当に驚かせました。
リンのフーリエ変換

2
Rin'sFouriertransform私はどのようにきれいにして喜んでいた@ mapMこの挑戦のために働いて、最初に私にそれがとして処方されていたsequence . map gが、それはのようにコンパクトに表現することができmapM id . map g、その後、私はちょうど私ができる見たmapM g
コール

1
私はあなたが交換することができると思う=='v'のために>'-'
H.PWiz

9

Perl 6、32バイト

{[X~] .comb».&{$_,('^'if /v/)}}

オンラインでお試しください!

  • .comb 文字列を文字に分割します。
  • ».&{...} 中括弧間の関数に従って文字をマッピングします。
  • $_, ('^' if /v/)各文字の代替のリストを生成します。v代替のみがあります^
  • [X~]文字列連結のクロス積演算子でそのリストを縮小しますX~

9

ゼリー、7バイト

«Ƭ€”^Œp

オンラインでお試しください!

出力は、Jelly文字列のリストです。

説明:

«Ƭ€”^Œp  Arguments: 1
«Ƭ€”^    Dyad-nilad pair
  €       Map over left argument
 Ƭ         Apply repeatedly until a result that has previously been seen is seen
           again, return original and intermediate results
«           Dyad: Minimum of arguments
   ”^     Nilad: Literal: '^'
         Note: 'v' is the only character that is greater than '^' and can
         appear in the input, so, while for every character c other than 'v'
         this operation returns [c], for 'v' it returns ['v', '^']. In this way,
         duplicates are never going to appear in the output.
     Œp  Monad: Cartesian product of elements

私は実際にJellyコードページをスクランブルして、ほとんどの場合、最初の答えが他のすべての答えを絶えず追い出していることを理解しようとしました...これがどのように機能するのか説明してくれますか?
リンのフーリエ変換

@ Rin'sFouriertransform説明を追加しました。
エリック・ザ・アウトゴルファー

6

Perl 5、29バイト

sub{glob"\Q@_"=~s/v/{v,^}/gr}

オンラインでお試しください!

私の最初の提出!


通常、Perl 5のゴルファーは、関数の代わりにプログラムを送信sub{}して、少なくとも含める必要がないようにします。しかし、彼らは追加する必要がありsaysay␠say forまたはsay for␠交換で。

サブアプローチに進むことで、短縮できます

say for glob"\Q$_"=~s/v/{v,^}/gr        # Perl 5, -0n, 32 bytes

sub{glob"\Q@_"=~s/v/{v,^}/gr}           # Perl 5, 29 bytes

説明は非常に簡単です。Perl 5には、globファイル名のリスト(例foo*.txt)または文字列のリスト(例)の生成に使用できるシェルのようなグロブパターンを受け入れる組み込み演算子があります{a,b,c}。キャッチは、改行をエスケープする必要があることです。これはquotemeta(as \Q)を使用して行いました。



4

APL(Dyalog Classic)21 17 15バイト

⊃⊢∘.,.∪'v'r'^'

オンラインでお試しください!

私のkソリューションに似ています

文字列のn次元配列を返します(n =スイッチの数)

説明しやすい形式で: ⊃(∘.,⌿ ⊢ ∪¨ 'v'⎕r'^')

'v'⎕r'^'vsを^sに置き換えます

⊢ ∪¨...元の各文字との結合。長さ1または2の文字列のベクトルです

∘.,⌿ デカルト積の削減

開示する

完全にゴルフされたバージョンを取得するには、パターンに従ってくださいf⌿ A g¨ B-> A f.g B

∘.,⌿ ⊢ ∪¨ 'v'⎕r'^' -> ⊢ ∘.,.∪ 'v'⎕r'^'

副作用として、括弧は不要になりました


外積と内積のあるものはすべて+1に値します。
アダム

3

J、42バイト

]`('v'I.@e.~[)`[}"1'v^'{~2#:@i.@^1#.e.&'v'

オンラインでお試しください!

説明

]`('v' I.@e.~ [)`[}"1 ('v^' {~ 2 #:@i.@^ 1 #. e.&'v')

取りましょう

-v-
-v-

入力例として。

  • ('v^' {~ 2 #:@i.@^ 1 #. e.&'v')入力形式を無視して、スイッチのみのすべての可能なコンボを作成します。この例では、以下を生成します。

    vv
    v^
    ^v
    ^^
    
    • 1 #. e.&'v'v入力内のs の数をカウントします。
    • 2 #:@i.@^、その電力に2を上昇させ、0から整数を生成し、そのi.、およびバイナリに変換#:
    • 'v^' {~進数への変更vと、^
  • ]`('v' I.@e.~ [)`[}"1元の入力を修正し、前の手順で説明した結果の各行に対して1つのコピーを生成します(つまり、すべての可能なv/ ^コンボ)。各コピーvで、元の入力のはv/の可能な1つのシーケンスに置き換えられ^ます。

3

Java、202 197 189 191バイト

はい、それは比較的冗長な言語ですが、それは私が古典的なゴルフとして考えるものです:

import java.util.function.Function;

public class SwitchBored
{
    public static void main(String[] args)
    {
        Function<String, String> f = s->{byte i,j,k,m=1,u='^',d='v',a[]=(s+"\n\n").getBytes();for(i=0,s="";i<m;i++,s+=new String(a))for(j=0,k=0;k<a.length;k++){if(a[k]==d||a[k]==u){a[k]=(i&1<<j++)!=0?u:d;m<<=i>0?0:1;}}return s;};

        //System.out.println(f.apply("-v-"));
        System.out.println(f.apply("-v-v-v-\n-v-v-v-"));
        //System.out.println(f.apply("-v-v-v-\n-v-v-"));
        //System.out.println(f.apply("-v-v-v-v-v-\n-v-"));
        //System.out.println(f.apply("-v-v-v-v-v-\n-v-v-v-v-v-"));
    }
}

適切なレイアウトを実現するために必要な改行を処理する「単純な」方法は、元の入力文字配列を実際に再利用し、適切な位置で'v'sと'^'s だけを埋めることだと思いました。

更新:

位置を保存しないintと、配列変数の宣言を捨てることができ、配列の各位置にオンザフライvまたは^オンザフライが含まれているかどうかをチェックするコストがかかります)、5バイト節約できます。

上限を(1<<numberOfSwitches)よりコンパクトに計算することにより、さらに8バイト節約できます。

コメントで言及されたルールによると、関数宣言はカウントされるべきであるため、今ではラムダです...


2
String generate(String s) {...}バイトカウントに関数定義()を含める必要があると確信しています。191バイトのfixed / lambdaバージョンを次に示します。私はいくつかのマイナーなゴルフをして3バイトを削りました
Benjamin Urquhart

@BenjaminUrquhart OK、これは私がよく知らない「ルール」の詳細です(ここで定期的にゴルフをしているわけではありません)。私は実際にあると考え{ function body }、それは問題であなたがある機能の中にそれを置くかどうかしないため、関連するべきであるstaticかどうか、そしてもちろん、場合、スコアに向けた宣言カウント、1は、ラムダ式に変換することができます。しかし、これが今行われていることです。これを指摘してくれてありがとう。
Marco13

1
いくつかの提案:1 d=94. chars()ではなくascii-codesを使用します。2. i宣言したら初期化します。3. i++<m個別の増分の代わりに使用します(ループの内容を1か所で変更する必要がありますが、これによりコストは追加されません)。4.逃げることができます(i&1<<j++)>0か?5. {}内側のforループには必要ないと思います。6.あなたが交換することができるa[k]==d||a[k]==ua[k]>45、私は思います。7.に進みj=k=0ます。これで19バイトが削除されます。
VisualMelon

@VisualMelonこれらのいくつかは「古典的なゴルフ」アプローチであり、私はすでにそれらのいくつかを適用しました。それらが適用可能かどうかは依存します-いくつか{}は必要だと思いますが、別の見方をすることができます。a[k]>45しかし、巧妙なトリックかもしれません。確かに、私は会議の開始を待つ時間を無駄にするためにこれを書いただけです(クラス名-これは意図的なものでした;-))
Marco13

@ Marco13確かに、それらは古典的なトリックですが、すべてここで具体的に適用できます。私はそれらに基づいて172バイトのソリューションをあなたに与えることによって楽しみを台無しにしません(ところで、あなたのものは192ではなく、191であると思いますが、ラムダカウントがどのように機能するのか分かりません:私はいずれにしてもそれに反対です)。
VisualMelon

3

J41 40 24バイト

[:>@,@{<@(,'^'$~'v'=])"0

オンラインでお試しください!


非常に印象的。の使用が大好きです{。ただし[:>@,@{<@(,'^'$~'v'=])"0、「各出力ボードは入力とまったく同じ形式である必要があり」、入力はボックス化されていないため、少し公平になると思います。
ジョナ

@ジョナありがとう。修正しました。
ngn





2

K4、44バイト

溶液:

-1{@[x;&w;:;]@'"v^"@a\:'!*/a:(+/w:"v"=x)#2};

例:

q)k)-1{@[x;&w;:;]@'"v^"@a\:'!*/a:(+/w:"v"=x)#2}"-v-";
-v-
-^-

q)k)-1{@[x;&w;:;]@'"v^"@a\:'!*/a:(+/w:"v"=x)#2}"-v-\n-v-";
-v-
-v-
-v-
-^-
-^-
-v-
-^-
-^-

q)k)-1{@[x;&w;:;]@/:"v^"@a\:'!*/a:(+/w:"v"=x)#2}"-v-v-\n-v-v-v-\n-v-";
-v-v-
-v-v-v-
-v-
-v-v-
-v-v-v-
-^-
-v-v-
-v-v-^-
-v-
-v-v-
-v-v-^-
-^-
-v-v-
-v-^-v-
-v-
-v-v-
-v-^-v-
-^-
-v-v-
-v-^-^-
-v-
-v-v-
-v-^-^-
-^-
-v-v-
-^-v-v-
-v-
-v-v-
-^-v-v-
-^-
-v-v-
-^-v-^-
-v-
-v-v-
-^-v-^-
-^-
-v-v-
-^-^-v-
-v-
-v-v-
-^-^-v-
-^-
-v-v-
-^-^-^-
-v-
-v-v-
-^-^-^-
-^-
-v-^-
-v-v-v-
-v-
-v-^-
-v-v-v-
-^-
-v-^-
-v-v-^-
-v-
-v-^-
-v-v-^-
-^-
-v-^-
-v-^-v-
-v-
-v-^-
-v-^-v-
-^-
-v-^-
-v-^-^-
-v-
-v-^-
-v-^-^-
-^-
-v-^-
-^-v-v-
-v-
-v-^-
-^-v-v-
-^-
-v-^-
-^-v-^-
-v-
-v-^-
-^-v-^-
-^-
-v-^-
-^-^-v-
-v-
-v-^-
-^-^-v-
-^-
-v-^-
-^-^-^-
-v-
-v-^-
-^-^-^-
-^-
-^-v-
-v-v-v-
-v-
-^-v-
-v-v-v-
-^-
-^-v-
-v-v-^-
-v-
-^-v-
-v-v-^-
-^-
-^-v-
-v-^-v-
-v-
-^-v-
-v-^-v-
-^-
-^-v-
-v-^-^-
-v-
-^-v-
-v-^-^-
-^-
-^-v-
-^-v-v-
-v-
-^-v-
-^-v-v-
-^-
-^-v-
-^-v-^-
-v-
-^-v-
-^-v-^-
-^-
-^-v-
-^-^-v-
-v-
-^-v-
-^-^-v-
-^-
-^-v-
-^-^-^-
-v-
-^-v-
-^-^-^-
-^-
-^-^-
-v-v-v-
-v-
-^-^-
-v-v-v-
-^-
-^-^-
-v-v-^-
-v-
-^-^-
-v-v-^-
-^-
-^-^-
-v-^-v-
-v-
-^-^-
-v-^-v-
-^-
-^-^-
-v-^-^-
-v-
-^-^-
-v-^-^-
-^-
-^-^-
-^-v-v-
-v-
-^-^-
-^-v-v-
-^-
-^-^-
-^-v-^-
-v-
-^-^-
-^-v-^-
-^-
-^-^-
-^-^-v-
-v-
-^-^-
-^-^-v-
-^-
-^-^-
-^-^-^-
-v-
-^-^-
-^-^-^-
-^-

説明:

のインプレース置換"^"。スイッチの組み合わせの数(2 ^ nなど)の決定、バイナリでのカウントアップ、スイッチの交換...

-1{@[x;&w;:;]@'"v^"@a\:'!*/a:(+/w:"v"=x)#2}; / the solution
-1                                         ; / print to STDOUT, swallow -1
  {                                       }  / lambda taking implicit x
                                        #2   / take 2
                             (         )     / do this together
                                  "v"=x      / does input = "v" ?
                                w:           / save as w
                              +/             / sum up
                           a:                / save as a
                         */                  / product
                        !                    / range 0..n
                    a\:'                     / convert each to base-2
               "v^"@                         / index into "v^"
             @'                              / apply each
   @[x;&w;:;]                                / apply assignment to x at indexes where w is true

2

R、116バイト

function(x,u=utf8ToInt(x))apply(expand.grid(rep(list(c(118,94)),sum(u>45))),1,function(i)intToUtf8(`[<-`(u,u>45,i)))

オンラインでお試しください!

改行で区切られたボードのベクトルを返す関数


ああ、私は非常に難しい方法で入力を取得することに集中していたので、この方法の容易さを無視しました。の素敵な使用"[<-"
ジュゼッペ

@ジュゼッペ:私はこのソリューションにあまり満足していません...しかし、私は他の方法で組み合わせを生成しようとしました(たとえばバイナリ変換を使用)が、これは最短になりました。
digEmAll


1

Retina 0.8.2、29バイト

T`¶v`;#
+%1`#
v$'¶$`^
%`;|$
¶

オンラインでお試しください!説明:

T`¶v`;#

改行を;sに、vsを#マーカーに変更します。

+%1`#

#sを左から右に1つずつ交換します。

v$'¶$`^

各行を2行に変更します。1行#をa vに置き換え、1行をa に置き換え^ます。

%`;|$
¶

変更は、;結果離れて戻って改行やスペースにね。




1

Python 3-構成、203バイト

def f(a):
 b=[0]
 for l in a.split():b+=[b[-1]+l.count('v')]
 return'\n'.join(''.join(f"{k:b}".zfill(b[-1])[x:y]+'-\n'for x,y in zip(b,b[1:]))for k in range(2**b[-1])).replace('0','-v').replace('1','-^')

オンラインでお試しください!

最初に試してみてください。あまり小さくはありませんが機能します。Pythonにはエレガントな文字列の置換はありません...

最初のループは、行のビットインデックスへのマッピングを構築します。つまり、各行について、ビットカウンタの最初のビットのインデックスが格納されます。これは、次のループでビットカウンターにインデックスを付けるために使用されます。

2番目のループはバイナリカウンターを実行し、各行と反復のビットを抽出して結合します。すべてを結合した後、文字列置換を使用してスイッチマップ形式に変換されます。

入力文字列を何度も再構築するのではなく、再利用するよりエレガントな方法があると思います。

編集:Python 3.8の回答に触発され、ここでははるかに短い置換バージョンです

Python 3-置換、123バイト

def f(a):r=range;n=a.count('v');return'\n'.join(a.replace('v','{}').format(*('v^'[k&2**i>0]for i in r(n)))for k in r(2**n))

オンラインでお試しください!



0

、28バイト

⪫EX²№θv⭆θ⎇⁼λv§v^÷ιX²№…θμv붶

オンラインでお試しください!リンクは、コードの詳細バージョンです。説明:

   ²                            Literal 2
  X                             Raised to power
    №                           Count of
      v                         Literal `v`
     θ                          In input string
 E                              Map over implicit range
        θ                       Input string
       ⭆                        Map over characters and join
           λ                    Current character
          ⁼                     Equal to
            v                   Literal `v`
         ⎇                      Then
              v^                Literal `v^`
             §                  Circularly indexed by
                 ι              Outer index
                ÷               Integer divided by
                   ²            Literal 2
                  X             Raised to power
                    №           Count of
                        v       Literal `v`
                      θ         In input string
                     …          Truncated to length
                       μ        Inner index
                         λ      Else current character
⪫                         ¶¶    Join with newlines
                                Implicitly print

0

PHP、93バイト

for(;$j<1<<$x;$j+=print$s)for($x=0,$s=$argv[1];$i=strpos($s,v,$i+1);$s[$i]=$j&1<<$x++?'^':v);

オンラインでお試しください!

スタンドアロンプ​​ログラム、コマンドライン経由で入力。

の数に基づいて、入力文字列の可能な順列の数をループしvます。バイナリでカウントアップしながら、入力文字列の各バイナリをa で置き換え、各バイナリ1をa で置き換えます。^0v

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.