모스 디코드 골프


24

나는 성장하는 경보가 한 공간의 증오이 답변이 있는지 모스 부호는 공백이 교활한 제거으로부터 안전하기 위해 나에게 영감을하고있다.

따라서 모든 공백을 제거한 상태에서 모스 부호를 성공적으로 번역 할 수있는 프로그램을 작성해야합니다.

모스 식 부호

규칙 :

  1. 입력은 대시와 점 (ASCII 2D 및 2E)으로 만 구성된 문자열입니다. 다른 문자를 포함하는 입력에 대해서는 출력이 정의되지 않습니다. 선택한 언어에 편리한 방법을 사용하여 입력을 받으십시오 (stdin, text 파일, prompt user 등). 모스 부호 입력은 문자 AZ로만 구성되며 일치하는 숫자 나 문장 부호는 필요하지 않다고 가정 할 수 있습니다.

  2. 출력에는 이 사전 파일에 포함 된 단어 만 포함되어야 합니다 ( 사전 파일 에 액세스하는 편리한 방법을 자유롭게 사용하십시오). 유효한 모든 디코딩은 stdout으로 출력되어야하며 입력의 모든 점과 대시를 사용해야합니다. 출력에서 일치하는 각 단어는 공백으로 구분하고 가능한 각 디코딩은 개행으로 구분해야합니다. 대문자, 소문자 또는 대소 문자 혼합 출력을 편리하게 사용할 수 있습니다.

  3. 표준 허점 에 대한 모든 제한 은 위에서 언급 한 한 가지 예외를 제외하고 적용되며, 원하는 경우 인터넷 연결을 통해 요구 사항 2에서 참조 된 사전 파일에 액세스 할 수 있습니다. URL 단축이 허용 됩니다. goo.gl/46I35Z 가 가장 짧을 것으로 생각합니다 .

  4. 이것은 코드 골프, 가장 짧은 코드 승리입니다.

참고 : Pastebin에 사전 파일을 게시하면 모든 줄 끝이 Windows 스타일 0A 0E 시퀀스로 변경되었습니다. 프로그램은 줄 끝을 0A 만, 0E 만 또는 0A 0E로 가정 할 수 있습니다.

테스트 사례 :

입력:

......-...-..---.-----.-..-..- ..

출력에는 다음이 포함되어야합니다.

안녕 세상

입력:

.--..-.-----..-..-----..-.--..--...---..--...-.... ...--.-..-.-.----...--.---.-....-.

출력에는 다음이 포함되어야합니다.

프로그래밍 퍼즐 및 코드 골프

입력:

-.....--.-..-..-.-.-.--....-.---.---...-.----..-.- --..---.--....---...-..-.-......-...---..-.---..-- ---.

출력에는 다음이 포함되어야합니다.

빠른 갈색 여우는 게으른 개 위로 점프


3
AN (.- -.)와 사이에 어떻게 알 수 EG (. --.)있습니까?
seequ

2
@Sieg-출력에는 유효한 디코딩이 모두 포함되어야합니다.
Comintern

1
@Dennis-Ahhh ... Pastebin 또는 내 브라우저가 그렇게했다고 확신합니다. 내 소스 파일에 없습니다. 줄 구분자를 시스템에 적합한 것으로 변경할 수 있으며 다른 변경은 할 수 없습니다. 전화가 없을 때 질문을 편집하겠습니다.
Comintern

2
@Falko 그것은 올바른 행동입니다. 문제는 출력에 "hello world" 가 포함되어야 한다는 것입니다. 유효한 모든 디코딩을 인쇄해야합니다.
홉스

2
(거의 시적, 실제로)
호브

답변:


5

루비, 210

(1..(g=gets).size).map{|x|puts IO.read(?d).split.repeated_permutation(x).select{|p|p.join.gsub(/./,Hash[(?a..?z).zip"(;=/%513':07*)29@-+&,4.<>?".bytes.map{|b|('%b'%(b-35))[1,7].tr'01','.-'}])==g}.map{|r|r*' '}}

"과 골프"와 같은 관행이 있다면, 이번에 내가 참여했다고 생각합니다. 이 솔루션 은 길이 1에서 입력 길이까지 모든 사전 단어 의 반복 순열 배열을 생성합니다 . "a"가 사전 파일에서 가장 짧은 단어이고 코드의 길이가 2자인 경우 입력 크기의 절반까지 길이의 순열을 생성하는 데 충분했지만 /2이 도메인의 자세한 표시는 그래서 나는 자제했다.

순열 어레이가 생성되면 ( NB는 : 그 길이가 45,404이다 (104) 각각의 순열 배열 연접되어 상기 pangrammatic 예컨대 입력의 경우), 그 알파벳 문자가 아닌 편리한 통해 자신의 모르스 부호 등가물로 대체 (Regexp, Hash)의 변형 #gsub방법; 이 문자열이 입력과 동일한 경우 유효한 디코딩을 찾았습니다.

"d"라는 파일에서 사전을 읽거나 (몇 번) 입력에 개행을 포함해서는 안됩니다.

예제 실행 (우주 열사병이 끝나기 전에 프로그램에 전투 기회를 줄 사전을 사용) :

$ cat d
puzzles
and
code
dummy
golf
programming
$ echo -n .--..-.-----..-..-----..-.--..--...---..--...-.......--.-..-.-.----...--.---.-....-. | ruby morse.rb
programming puzzles and code golf
^C

5

하스켈, 296 자

  • 사전 파일 : "d"라는 텍스트 파일이어야합니다.
  • 입력 : stdin, 후행 줄 바꿈이 있지만 내부 공백은 없을 수 있습니다.
main=do f<-readFile"d";getLine>>=mapM(putStrLn.unwords).(words f&)
i!""=[i]
(i:j)!(p:q)|i==p=j!q
_!_=[]
_&""=[[]]
d&i=do
w<-d
j<-i!(w>>=((replicate 97"X"++words".- -... -.-. -.. . ..-. --. .... .. .--- -.- .-.. -- -. --- .--. --.- .-. ... - ..- ...- .-- -..- -.-- --..")!!).fromEnum)
n<-d&j
[w:n]

요소 설명 :

  • main사전을 읽고, stdin을 읽고, 실행 하고 적절한 공백으로 &출력 형식을 지정합니다 &.
  • (replicate 97"X"++words".- -... -.-. -.. . ..-. --. .... .. .--- -.- .-.. -- -. --- .--. --.- .-. ... - ..- ...- .-- -..- -.-- --..")!!)(의 정의 안에있는 표현식 &)은 인덱스가 문자 코드 (97은 코드 'a')이고 값은 모스 시퀀스 인 목록입니다.
  • !(중위 연산자로 명명 된 함수)는 접두사와 문자열을 일치시킵니다. 접두어가 있으면 나머지는 단일 요소 목록 (목록 모나드에서 성공)으로, 그렇지 않으면 빈 목록 (목록 모나드에서 실패)으로 리턴합니다.
  • &"비 결정적"실행을 위해리스트 모나드를 사용합니다. 그것

    1. d(사전 단어) 항목을 선택하고
    2. 입력 문자열 !에 해당 단어의 모스 형식 ( w>>=((…)!!).fromEnum과 동등한 concatMap (((…)!!) . fromEnum) w) 을 일치시키는 데 사용 합니다 i.
    3. d&j나머지 문자열과 일치하도록 자체 ( )를 호출 하고
    4. w:n리스트 모나드에서 단어 목록으로 가능한 결과를 리턴합니다 [w:n](이는 더 짧고 구체적입니다 return (w:n)).

    6 행 이후의 모든 행은 do6 행에서 시작된 표현식의 일부입니다 . 한 줄에 세미콜론을 사용하는 것과 정확히 같은 수의 문자를 사용하지만 프로그램에서 한 번만 수행 할 수 있지만 더 읽기 쉽습니다.

이 프로그램은 매우 느립니다. 수정 된 단어를 각 패턴 일치에서 다시 계산하지 않고 목록에서 원본 옆에 저장하여 쉽게 빠르고 쉽게 만들 수 있습니다. 다음으로해야 할 일은 불필요한 분기를 시도하지 않도록 모스 기호 (2-ary trie ) 가있는 이진 트리에 단어를 저장하는 것 입니다.

사전 파일과 같은 사용되지 않는 문자를 보관 않은 경우는 약간 짧게 할 수있다 "-"의 제거를 허용 replicate 97"X"++하고 찬성 .(-97+)전과를 !!.


젠장, 영리합니다. 당신에게 +1.
Alexander Craggs

1
당신은 그것을 (+(-97))다시 쓸 수 있다는 것을 알고 (-97+)있습니까?
자랑스런 Haskeller

h의 세 번째 정의를 제거하고 대신 |0<1=[]두 번째 정의에 추가 해야합니다
proud haskeller

2
interact12자를 사용 하여 승리 하십시오 . interact$unlines.map unwords.(words f&)
gxtaillon

1
다음을 교체 할 수 있어야 concatMap>>=
자랑 haskeller

3

파이썬- -363 345

암호:

D,P='-.';U,N='-.-','.-.'
def s(b,i):
 if i=='':print b
 for w in open('d').read().split():
  C=''.join([dict(zip('abcdefghijklmnopqrstuvwxyz-\'23',[P+D,D+3*P,U+P,'-..',P,D+N,'--.',4*P,2*P,P+3*D,U,N+P,2*D,D+P,D*3,'.--.',D+U,N,P*3,D,'..-',3*P+D,'.--','-..-',U+D,'--..']+['']*4))[c]for c in w]);L=len(C)
  if i[:L]==C:s(b+' '+w,i[L:])
s('',input())

설명:

사전은 "d"라는 일반 텍스트 파일로 저장해야합니다.

D, P, UN 모스 룩업 테이블의 짧은 정의 그냥 도우미 변수입니다.

s(i)는 이전에 번역 된 메시지 부분 p과 나머지 코드 부분의 각 유효한 번역 을 인쇄하는 재귀 함수입니다 i. i비어있는 경우 코드 끝에 도달 b하여 전체 번역 이 포함되어 있으므로 간단히 변환 print됩니다. 그렇지 않으면 우리 w는 사전의 각 단어 를 확인하고 d그것을 모스 부호로 번역 C하고, 나머지 코드 i가로 시작 C하면 단어 w를 번역 된 시작 부분에 추가 b하고 함수를 호출합니다s 하고 나머지에서 재귀 적으로 .

효율성에 대한 참고 사항 :

이것은 꽤 느리지 만 골프 버전입니다. 특히 사전을로드하고 dict(zip(...))각 변수마다 모스 조회 테이블 ( )을 구성하면 (더 많은 변수를 피하기 위해) 비용이 많이 듭니다. 그리고 사전에 사전에있는 모든 단어를 한 번에 한 번 번역하는 것이 더 효율적이며 필요할 때마다 각 재귀에 번역하는 것이 더 효율적입니다. 이러한 아이디어는 40 자 이상의 캐릭터로 다음과 같은 버전으로 이어지지 만 속도는 크게 향상됩니다.

d=open('d').read().split()
D,P='-.';U,N='-.-','.-.'
M=dict(zip('abcdefghijklmnopqrstuvwxyz-\'23',[P+D,D+3*P,U+P,'-..',P,D+N,'--.',4*P,2*P,P+3*D,U,N+P,2*D,D+P,D*3,'.--.',D+U,N,P*3,D,'..-',3*P+D,'.--','-..-',U+D,'--..']+['']*4))
T=[''.join([M[c]for c in w])for w in d]
def s(b,i):
 if i=='':print b
 for j,w in enumerate(d):
  C=T[j];L=len(C)
  if i[:L]==C:s(b+' '+w,i[L:])
s('',input())

로 교체 .startswith(C)하여 2자를 저장할 수 있습니다 [:len(C)]==C.
Greg Hewgill

와우 고마워! 각 재귀에 전체 사전을로드하면 문자가 저장되고 알고리즘이 한 번 더 느려지기 때문에 꽤 이상합니다.
Falko

@GregHewgill : 예, 제가 원래 한 일입니다. 방금 두 버전을 모두 다루기 위해 답변을 편집했습니다.
Falko

1
단어의 길이를 내림차순으로 사전을 정렬하면 더 흥미로운 결과 (더 긴 단어)를 더 빨리 생성 할 수 있습니다. d=sorted(open('d').read().split(),key=len,reverse=1)또는 사전을 그런 식으로 미리 정렬하여 외부에서 수행하십시오.
Greg Hewgill

사전 파일을 다시 포맷 할 수 있다면 미리 계산 된 파이썬 사전으로 포맷하고 M=eval(open('d').read()):)
Greg Hewgill

3

펄 (5.10+), 293 자

사전 파일은 "d"(및 단어 사이에 CR을 원하지 않는 경우 유닉스 형식이어야 함), stdin에 모스 입력 (마지막 줄 바꿈 없음 echo -n)으로 저장해야합니다 (use ).

open D,d;chomp(@w=<D>);@m{a..z}=map{substr(sprintf("%b",-61+ord),1)=~y/01/.-/r}
'BUWI?OKMATJQDCLSZGE@FNHVXY'=~/./g;%w=map{$_,qr#^\Q@{[s/./$m{$&}/reg]}#}@w;
@a=[$i=<>];while(@a){say join$",@{$$_[1]}for grep!$$_[0],@a;
@a=map{$x=$_;map{$$x[0]=~$w{$_}?[substr($$x[0],$+[0]),[@{$$x[1]},$_]]:()}@w}@a}

(줄 바꿈은 서식 지정에만 해당).

Ungolfed 코드 :

# Read the word list
open my $dictionary, '<', 'd';
chomp(my @words = <$dictionary>);

# Define morse characters
my %morse;
@morse{'a' .. 'z'} = map {
  $n = ord($_) - 61;
  $bits = sprintf "%b", $n;
  $bits =~ tr/01/.-/;
  substr $bits, 1;
} split //, 'BUWI?OKMATJQDCLSZGE@FNHVXY';

# Make a hash of words to regexes that match their morse representation
my %morse_words = map {
  my $morse_word = s/./$morse{$_}/reg;
  ($_ => qr/^\Q$morse_word/)
} @words;

# Read the input
my $input = <>;

# Initialize the state
my @candidates = ({ remaining => $input, words => [] });

while (@candidates) {
  # Print matches
  for my $solution (grep { $_->{remaining} eq '' } @candidates) {
    say join " ", @{ $solution->{words} }; 
  } 
  # Generate new solutions
  @candidates = map {
    my $candidate = $_;
    map {
      $candidate->{remaining} =~ $morse_words{$_}
        ? {
          remaining => substr( $candidate->{remaining}, $+[0] ),
          words => [ @{ $candidate->{words} }, $_ ],
        }
        : ()
    } @words
  } @candidates;
}

Modus Operandi :

모스 부호 기호는 "."을 변경하여 저장됩니다. "-"는 이진수 0과 1로 시작하고, "1"을 앞에 붙여서 (앞의 점들이 흐트러지지 않도록) 이진수를 10 진수로 변환 한 다음 61 값이 더 높은 문자를 인코딩합니다. 인쇄 가능한 문자 및 백 슬래시가 필요없는 항목).

나는 이것을 일종의 파티션 문제라고 생각하고 그것을 기반으로 솔루션을 구축했습니다. 사전의 각 단어에 대해 문자열의 시작 부분에 공백이없는 모스 표현과 일치하고 캡처하는 정규식 객체를 구성합니다. 그런 다음 단어와 일치하지 않고 전체 입력이 "남은 입력"인 상태를 만들어 폭이 가장 넓은 검색을 시작합니다. 그런 다음 나머지 입력의 시작 부분과 일치하는 단어를 찾고 일치하는 단어에 단어를 추가하고 나머지 입력에서 모스를 제거하는 새로운 상태를 만들어 각 상태를 확장합니다. 남은 입력이없는 상태는 성공적이며 단어 목록이 인쇄됩니다. 어떤 단어 (성공한 단어 포함) 와도 일치하지 않는 상태는 하위 상태를 생성하지 않습니다.

ungolfed 버전에서 상태는 가독성을위한 해시입니다. 골프 버전에서 그것들은 배열입니다 (코드가 짧고 메모리 소비가 적습니다). slot [0]은 나머지 입력이고 slot [1]은 일치하는 단어입니다.

해설

이것은 불경건 한 속도입니다. 그렇지 않은 솔루션이 있는지 궁금합니다. Marpa (단일 입력 문자열에 여러 구문 분석을 제공하는 Earley 파서)를 사용하여 빌드하려고했지만 문법을 구성하는 메모리가 부족합니다. 아마도 BNF 입력 대신 하위 수준 API를 사용하면 ...


Kevin Reid와 동일한 요구 사항을 추가하면 (입력에 줄 바꿈 없음)을 제거하여 7자를 저장할 수 있습니다 chomp(). 내가해야합니까?
홉스

"편리한 방법을 자유롭게 사용하십시오".
Comintern

ord대신 2 바이트를 면도하십시오 ord$_. 1 바이트를 join$"대신 면도join" "
Zaid

2

하스켈-418

이 디코 잉 문제는 동적 프로그래밍으로 효율적으로 해결할 수 있습니다. 나는 이것이 코드 골프라는 것을 알고 있지만 빠른 코드를 좋아합니다.

우리는 입력 문자열을 말해봐 s우리가 배열을 구축 dp, dp[i]문자열의 모든 유효한 디코딩 결과의 목록입니다 s[:i]. 각 단어에 대해 w먼저 우리는 그것을 코딩하는 사전에서 mw, 우리는 일부 계산할 수 dp[i]dp[i - length(mw)]경우를 s[i - length(mw):i] == mw. 건물의 시간 복잡성은 dp입니다 O({count of words} {length of s} {max word length}). 마지막으로dp[length(s)] 마지막 요소 인 우리가 필요합니다.

사실, 우리는 전체 디코딩을 각각의 요소로 저장할 필요가 없습니다. dp[i] . 우리에게 필요한 것은 마지막으로 해독 된 단어입니다. 이를 통해 구현이 훨씬 빨라집니다. i3 랩탑에서 "hello world"사례를 완료하는 데 2 ​​초도 걸리지 않았습니다. 질문에 게시 된 다른 경우에는 출력 할 것이 너무 많아 프로그램이 실제로 완료되지 않습니다.

동적 프로그래밍 기술을 사용하여 유효한 디코딩 수를 계산할 수 있습니다 . 코드는 여기에서 찾을 수 있습니다 . 결과 :

input: ......-...-..---.-----.-..-..-..
count: 403856

input: .--..-.-----..-..-----..-.--..--...---..--...-.......--.-..-.-.----...--.---.-....-.
count: 2889424682038128

input: -.....--.-..-..-.-.-.--....-.---.---...-.----..-.---..---.--....---...-..-.-......-...---..-.---..-----.
count: 4986181473975221635

언 골프

import Control.Monad

morseTable :: [(Char, String)]
morseTable = zip ['a'..'z'] $ words ".- -... -.-. -.. . ..-. --. .... .. .--- -.- .-.. -- -. --- .--. --.- .-. ... - ..- ...- .-- -..- -.-- --.."

wordToMorse :: String -> Maybe String
wordToMorse xs = return . concat =<< mapM (`lookup` morseTable) xs

slice :: (Int, Int) -> [a] -> [a]
slice (start, end) = take (end - start) . drop start

decode :: String -> String -> IO ()
decode dict s = trace (length s) [] where
  dict' = [(w, maybe "x" id . wordToMorse $ w) | w <- lines dict]
  dp = flip map [0..length s] $ \i -> [(j, w) |
        (w, mw) <- dict', let j = i - length mw, j >= 0 && mw == slice (j, i) s]

  trace :: Int -> [String] -> IO ()
  trace 0 prefix = putStrLn . unwords $ prefix
  trace i prefix = sequence_ [trace j (w:prefix) | (j, w) <- dp !! i]

main :: IO ()
main = do
  ws <- readFile "wordlist.txt"
  decode ws =<< getLine

골프

import Control.Monad
l=length
t=zip['a'..]$words".- -... -.-. -.. . ..-. --. .... .. .--- -.- .-.. -- -. --- .--. --.- .-. ... - ..- ...- .-- -..- -.-- --.."
h s=return.concat=<<mapM(`lookup`t)s
f d s=g(l s)[]where g 0 p=putStrLn.unwords$p;g i p=sequence_[g j(w:p)|(j,w)<-map(\i->[(j,w)|(w,m)<-[(w,maybe"x"id.h$w)|w<-lines d],let j=i-l m,j>=0&&m==(take(i-j).drop j$s)])[0..l s]!!i]
main=do d<-readFile"d";f d=<<getLine

합리적으로 효율적인 솔루션을 보게되어 기쁩니다. 이제 나는 그것을 이해해야한다 :)
hobbs

2

PHP, 234 226 바이트

function f($s,$r=""){$s?:print"$r
";foreach(file(d)as$w){for($i=+$m="";$p=@strpos(__etianmsurwdkgohvf_l_pjbxcyzq,$w[$i++]);)$m.=strtr(substr(decbin($p),1),10,"-.");0!==strpos($s,$m)?:g(substr($s,strlen($m)),$r.trim($w)." ");}}

재귀 함수,라는 파일에서 사전을 가져옵니다 d.
문자가 아닌 문자를 포함하는 사전의 모든 단어에 대해 실패합니다.

당신이 경우 어떤 파일 이름을 사용할 수 있습니다 define ("d","<filename>");함수를 호출하기 전에 .

빠른 실행을 위해 2 또는 3 바이트를 추가
제거 $s?:print"$r\n";, 삽입 $s!=$m?전에 0!==:print$r.$w;}}.

고장

function f($s,$r="")
{
    $s?:print"$r\n";            // if input is empty, print result
    foreach(file(d)as$w)        // loop through words
    {
        // translate to morse:
        for($i=+$m="";              // init morse to empty string, $i to 0
                                        // loop while character is in the string
            $p=@strpos(__etianmsurwdkgohvf_l_pjbxcyzq,$w[$i++])
        ;)
            $m.=                        // 4. append to word morse code
                strtr(
                    substr(
                        decbin($p)      // 1: convert position to base 2
                    ,1)                 // 2: substr: remove leading `1`
                ,10,"-.")               // 3. strtr: dot for 0, dash for 1
            ;
        0!==strpos($s,$m)           // if $s starts with $m
            ?:f(                        // recurse
                substr($s,strlen($m)),  // with rest of $s as input
                $r.trim($w)." "         // and $r + word + space as result
            )
        ;
    }
}

1

그루비 377 337

r=[:];t={x='',p=''->r[s[0]]=p+x;s=s.substring(1);if(p.size()<3){t('.',p+x);t('-',p+x)}};s='-eishvuf-arl-wpjtndbxkcymgzqo--';t()
m=('d'as File).readLines().groupBy{it.collect{r.get(it,0)}.join()}
f={it,h=[]->it.size().times{i->k=it[0..i]
if(k in m){m[k].each{j->f(it.substring(i+1),h+[j])}}}
if(it.empty){println h.join(' ')}}
f(args[0])

노트

dict는 파일 이름이어야합니다 d. 모스 문자열은 명령 행으로 전달됩니다. 예 :

% groovy morse.groovy ......-...-..---.-----.-..-..-.. | grep 'hello world'
hello world

"morse code compression"의 경우 이진 트리를 사용하고 있습니다.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.