一个简单的逻辑门计算器


9

如果您选择接受,那么您的任务就是为以下逻辑运算符构造一个简单的真值评估器:

----------------------------------------------------------------------------------
  Logical Name          |  Gate Name   |  Symbol  |  Symbol Name  |  Truth Table
----------------------------------------------------------------------------------
  Identity              |  is          |          |  (none)       |  10
  Negation              |  not         |    ~     |  tilde        |  01
  Conjunction           |  and         |    &     |  ampersand    |  1000
  Disjunction           |  or          |    |     |  pipe         |  1110
  Negative Conjunction  |  nand        |    ^     |  caret        |  0111
  Joint Denial          |  nor         |    v     |  "vee"        |  0001
  Exclusive Disjunction |  xor         |    x     |  "ecks"       |  0110
  Equivalence           |  equals/xnor |    =     |  equals       |  1001
  Implication           |  implies     |    >     |  greater than |  1011

真值表的顺序如下:

  1. 1 1
  2. 1 0
  3. 0 1
  4. 0 0

输入将以简单的字符串0、1和符号形式出现。您可以接受输入作为参数,也可以从用户在stdin上读取它。以下是一些示例输入/输出对:

Input: 1
Output: 1

Input: ~1
Output: 0

Input: 0|1
Output: 1

Input: 1>0
Output: 0

一元运算符(否定)将始终出现在布尔值之前,而二进制运算符将始终出现在两个布尔值之间。您可以假定所有输入均有效。字符串是常规的ASCII字符串。

如果愿意,可以同时使用T和F而不是1和0。 如果同时支持,则在字符数上使用-6

这是 :任何语言中最短的代码都会成功!


3
我相信^符号名称应该说成脱字号
FireFly 2013年

3
@FireFly哈哈,你是对的。太接近午餐了!谢谢。
asteri

Answers:


6

APL(45-6 = 39)

⍎(1+9≠L)⌷¨↓⍉Z⍪⍉⍪'10∧∨⍲⍱≠≤*'[L←'TF&|^vx>'⍳Z←⍞]

支持TF作为输入,但始终输出01

说明:

  • Z←⍞:读取一行并将其存储在 Z
  • L←'TF&|^vx>'⍳Z:获取'TF&|^vx>'每个字符的索引Z,给出9字符不在的索引'TF&|^vx>'
  • '10∧∨⍲⍱≠≤*'[... ]:在中找到相应的字符'10∧∨⍲⍱≠≤*'。(因此不在第一个列表中的字符变为*)。
  • ↓⍉Z⍪⍉⍪:将其放入矩阵中,将原始(Z)放在其顶部,然后将其拆分为字符串列表,其中第一个字符为原始字符,第二个字符为其译文(如果有)。
  • (1+9≠L)⌷¨:对于每个字符串,如果没有翻译(L=9在该位置),则获取第一个字符;如果没有,则获取第二个字符。
  • 示例:如果输入为T|0,那么我们1∨0现在将拥有对应的APL表达式
  • :评估

注意:~并且=已经做对了,所以不需要用任何东西代替它们。


非常好!这是一种转换为APL的方法,对吗?我在考虑使用J中基于gerund的方法,但是我不知道如何巧妙地拆分操作数。:\
FireFly

当您可以为诸如这样的不变字符简单地添加翻译规则时,为什么要进行矩阵处理⍎'1010~∧∨⍲⍱≠=≤'['10TF~&|^vx=>'⍳⍞]?(得分33-6 = 27)
2013年

8

Ç - 165 127

蛮好玩的!普通查找表依靠固定的偏移量进行查找。

main(){
  char*s="100011001110110v& x = |^> /~",
       t[6]="0/xxx",
      *u= strchr((gets(t+2),t),0)-3;
  putchar(strchr(s,u[1])[*u*2+u[2]-159]);
}

由于某种原因,gets它没有被隐式声明,因此当我删除包含时,我不得不更改gets(t+2)(gets(t+2),t)(或类似地,花费很多)。


说明

首先,由于运算符的真值表具有大量重叠字符,因此我们希望以某种方式存储查找表,以允许重叠。这是我选择存储它们的方式:

v    &    x    =    |    ^    >       ~     (operation)
1000 0001 0110 1001 0111 1110 1101 01 10    (truth table [order 00,01,10,11])
0    1    3    5    7    8    9    B  D     (offset in LUT below)

0123456789ABCDE   (offsets)
100011001110110   (values)

接下来,我们想将运算符符号映射到这些偏移量。为此,我们将运算符存储在与LUT数据相距固定偏移量的同一字符串中(即,之后的16个字符,即紧接LUT数据之后)。查找过程是“在s,减16,加left*2+right(左/右操作数)中查找运算符。对于空的“身份运算”的查找,由于如何获取输入,在这种情况下,该运算符将解析为以下内容t[1]初始化为: -在我们的例子中/,因此,我们用它/作为查找表的关键字来表示身份操作,当我们处理一元~操作“ left”(对于前面提到的查找计算)始终是相同的//碰巧小于0ASCII方式,即当我们补偿ASCII数字时\将表示-1。查找表关键字区域中的斜线(即中的倒数第二个字符s)的位置用于对此进行补偿。

接下来,输入处理。输入具有动态长度,但是如果我们为左操作数,运算符和右操作数指定了特定的静态名称,则不管输入如何,它都会更容易。如果我们假装可以从右到左读取输入,那么这基本上会自动发生-右操作数始终是最右字符,运算符(如果存在)是第二至右,左操作数(如果存在) )位于最右边。为了能够像这样索引字符串,我们使用strchr了以定位\0终止符(- 3以简化索引)。这说明了为什么t[0]t[1]成为左操作数/操作者分别当输入是1个或2个字符。

将其放在一起,输出将是putchar(strchr(s,u[1])[(u[0] - '0')*2 + (u[2] - '0') - 15]),但是某些重构和恒定折叠会使我们变得更短putchar(strchr(s,u[1])[u[0]*2+u[2]-159])


您能解释一下它是如何工作的吗?
约翰内斯·库恩

真值表重叠是一个绝妙的主意。我自己永远也不会想到这一点。:)
asteri

也是从右到左的读数。我知道可变长度的输入和定位会带来挑战,这是解决它的好方法。真正出色的开箱即用思维。想加入我的开发团队吗?哈哈
asteri

4
我认为更多答案应该有这样的解释。帮助仍在学习中的我们很多人!(而那些仍在学习的人意味着所有人)
agweber

@agweber:很高兴听到,我有点担心我的解释。是的,可能这里的每个人都处于“还在学习”阶段。好吧,至少我知道我是。
FireFly 2013年

4

TCL,212 208-6 = 202

proc o n\ e {proc $n a\ b expr\ $e}
o > {$a<=$b}
o v {!($a|$b)}
o x {$a^$b}
o ^ {!($a&$b)}
namespace pat tcl::mathop 
lmap o\ b [lassign [split [string map {~0 1 ~1 0} $argv] {}] a] {set a [$o $a $b]}
puts $a

取消高尔夫:

# Defines an operator
proc operator {name expression} {
    proc $name {a b} "expr $expression"
}
operator > {$a<=$b}
operator v {!($a|$b)}
operator x {$a^$b}
operator ^ {!($a&$b)}
# Call the commands in ::tcl::mathop if the command is not in the global namespace
namespace path tcl::mathop
# lmap instead foreach
# assume that we only got 1 argument.
foreach {op b} [lassign [string map {{~ 0} 1 {~ 1} 0} [split $argv {}]] a] {
   set a [$op $a $b]
}
puts $a

我认为foreach行需要一些解释:

  • split $argv {} 将输入字符串(实际上是一个列表,但代码高尔夫球)拆分成多个字符。
  • string map {{~ 0} 1 {~ 1} 0} ...接受一个字符串,并取代~ 01~ 10
  • lassign ... a 接受列表的第一个元素,并将其分配给变量a,返回其余元素。
  • foreach {op b} ... {code}遍历列表,每次使用2个元素:opb
  • set a [$op $a $b]在变量中执行命令op,将结果存储在a

3

JavaScript- 107105个字符

alert((x=eval(prompt().replace(/v/,'|~').replace(/\^/,'&~').replace(/x/,'^').replace(/=/,'==')))!=-1?x:0)

哈哈,真好。那很方便。甚至都没想到eval()我做了这个。请给我一点时间回家测试一下。
2013年

1
nand = &~和nor = |~
Johannes Kuhn

@Johannes:不是真的&~and |~,但是NAND只是AND的反函数。因此,将一位中的一位取反也可以将结果取反。
ProgramFOX 2013年

3

Befunge- 98-104101 98-6 72

...因为每个任务都需要一个esolang解决方案。.我的C实现的翻译,但一次只能处理一个字符。

#v~
2_vp5a00+*2%2\p10\%
0:<+1_v#-g5\g1
1_|#:\</2\-
.@>2%
 v   ~x^&=.>  |

有趣的事实:将更@改为,a,$然后您会得到一个永无止境的REPL(尽管这样做,您会发现标识实际上是“用lhs = 0和rhs = input重复最后一个命令”,这恰好是默认为identity )。REPL不再是。

Ungolfed(早期版本):

v10001100111011v& x = |^>~
  $       1111111111222222
 1234567890123456789012345

 [read input]
> ~ :a- #v_   $ 21g " "- + 0g , @

v p11:   <
   ↑save chr

0 ←lup   [traverse LUT]
> 1+  :11g  \0g -! #v_
 v                  <
    lup chr acc
v>  :3` #v_  $"0"-\2*+

               v>   . , a,
 v       <
v> 9+9+ 21p $

编辑:受@jpjacobs解决方案的启发,我现在依靠字符在LUT中的位置来表示真值表。例如,|在位置1110 2 = 14上,因为这对应于的真值表|


这很疯狂。好的,每一个解决方案都是疯狂的。
约翰内斯·库恩

2

J- 65 67-6 = 61

b。副词。不计算功能分配:TF版本为67个字符,非TF版本为63个字符:

lgcTF =:".@({&('*+-+-<*01',.3 6#'.:')"1@n^:(9>n=:'&|~xv>^FT'&i.)@{.&.>&.;:)
lgc   =:".@({&('*+-+-<*',.3 4#'.:')"1@n^:(7>n=:'&|~xv>^'&i.)@{.&.>&.;:)

LgcTF处理0和1以及T和F。

支持J的所有语法,包括序列,括号和从右到左的严格评估(没有其他优先级规则)。

不能使用运算符列表+ Z中未包含的所有字符,其他字符将用作标准J(包括变量)。

用法:

NB.Assign TF anyhow
T=:1 [ F=: 0
lgc 'T & F'
0
lgc ' T ~@& F' NB. negation after and = nand
NB. make a truth table
d=: 0 1
lgc 'd ~@|/ d'
1 0
0 0 
NB. and so on... 

1

后记263

萤火虫的想法翻译成后记。

{(0/xxx)dup 2 3 getinterval(%lineedit)(r)file exch 
readstring pop length 1 sub 3
getinterval(100011001110110v& x = |^> /~)dup
2 index 1 1 getinterval search pop exch pop exch pop 
length 3 2 roll{}forall exch pop exch 2 mul add 159 sub add 
1 getinterval =}loop

缩进:

%!

{
    (0/xxx) dup 2 3 getinterval
    (%lineedit)(r)file exch % (0/xxx) file (xxx)
    readstring pop
    length % (0/xxx) len(x|xx|xxx)
    1 sub 3 getinterval % (0/x)|(/xx)|(xxx)
    (100011001110110v& x = |^> /~) dup
    2 index 1 1 getinterval search pop % (0/x)|(/xx)|(xxx) s post match pre
    exch pop exch pop % (xxx) s pre
    length 
    3 2 roll {} forall exch pop % s len(pre) u_0 u_2
    exch 2 mul add 159 sub add % s ind
    1 getinterval
    = flush
} loop

1

Befunge-93,86个字符

通过将输入的第二个符号散列为y坐标(找到一个既紧凑又避免碰撞的函数是一项工作)来工作,然后将第一个和第三个符号取模2作为x坐标的两个最低有效位,然后检索指示位置上的任何值。更好的哈希函数或更紧凑的存储/寻址真值表的方法只是减少长度的两种可能方法。

~~~\:8/\5%:++00p2%\2%2*+00gg,@
0 1







1001
0001
1101
1

0
0110



1110
1000


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