사양에서 사각형 생성


14

소개

이 과제는 2D 패턴 일치 언어 인 Grime 에서 영감을 얻었습니다 . 기본적으로 2 차원 문자 격자를 설명하는 "문법"이 주어지며, 작업은 문법에 따라 격자를 생성하는 것입니다. 또한 그리드는 약한 의미에서 가능한 한 작아야합니다.

입력

귀하의 입력은 소문자 ASCII 문자와 기호가 포함 된 문자열 |-. 편의상 입력에 반복되는 소문자가 포함되지 않습니다. 문자열은 문자의 사각형 그리드 클래스에 대한 스펙이며 다음과 같이 스택을 사용하여 왼쪽에서 오른쪽으로 구문 분석됩니다.

  • 소문자가 주어지면, 문자 그리드를 c스택에 밀어 넣으 십시오 .m×ncm, n ≥ 1
  • 파이프 주어 |두 격자 팝 AB스택에서 ( B위에 WAS), 그리드 밀어 AB연결함으로써 얻어진 B오른쪽을 A. 이 것을 요구 A하고 B동일한 높이를 가지고있다.
  • 하이픈이 주어지면 -두 개의 그리드 AB스택 ( B위에 있음)을 팝 하고의 하단 A/B에 연결 B하여 얻은 그리드 를 밉니다 A. 이 것을 요구 A하고 B동일한 폭을 가지고있다.

이를 위해 보장되는 일부 의 선택 m하고 n(각 문자에 대해 상이 할 수 있음) 파싱 과정 중에 입력 사양 올바르게 단부에서 스택에 남아있는 일부 구형을 설명한다.

산출

출력은 입력으로 지정된 직사각형 문자 격자입니다. 행이나 열을 제거하면 무효화 될 수 있다는 점에서 그리드는 최소화되어야합니다. 줄 바꿈으로 구분 된 문자열 (후행 줄 바꿈 유무에 관계없이), 2D 문자 배열 또는 문자열 배열 중 가장 편리한 형식을 반환 할 수 있습니다.

위에서 설명한대로 입력을 처리 할 필요는 없습니다. 유일한 중요한 것은 출력이 정확하다는 것입니다.

사양을 고려

par-s||e-

첫째, 우리는 밀어 선택 1×2의 사각형을 p, 그리고 1×1의 사각형 ar(그 이유는 나중에 분명히 할 것이다). 그런 다음 사각형 ar사각형 을 팝 하고 세로 연결을 누릅니다.

a
r

다음으로 우리는 1×2사각형을 밀어 넣고 s, 위 사각형을 터 뜨리고 가로 연결을 밀어 넣습니다.

as
rs

그런 다음 사각형과 사각형을 팝 p하고 연결을 푸시합니다.

pas
prs

마지막으로 우리는 3×1사각형을 밀어 넣고 e위 사각형을 밀어 수직 연결을 밀어 넣습니다.

pas
prs
eee

이것은 프로그램의 출력이거나 적어도 하나의 가능성입니다. 그럼에도 불구하고

ppas
ppas
pprs
eeee

많은 행과 열을 제거 할 수 있으므로 스펙에 의해 생성되는 경우 올바른 출력이 아닙니다.

더 미묘한 예로서, 고려

co|m|p|il|e|r|-

이 사양은 사각형을 생성합니다

comp
iler

유효한 출력입니다. 그러나 또한 생성

commp
iiler

단일 행 또는 열을 무효화하지 않고 제거 할 수 없으므로 유효합니다.

규칙

당신은 전체 프로그램이나 기능을 제공 할 수 있습니다. 가장 낮은 바이트 수가 이기고 표준 허점은 허용되지 않습니다.

추가 테스트 사례

이를 사용하여 프로그램을 테스트 할 수 있습니다.

Input:
a
Output:
a

Input:
co|mp|l|-ex|i|f|-y|
Example output:
cccoy
mplly
exify

Input:
ja-r|g-o|ni-|ze|d-|
Example output:
jronze
arondd
ggoidd

Input:
un|co|p-yr|i|gh-t-ab|-|le-||-
Example output:
unnnnnnn
coyriggl
ppyrihhe
ppyritte
ppyriabe

n과 m은 어디에서 왔습니까?
seequ

정적이거나 입력 형식이어야합니까?
seequ

@Sieg nm비 결정적으로 선택됩니다. 적합한 값이 존재하는 것이 보장되지만 값을 찾는 것이 프로그램의 작업입니다.
Zgarb

당신은 실제로 그들이 무엇인지 정의하지 않습니다.
seequ

un|co|p-|yr|i|gh--t-ab|-|le-||-유효하지 않습니다. 마지막 -은 arity가 2이고 스택에는 하나의 요소 만 있습니다.
orlp

답변:


6

K, 123110 바이트

cardboard_box의 솔루션에 비슷한 접근 방식을 사용했습니다.

r:{y,x#,*|y};h:{t:(#x)|#y;r[t-#x;x],'r[t-#y]y};a:{(,x .|2#y),2_ y};*(){(a[{+h[+x;+y]}]x;a[h]x;(,,y),x)"-|"?y}/

이 프로그램은 일련의 도우미 정의 다음에 문자열을 올바른 인수로 취하는 암묵적 기능이 뒤 따릅니다. 가독성을 위해 다시 포맷하고 최종 기능을 f다음 과 같이 지정하십시오 .

r: {y,x#,*|y};                           / repeat last row x times
h: {t:(#x)|#y;r[t-#x;x],'r[t-#y;y]};     / append horizontal
v: {+h[+x;+y]};                          / append vertical
a: {(,x[y@1;y@0]),2_ y};                 / pop two values, concat

f: *(){:[y="-";a[v;x]; y="|";a[h;x]; (,,y),x]}/;

사용 예 :

  f "ja-r|g-o|ni-|ze|d-|"
("jronze"
 "aroidd"
 "ggoidd")

코나를 사용하여 테스트,하지만 그것도에서 작동 확인 당신이 대체하는 경우 :의 정의에 fA를 $- K5는 "COND"의 구문을 변경했습니다.

요점은 수직 추가가 두 행렬의 전치의 수평 추가의 전치라는 것을 인식하고 있습니다. (정의 참조 v) 나는 여기저기서 몇 글자를 짜낼 여지가 있다고 생각합니다. 더 자세한 설명에 관심이있는 사람이 있으면 알려주세요.

편집하다:

이 항목의 맨 위에있는 프로그램을 업데이트했습니다. 언 골프 버전 :

r: {y,x#,*|y};                           / repeat row x times
h: {t:(#x)|#y;r[t-#x;x],'r[t-#y;y]};     / append horizontal
v: {+h[+x;+y]};                          / append vertical
a: {(,x .|2#y),2_ y};                    / apply a concat
f: *(){(a[v]x;a[h]x;(,,y),x)"-|"?y}/;

주목할만한 길이 최적화에는에서 "dot apply"를 사용하고 a, "cond"를 목록 인덱싱 f(덜 효율적이지만 짧음)으로 대체하고 양식의 용어를 그룹화가 허용하는 위치 a[b;c]로 바꿉니다 a[b]c. 더 이상 "cond"또는 k3과 k5가 다른 프리미티브를 사용하지 않기 때문에이 버전은 이제 수정없이 oK에서 작동합니다.


현상금을 수상한 것을 축하합니다!
Zgarb

감사! K에게 꽤 좋은 결과를 낳은 것은 흥미로운 문제였습니다. 비교를 위해 J 나 APL의 시도를 보는 것이 흥미 로웠을 것입니다.
JohnE

4

프롤로그, 539 바이트

:-lib(ic).
:-lib(util).
b(A,B,C):-between(A,B,C).
g(S):-string_list(S,L),p(L,[]).
w(h(L,R):_:_,I,J):-w(L,I,J);L=_:W:_,X is I-W,w(R,X,J).
w(v(U,D):_:_,I,J):-w(U,I,J);U=_:_:H,Y is J-H,w(D,I,Y).
w(f(C):W:H,I,J):-b(1,W,I),b(1,H,J),char_code(S,C),put_char(S).
p([],[S]):-term_variables(S,V),S=_:X:Y,labeling(V),!,b(1,Y,J),(b(1,X,I),w(S,I,J);nl),fail.
p([124|T],[Q,Z|R]):-!,Q=_:WA:H,Z=_:WB:H,W #= WA+WB,p(T,[h(Z,Q):W:H|R]).
p([45|T],[Q,Z|R]):-!,Q=_:W:HA,Z=_:W:HB,H #= HA+HB,p(T,[v(Z,Q):W:H|R]).
p([C|T],R):-!,[H,W] #:: 1..100,p(T,[f(C):W:H|R]).

설명

우리는 predicate로 시작 g하는데, 이것은 문자열을 가져 와서 그것을 문자 목록으로 변환 p하고 빈 스택을 가진 두 번째 인자로 (parse) 술어를 호출합니다 .

술어 p는 적절하게 수정 된 스택을 사용하여 재귀 적으로 호출합니다 ( [H|T]파괴 및 생성자 패턴 찾기 ). 입력 목록이 비어있는 기본 사례에서 호출되면 p스택의 고유 한 요소를 인쇄합니다. 이 시점에서 스택에 둘 이상의 요소가있는 경우 빈 입력 문자열, 잘못된 입력 문자열 또는 버그 (emtpy 문자열의 경우 술어는 실패 No하지만 프롤로그는 말한다 )를 인쇄하지만, 빈 문자열에는 아무것도 인쇄해서는 안되기 때문에 괜찮습니다.)

해결

스택에는 표시된 사각형에 대한 설명이 포함되어 있습니다. S:W:H여기서 사각형 S의 상징적 표현, W너비 및 H높이입니다 (참고로, functor라는 이름 A:B:(A,B)튜플의 구문 설탕입니다. 튜플을 :갖는 것보다 쓰기가 짧습니다) 접두사 표기법으로).

with AB사각형 직사각형 사양 S은 다음 중 하나 일 수 있습니다.

  • h(A,B) : A와 B의 수평 연결
  • v(A,B) : A와 B의 수직 연결
  • f(C) : C로 채 웁니다. 여기서 C는 문자 코드입니다.

그리드의 너비와 높이는 구속 조건 프로그래밍 변수입니다. 수직 (수평) 연결 중에 조작 된 사각형의 너비 (수신 높이)는 통합되는 반면 결과 높이 (수신 너비)는 다음의 합으로 제한됩니다. 각 서브 그리드의 높이 (가로 폭)

프로세스가 끝날 때 라벨링 단계는 가능한 최소값을 사용하여 제약 조건을 고려하면서 변수를 표시합니다 (이는 솔루션을 시도하는 순서의 속성입니다).

제약 조건없이 다른 답변에서와 동일한 추론을 사용하여 더 짧은 답변을 얻었을 수도 있지만 지금은 너무 늦습니다.

변수의 기본 도메인이로 설정되어 1..100있으므로 가능한 그리드 크기에 제한이 있습니다. 필요한 경우 상한을 변경할 수 있습니다. 이것의 성능에 미치는 영향은 특정 솔루션이 솔루션을 허용하지 않는다고 판단하는 데 많은 시간 걸릴 있다는 것 입니다. 제약 조건이 지수 검색을 크게 제거 할 가능성이 있기 때문에 나는 " 할 수있다 " 고 말했다 . 거부하기 어려운 / 고가의 입력 문자열을 찾으면 공유하십시오.

인쇄

의 종류가 있기 때문에 인쇄 부분은 흥미 롭다 레이 캐스팅 구조를 통해 알고리즘 : I으로 반복 지점에서 결과 그리드의 각 셀, 이상 (1,1)(W,H)과 전화 w술어가 메인 트리에서 그리드의 내용을 인쇄하기에 이 위치 (물론 각 줄을 처리 한 후 줄 바꿈이 인쇄 됨).

으로는 w, 위치가 현재의 그리드를 기준으로 (루트 그리드는 절대 좌표를 정의한다).

인쇄 할 때 h(A,B)point (X,Y)에서 구조체를 두 가지 모두에 무조건 인쇄합니다.

  • 그리드 A 점에서 (X,Y), 그리고
  • 격자 B점에서 (H,Y), 곳이 H있다X 마이너스의 폭 A.

격자 나무의 잎 가지, f(C)C 는 상대 위치가 그리드 내부에있는 경우 문자를 인쇄 하거나 아무 것도 수행하지 않습니다. 이것이 그리드의 내용을 출력 스트림으로, 위에서 아래로, 왼쪽에서 오른쪽으로 인쇄하는 방법입니다. 실제 어레이가 생성되지 않습니다.

테스트

t("ja-r|g-o|ni-|ze|d-|").
t("un|co|p-yr|i|gh-t-ab|-|le-||-").
t("co|mp|l|-ex|i|f|-y|").
t("a").

tt :- t(X),nl,g(X).
tt.

테스트 실행 :

[eclipse] tt.

jronze
aronze
ggoidd

uuuuuuun
coyriggl
coyrihhl
coyrittl
ppyriabe

cccoy
mmply
exify

a

Yes (0.00s cpu)

+1 No actual arrays are produced.그렇게해야합니다. 문법이 너무 단순하고 지름길이 있기 때문에이 경우 과잉입니다.
edc65

@ edc65 네, 그것은 과잉입니다. 그러나 코드 골프이기 때문에 크기를 최소화하려고 시도했으며 배열을 조작하는 것이 너무 장황했을 것입니다.
coredump

3

파이썬 2.7, 259

z=zip
def p(a,b):
 s,l=sorted([a,b],key=len)
 s+=([s[-1]]*(len(l)-len(s)))
 return z(*(z(*a)+z(*b)))
g=lambda s,t=[]:s and(s[0]=='-'and g(s[1:],t[:-2]+[z(*p(z(*t[-2]),z(*t[-1])))])or(s[0]=='|'and g(s[1:],t[:-2]+[p(t[-2],t[-1])])or g(s[1:],t+[[s[0]]])))or t[0]

g사양을 취하고 2D 문자 배열을 제공하는 함수입니다. 보다 사용자 친화적 인 버전을 원한다면이 줄을 추가하여 stdin에서 사양을 가져 와서 그리드를 인쇄하십시오.

print'\n'.join(''.join(s)for s in g(raw_input()))

테스트 사례

Input:
a
Output:
a
==========
Input:
co|mp|l|-ex|i|f|-y|
Output:
coooy
mplly
exify
==========
Input:
ja-r|g-o|ni-|ze|d-|
Output:
jronze
aroidd
ggoidd
==========
Input:
un|co|p-yr|i|gh-t-ab|-|le-||-
Output:
unnnnnnn
coyriggl
ppyrihhe
ppyritte
ppyriabe

설명

전략은 간단합니다. 그리드 G가 사양에 유효한 경우 S의 가장 오른쪽 열을 반복 G하면에 대한 유효한 사양이 제공 S되고 맨 아래 행을 반복하는 경우에도 마찬가지입니다 (증거는 구조적 유도에 의한 것임 S). 따라서 두 개의 직사각형을 연결하려면 크기가 일치 할 때까지 작은 열의 마지막 열 / 행을 추가하면됩니다 (이것은 함수 p의 기능입니다).


3

하스켈, 388 367 352 바이트

data C=L{c::Char}|N{t::Int,w::Int,h::Int,l::C,r::C}
q=replicate
[]#[x]=x
(c:i)#(b:a:s)|c=='-'=i#(N 1(max(w a)$w b)(h a+h b)a b:s)|c=='|'=i#(N 2(w a+w b)(max(h a)$h b)a b:s)
(c:i)#s=i#(N 0 1 1(L c)(L c):s)
p i|t i==0=q(h i)$q(w i)$c$l i|t i==2=zipWith(++)(p(l i){h=h i})$p(r i){h=h i,w=w i-w(l i)}|1<2=p(l i){w=w i}++p(r i){w=w i,h=h i-h(l i)}
f=p.(#[])

사용법 : f "par-s||e-"->["pas","prs","eee"]

예쁜 인쇄로 테스트 실행 :

> putStr $ unlines $ f "par-s||e-"
pas
prs
eee

> putStr $ unlines $ f "co|m|p|il|e|r|-"
comp
iler

> putStr $ unlines $ f "a"
a

> putStr $ unlines $ f "co|mp|l|-ex|i|f|-y|"
coooy
mplly
exify

> putStr $ unlines $ f "ja-r|g-o|ni-|ze|d-|"
jronze
aroidd
ggoidd

> putStr $ unlines $ f "un|co|p-yr|i|gh-t-ab|-|le-||-"
unnnnnnn
coyriggl
ppyrihhe
ppyritte
ppyriabe

작동 방식 :이 함수 #는 입력 문자열을 트리 구조로 구문 분석하여 인쇄 할 문자를 보유한 C리프 L또는 노드 N입니다. Na) 나란히 조인 ( t==2), b) 맨 아래 조인 ( t==1) 또는 c) 단일 문자 사각형 ( t==0) 일 수 있습니다. 모든 노드에는 너비 및 높이 필드와 왼쪽 및 오른쪽 자식이 있습니다. 파싱 ​​후p 하위 노드의 크기 (너비 x 높이)를 재귀 적으로 조정하고 결합하여 나머지 루트 노드를 인쇄합니다.

편집 : 예쁜 인쇄 대신 줄 목록으로 출력


1

자바 스크립트 (ES6), 283 295

편집 (이 골프) JS 솔루션은 최소한 (골프 가능한) 참조 Python 솔루션보다 짧습니다.

cardboard_box와 유사하게 가장 왼쪽 열 또는 맨 위 행을 반복합니다.

F=w=>(
s=[t=1,l='length'],
[for(c of w)(
  b=s[t],a=s[--t],
  c>'z'?
    s[t]=(G=(a,b,m=b[l]-a[l])=>m?m>0?G([a[0],...a],b):G(a,[b[0],...b]):a.map((r,i)=>r+b[i]))(a,b)
  :c<'a'?
    s[t]=a.map(r=>r[m=b[0][l]-r[l],0].repeat(m>0&&m)+r).concat(b.map(r=>r[0].repeat(m<0&&-m)+r))
  :s[t+=2]=[c]
)],
s[t].join('\n'))

Ungolfed 이것은 내 첫 번째 ungolfed 솔루션입니다.

F=sp=>{
  s=[]
  for(c of sp){
    a=s.pop(b=s.pop())
    if (c > 'z')
    {
      l = a.length
      m = b.length
      for(; l-m ;)
        l < m ? l = a.unshift(a[0]) : m = b.unshift(b[0])
      s.push(a.map((r,i) => r + b[i]))
    }
    else if (c < 'a')
    {
      l = a[0].length
      m = b[0].length
      s.push(
        a.map(r => r[0].repeat(l < m ? m-l : 0) + r)
        .concat(b.map( r => r[0].repeat( l > m ? l-m : 0) + r))
      )
    }
    else 
    {
      s.push(a,b,[c])
    }
  }
  return s.pop().join('\n')
}

Firefox / FireBug 콘솔에서 테스트

;['par-s||e-','co|m|p|il|e|r|-','co|mp|l|-ex|i|f|-y|',
 'ja-r|g-o|ni-|ze|d-|','un|co|p-yr|i|gh-t-ab|-|le-||-']
.forEach(w=>console.log(F(w)))

산출

pas
prs
eee

comp
iler

cccoy
mmply
exify

jronze
aronze
ggoidd

uuuuuuun
coyriggl
coyrihhl
coyrittl
ppyriabe

0

파이썬 3, 251 바이트

내가 약속 한 참고 답변은 다음과 같습니다.

T=lambda m:list(map(list,zip(*m)))
E=lambda a,b:a[:1]*(len(b)-len(a))+a
H=lambda a,b:[d+c for c,d in zip(E(a,b),E(b,a))]
s=[]
for k in input():s=k>"z"and[H(*s[:2])]+s[2:]or k<"a"and[T(H(*map(T,s[:2])))]+s[2:]or[[[k]]]+s
for r in s[0]:print("".join(r))

STDIN에서 문자열을 가져 와서 STDOUT으로 인쇄하는 전체 프로그램입니다. 접근 방식은 cardboard_box와 동일합니다. 1x1 배열을 문자로 푸시하고 연결에 필요한 경우 행을 복제하십시오.

$ echo "par-s||e-" | python3 gr.py
pas
prs
eee

상해

  • T주어진 목록의 목록을 바꿉니다. 대부분의 작업은 zip(*m)행을 열로 바꾸는 작업으로 이루어지며 나머지는 결과를 목록 목록으로 변환합니다 zip. 튜플 생성기를 반환하기 때문 입니다.
  • E(a,b)a의 길이와 일치 할만큼 첫 번째 요소가 반복해서 반복 된 상태로 반환합니다 b. 목록에 음수를 곱하면 빈 목록이 제공되므로 b보다 짧은 경우 a를 반환합니다 a.
  • H(a,b)수평 연결 및를 반환 a하며 b, E필요한 경우 길이가 짧아집니다 .
  • s 스택입니다.
  • 에서 for루프, 우리는 입력 문자열을 반복하고, 대체s 새로운 값 : 그것의 경우 |(이상은 z), 우리는 두 개의 값을 팝과 밀어 H, 경우의 -(보다 a), 우리는 두 개의 값, 전치, 사료 팝 H, 다시 전치하고 결과를 푸시하고 그렇지 않으면 문자로 1x1 배열을 푸시하십시오.
  • 마지막으로, 우리는 첫 번째 요소를 인쇄합니다 s .
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.