Простой логический калькулятор

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 для подсчета символов, если вы поддерживаете оба.

Это : самый короткий код на любом языке выигрывает!

Asteri
источник
3
Я считаю, ^что имя символа должно быть написано карет .
FireFly
3
@FireFly Ха-ха, ты прав. Слишком близко к обеду! Спасибо.
Астери

Ответы:

6

APL (45 - 6 = 39)

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

Поддерживает Tи в Fкачестве ввода, но всегда будет выводить 0или 1.

Объяснение:

  • 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
  • : eval

Примечание: ~и =уже поступайте правильно, чтобы их не нужно было заменять чем-либо.

Мэринус
источник
Очень хорошо! Это подход с переводом на APL и Eval, верно? Я размышлял над подходом на основе герундов в J, но я не знаю, как ловко разделить операнды. : \
FireFly
Зачем манипулировать матрицей, когда вы можете просто добавить правила перевода для символов без изменений, например ⍎'1010~∧∨⍲⍱≠=≤'['10TF~&|^vx=>'⍳⍞]? (Счет 33-6 = 27)
TwiNight
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
Также чтение справа налево. Я знал, что ввод и позиционирование переменной длины будет проблемой, и это отличный способ ее решить. Действительно отличное нестандартное мышление. Хочешь работать в моей команде разработчиков? Ха-ха
астери
4
Я думаю, что у большего количества ответов должны быть подобные объяснения. Помогает тем из нас, кто еще многому учится! (И под теми, кто все еще учится, в значительной степени понимают всех)
agweber
@agweber: Приятно слышать, я немного волновался по поводу моего объяснения. И да, вероятно, все здесь находятся в фазе "все еще обучения" .. ну, по крайней мере, я знаю, что я нахожусь.
FireFly
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

Ungolfed:

# 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} ...берет строку и заменяет ~ 0на 1и ~ 1с0
  • lassign ... a берет первый элемент списка и присваивает его переменной a, возвращает остаток.
  • foreach {op b} ... {code}просматривает список и каждый раз принимает 2 элемента: opиb
  • set a [$op $a $b]выполняет команду в переменной op, сохраняет результат вa
Йоханнес Кун
источник
3

JavaScript - 107 105 символов

alert((x=eval(prompt().replace(/v/,'|~').replace(/\^/,'&~').replace(/x/,'^').replace(/=/,'==')))!=-1?x:0)
ProgramFOX
источник
Ха-ха забавно. Это удобно Даже не думал о том, eval()когда я это придумал. Просто дай мне немного времени, чтобы вернуться домой и проверить это.
Астери
1
нанд = &~и ни = |~?
Йоханнес Кун
@Johannes: Это на самом деле не &~и |~, но NAND только обратная И. Таким образом, инвертирование одного из битов также инвертирует результат.
ProgramFOX
3

Befunge-98 - 104 101 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 и ОРЗ = вход», который как раз случается по умолчанию идентичности ). 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, потому что это соответствует таблице истинности для |.

Светляк
источник
Это безумно. Хорошо, каждое решение в befunge сумасшедшее.
Йоханнес Кун
2

J - 65 67-6 = 61

Нет больше б. Наречие. Без учета назначения функции: 67 символов для версии TF, 63 для версии без TF:

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... 
jpjacobs
источник
1

Постскриптум 263

Идея светлячка переведена в Postscript.

{(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
МДС
источник