GNU 도입부 622 634 코드 페이지 850에서 668 바이트
업데이트 : 이전 버전의 프로그램에서 때때로 교차가 너무 빡빡하여 제대로 렌더링되지 않아 사양을 위반하는 경우가있었습니다. 이를 방지하기 위해 추가 코드를 추가했습니다.
업데이트 : 분명히 PPCG 규칙에는 프로그램을 종료하고 시작 당시의 상태를 정확하게 복원하기 위해 추가 코드가 필요합니다. 이로 인해 프로그램이 다소 길어지고 알고리즘에 관심이 없지만 규칙 준수를 위해 변경했습니다.
골프 프로그램
GNU Prolog는 이식 가능한 Prolog의 산술 구문보다 약간 짧은 제약 솔버 구문을 가지고 있기 때문에 몇 바이트를 절약 할 수 있습니다.
y(A,G):-A=1;A= -1;A=G;A is-G.
z(A/B,B,G):-y(A,G),y(B,G),A=\= -B.
v(D,E,G):-E=1,member(_-_,D),p(D);F#=E-1,nth(F,D,M),(M=[_];M=L-S/R,z(L,O,G),J is F+O,nth(J,D,I/U-T/Q),(I=O,Q#=R-1,S=T;K is J+O,R=0,n(S-T-V),y(U,G),U\=O,U=\= -O,I=U,nth(K,D,O/_-V/_))),v(D,F,G).
i([H|K],S):-K=[]->assertz(n(S-H-0));T#=S+1,assertz(n(S-H-T)),i(K,T).
t([],1,_):-!.
t(D,R,G):-S#=R-1,t(E,S,G),H#=G-1,length(F,H),append(F,[[x]|E],D).
s(1,2).
s(-1,1).
s(S,T):-S>1->T=3;T=0.
r(I/O-_,C):-s(I,J),s(O,P),N#=J*4+P+1,nth(N,"│┐┌?└─?┌┘?─┐?┘└│",C).
r([X],C):-X\=y->C=10;C=32.
p([]).
p([H|T]):-r(H,C),put_code(C),!,p(T).
g(4).
g(G):-g(H),G#=H+1.
m(K):-i(K,0),g(G),t(D,G,G),length(D,L),v(D,L,G),abolish(n/1).
연산
이것은 시작하는 방법을 알기가 어려운 문제 중 하나입니다. 주어진 표기법에서 매듭의 모양을 해결하는 방법은 확실하지 않습니다. 표기법이 모호 할 수 있습니다). 내 솔루션은 효과적으로 오래된 골프 대기를 사용하는 것입니다. 가능한 모든 출력을 생성하고 입력과 일치하는지 확인하는 매우 비효율적 인 프로그램을 작성하십시오. (Prolog가 가끔 막 다른 골목을 버릴 수 있기 때문에 여기에서 사용되는 알고리즘이 약간 더 효율적이지만, 계산 복잡성을 향상 시키기에는 충분한 정보가 없습니다.)
출력은 터미널 아트를 통해 이루어집니다. GNU Prolog는 ASCII와 일치하는 단일 바이트 문자 세트를 원하지만 어떤 비트가 사용되는지는 상관하지 않습니다 (높은 비트 세트를 가진 문자를 불투명으로 처리하므로). 결과적으로 IBM850을 사용했습니다. IBM850은 널리 지원되며 필요한 선 그리기 문자가 있습니다.
산출
프로그램은 가능한 모든 매듭 이미지를 경계 상자 크기 순서대로 검색 한 다음 첫 번째를 찾으면 종료합니다. 출력 결과는 다음과 같습니다 m([0]).
.
┌┐
┌│┘
└┘
내 컴퓨터에서 실행하는 데 290.528 초가 걸렸습니다. 이 프로그램은 매우 효율적이지 않습니다. 나는 2 시간 동안 달리기를 m([0,1])
끝내고 이것을 끝내었다.
┌┐┌┐
└─│┘
└┘
주석이 달린 언 골프 버전
Stack Exchange의 구문 형광펜에는 Prolog에 대한 잘못된 주석 기호가있는 것으로 보이므로 %
(Prolog가 실제로 사용하는) 주석 대신 이 설명은 % #
주석 (물론 시작으로 인해 동일 %
하지만 올바르게 강조 표시됨)을 사용합니다.
% # Representation of the drawing is: a list of:
% # indelta/outdelta-segment/distance (on path)
% # and [x] or [_] (off path; [x] for border).
% # A drawing is valid, and describes a knot, if the following apply
% # (where: d[X] is the Xth element of the drawing,
% # k[S] is the Sth element of the input,
% # n[S] is S + 1 modulo the number of sections):
% # d[X]=_/O-S-R, R>1 implies d[X+O]=O/_-S-(R-1)
% # d[X]=_/O-S-0 implies d[X+O]=_/_-k[S]-_
% # and d[X+O*2]=O/_-n[S]-_
% # all outdeltas are valid deltas (±1 row/column)
% # not technically necessary, but makes it possible to compile the
% # code (and thus makes the program faster to test):
:- dynamic([n/1]).
% # legal delta combinations:
y(A,G):-A=1;A= -1; % # legal deltas are 1, -1,
A=G;A is-G. % # grid size, minus grid size
z(A/B,B,G):-y(A,G),y(B,G), % # delta components are valid
A=\= -B. % # doesn't U-turn
% # z returns the outdelta for convenience (= byte savings) later on
% # We use v (verify) to verify the first E-1 elements of a drawing D.
% # nth is 1-indexed, so we recurse from length(D)+1 down to 2, with
% # 1 being the trivial base case. After verifying, the grid is printed.
% # This version of the program causes v to exit with success after
% # printing one grid (and uses p to do the work of deciding when that is).
v(D,E,G):-E=1, % # base case:
member(_-_,D), % # ensure the grid is nonempty
p(D); % # print the grid (and exit)
% # otherwise, recursive case:
F#=E-1,nth(F,D,M), % # check the last unchecked element
(
M=[_]; % # either it's not on the path; or
M=L-S/R, % # it's structured correctly, and
z(L,O,G), % # it has a valid delta;
J is F+O, % # find the outdelta'd element index
nth(J,D,I/U-T/Q), % # and the outdelta'd element
(
I=O,Q#=R-1,S=T; % # if not an endpoint, points to next pixel
K is J+O, % # else find segment beyond the path:
R=0, % # it's an endpoint,
n(S-T-V), % # it points to the correct segment,
y(U,G), % # ensure we can do NOT comparisons on U
U\=O,U=\= -O, % # the line we jump is at right angles
I=U, % # the line we jump is straight
nth(K,D,O/_-V/_) % # the pixel beyond has a correct indelta,
% # and it has the correct segment number
)
),
v(D,F,G). % # recurse
% # We use i (init) to set up the k, n tables (k and n are fixed for
% # any run of the program, at least). S is the number of elements that
% # have been removed from K so far (initially 0). To save on characters,
% # we combine k and n into a single predicate n.
i([H|K],S):-K=[]-> % # if this is the last element,
assertz(n(S-H-0)); % # section 0 comes after S;
T#=S+1, % # otherwise, add 1 to S,
assertz(n(S-H-T)), % # that section comes after S,
i(K,T). % # and recurse.
% # We use t (template) to create a template drawing. First argument is
% # the drawing, second argument is the number of rows it has plus 1,
% # third argument is the number of columns it has plus 1.
t([],1,_):-!.
t(D,R,G):-S#=R-1,t(E,S,G), % # recurse,
H#=G-1,length(F,H), % # F is most of this row of the grid
append(F,[[x]|E],D). % # form the grid with F + border + E
% # We use s (shrink) to map a coordinate into a value in the range 0, 1, 2, 3.
s(1,2).
s(-1,1).
s(S,T):-S>1->T=3;T=0.
% # We use r (representation) to map a grid cell to a character.
r(I/O-_,C):-s(I,J),s(O,P),N#=J*4+P+1,nth(N,"│┐┌?└─?┌┘?─┐?┘└│",C).
r([X],C):-X\=y->C=10;C=32.
% # We use p (print) to pretty-print a grid.
% # The base case allows us to exit after printing one knot.
p([]).
p([H|T]):-r(H,C),put_code(C),!,p(T).
% # We use g (gridsize) to generate grid sizes.
g(4).
g(G):-g(H),G#=H+1.
% # Main program.
m(K):-i(K,0), % # initialize n
g(G), % # try all grid sizes
t(D,G,G), % # generate a square knot template, size G
length(D,L), % # find its length
v(D,L,G), % # verify and print one knot
% # Technically, this doesn't verify the last element of L, but we know
% # it's a border/newline, and thus can't be incorrect.
abolish(n/1). % # reset n for next run; required by PPCG rules