蛮力配电盘


32

前几天,我们的团队去了一个逃生室。难题之一是由六个机械开关组成的板,您必须找到打开和关闭的正确组合才能解锁盒子,如下所示:

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

作为开发人员,我们认为尝试2 ^ 6 = 64个组合中的每个组合要比实际解决难题更有效。因此,我们分配了一个可怜的家伙进行一些二进制计数:

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

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

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

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

等等。

挑战
编写一个程序,给定所有开关都按上述格式设置为关闭的字符串,从而以任意顺序生成打开和关闭的所有组合。

您可以编写完整的程序或函数。因此,您的程序可以通过stdin,文件或单个字符串参数接收输入,然后返回或打印输出。如果返回,则输出可能在列表/数组/等中。而不是单个字符串。如果输出为单个字符串,则板子之间应使用换行符分隔(允许使用尾随换行符)。

输入字符串将与正则表达式匹配,r'((-v)+-)(\n(-v)+-)*'并代表一块板,所有开关均关闭。这意味着无零情况,并且开关左对齐。每行可能没有相同数量的开关。

每个输出板应具有与输入完全相同的格式,除了v可以根据需要用^代替。输出板可以用任意数量的换行符分隔。

由于运行时间自然是开关数量的O(2 ^ n),因此您的代码将不会在任何排列的10个以上的开关上进行测试。

这是代码高尔夫球,因此以字节数为单位的最短代码获胜。

样本输入和输出

输入:

-v-

可能的输出:

-v-
-^-

输入:

-v-
-v-

可能的输出:

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

-v-
-^-


-v-
-v-

由于要为更大数量的开关检查答案非常繁琐,因此这里有一个Python脚本作为健全性检查工具。(不幸的是,我提供了一个当前注释掉的代码段,以在给定的输入文件中生成预期的输出,以备您需要更多的测试用例。)将输入字符串放在名为“ input”的文件中,并将换行符分隔的输出(对不起,没有列表格式)放在同一目录中的名为“ output”的文件中,然后运行python3 sanitycheck.py


8
不错的第一个挑战!
朱塞佩

12
希望“可怜的人”了解格雷码,以便在每个组合之间仅翻转一位。
Eric Duminil

1
时间是我们最宝贵的财富,不要白白浪费时间。
Pedro Lobito

6
给定主题,我很失望,您并不需要切换次数最少的订单(例如00-> 01-> 11-> 10有3个切换,而00-> 01-> 10-> 11有4个切换) -研究员蛮力逃避者
池上

2
@EricDuminil:如果机械开关不是按钮(甚至可能不是按钮),那么很可能,切换一,两个和三个连续的开关(您几乎可以同时进行)之间所需的时间差不会足够大抵消额外的脑力劳动以遵循格雷代码。
tomasz

Answers:


23

Haskell25 24 23 17字节

mapM$min"^v".pure

在线尝试!

-1个字节感谢@ H.PWiz

-1字节感谢@nimi

返回字符串列表。TIO有2个额外的字节用于函数声明-我已经看到其他人在无点编写函数时将其关闭,因此除非另有说明,否则我会这样做。

上一个答案(25个字节)

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

这些解释都是针对先前的答案的,其工作方式几乎相同,不同之处在于我内联了的定义g。该方法g的工作原理是现在使用的词汇比较替代^vv,并保持一切相同。

有趣的是,这适用于任意总机:

>>> 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

说明(长)

mapM对于不熟悉Haskell的人来说,这是一个非常可怕的功能。但是在这种情况下不难理解。通过使其作用于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^"; 其他所有内容都将转换为单例字符串(请记住,字符串只是的列表Char,因此我们可以将其放入x单例列表中)。在REPL上进行测试,我们发现情况确实如此

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

注意,g具有正确类型的参数可以作为mapM(当然!)。

我们将mapM通过给出它g和论点来探索工作原理

"-v-\n-v-"

作为输入。

mapM首先映射gString,因为g皈依Chars到Strings,这给我们的列表Strings

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

虽然这是正确的输出类型,mapM但实际效果要稍微多一些。String如果必须从列表中的每个字符中选择一个字符String(按顺序),则可以将其视为可以从此列表创建的所有s 。

因此,对于第一个元素,您只能选择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-^-"]

如预期的。


哦,我一直在等待一个纯粹的功能性答案,这真让我惊讶于它的简洁程度。
in的傅立叶变换

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~]使用string-concatenation叉积运算符减少该列表X~

9

果冻,7个字节

«Ƭ€”^Œp

在线尝试!

输出是果冻字符串的列表。

说明:

«Ƭ€”^Œ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代码页,以试图找出第一个答案是如何不断超越其他每个答案的,几乎总是一个相当好的幅度……您是否想解释一下它的工作原理?
in的傅立叶变换

@ 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运算符,该运算符可以接受类似shell的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修改原始输入,为上一步中描述的结果的每一行生成一个副本(即所有可能的v/ ^组合)。在每个副本v中,原始输入的替换为一个可能的v/ 序列^

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个字节。

通过计算上限节省了另外8个字节 (1<<numberOfSwitches)更紧凑地。

根据注释中提到的规则,应该声明函数声明,因此现在是lambda ...


2
我很确定您必须String generate(String s) {...}在字节数中包含函数定义()。这是191个字节的固定/ lambda版本。我做了一些次要的高尔夫球运动以剃除3个字节
本杰明·厄克特

@BenjaminUrquhart好吧,这些是我不熟悉的“规则”的细节(我不经常在这里打高尔夫球)。我认为实际{ function body }应该相关,因为是否将其放入一个函数与否无关紧要static,当然,如果声明计入分数,则可以将其转换为lambda表达式。但这就是现在要做的,感谢您指出这一点。
Marco13

1
一些建议:1.使用ascii码,而不是char(d=94)。2. i声明时进行初始化。3.使用i++<m而不是单独的增量(需要在一处修改循环的内容,但这不会增加成本)。4.你能摆脱(i&1<<j++)>0吗?5.我认为您不需要将其{}用于内部for循环。6. 我认为您可以替换a[k]==d||a[k]==ua[k]>45。7.继续j=k=0。所有这些都将删除19bytes。
VisualMelon

@VisualMelon其中一些是“经典高尔夫”方法,我已经应用了其中一些方法。它们是否适用取决于-我认为有些{}是必要的,但我可以再看看。但是,这a[k]>45可能是一个巧妙的把戏。诚然,我只是为了浪费时间而写这封信,等待会议开始(因此,班级名称-这是有意的;-)),但也许我会再看一遍-谢谢!
Marco13

@ Marco13确实是经典技巧,但是所有这些都专门在这里适用。我不会给您基于它们的172字节解决方案来破坏乐趣(顺便说一句,它认为您的是192而不是191,但是我不知道lambda计数是如何工作的:无论如何我都反对它)。
VisualMelon

3

J41 40 24字节

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

在线尝试!


非常令人印象深刻。喜欢使用{。尽管我认为[:>@,@{<@(,'^'$~'v'=])"0这样会更公平一点,因为“每个输出板应与输入完全相同的格式”,并且输入未装箱。
约拿

@乔纳谢谢。更正。
ngn


3

C(gcc)75 74 70字节

-5字节感谢@ceilingcat

*b=0;f(char*s){b=b?b:s;*s?f(s+1),*s>46?*s=94,f(s+1),*s='v':0:puts(b);}

在线尝试!

要求存储s点可写


@cielingcat是正确的:tio.run
Brian Minton

确实是@BrianMinton。而且我永远也不会想尝试这个。真好!
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)))

在线尝试!

函数返回换行分隔板的向量


嗯,我是如此专注于以一种更加困难的方式来接受输入,以至于我忽略了这种输入的简便性。很好用"[<-"
朱塞佩

@Giuseppe:我对这个解决方案不是很满意...但是我试图以其他方式(例如,使用二进制转换)生成组合,但这最终是最短的。
digEmAll


1

视网膜0.8.2,29字节

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

在线尝试!说明:

T`¶v`;#

将换行符更改为;s,将vs 更改为#标记。

+%1`#

#从左到右一次更换一个。

v$'¶$`^

将每行更改为两行,一行#替换为v,一行用a代替^

%`;|$
¶

;s换回换行符,并将结果隔开。




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中没有优雅的字符串替换...

第一个循环建立线到位索引的映射,即对于每条线,存储位计数器中第一位的索引。这用于在下一个循环中索引位计数器。

第二个循环运行一个二进制计数器,提取每一行的位并进行迭代,然后将它们合并。将所有内容连接在一起后,使用字符串替换将其转换回切换映射格式。

我猜想,有一种更优雅的方法是重用输入字符串,而不是一遍又一遍地重建它。

编辑:受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

红宝石,64字节

返回一个数组。从获取数字1个2v (哪里 v 是输入中“ v”的数量),然后根据 v最低有效位。这使我们可以节省一个字节,而不是从02v-1个,因为 v 中的最低有效位 2v 全为零。

在Ruby中,i[j]返回从最低有效位开始的jth i位,也就是(i>>j)&1

->s{(1..2**s.count(?v)).map{|i|j=-1;s.gsub(/v/){'v^'[i[j+=1]]}}}

在线尝试!


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。而在二进制计数,替换每个二进制1^和每个二进制0v输入字符串。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.