테트리스 블록 프로그래밍 (말 그대로)


33

게임 테트리스 벽돌 또는 7 개 종류가있다 Tetr의 난의 minoes 수학적으로 공지되어 tetr O를 minoes 들이 4 개 정사각형 세그먼트로 만들어지기 때문에이 :

테트리스 벽돌

이름은 대략적인 모양에 해당하는 이름 I, J, L, O, S, T 및 Z입니다. 90 ° 회전을 계산하면 총 19 개의 고유 한 모양이 있습니다.

I
I
I
I

IIII

 J
 J
JJ

JJJ
  J

JJ
J
J

J
JJJ

L
L
LL

  L
LLL

LL
 L
 L

LLL
L

OO
OO

 SS
SS

S
SS
 S

TTT
 T

T
TT
T

 T
TTT

 T
TT
 T

ZZ
 ZZ

 Z
ZZ
Z

도전

이 19 개의 모양이 만들어지는 기본 세그먼트 역할을하는 직사각형 코드 블록을 작성하십시오. 이 코드가 모양 중 하나에 정렬되면 해당 모양과 관련된 단일 대문자를 출력하는 프로그램을 구성해야합니다. 이것은 19 가지 모양 모두에 적용되어야합니다.

19 개 모양 중 일부에있는 빈 영역은 공백으로 완전히 채워져 있습니다 ( ). 후행 빈 영역에는 아무것도 채워지지 않습니다 (따라서 프로그램이 항상 직사각형은 아닙니다).

이것이 코드 블록이라고 가정하십시오.

ABC
123

그런 다음 S Tetris 조각에 블록을 배치하면 다음과 같은 프로그램이 인쇄됩니다 S.

   ABCABC
   123123
ABCABC
123123

ABC
123
ABCABC
123123
   ABC
   123

(앞의 모든 빈 공간은 공백 문자로 채워지며 행에 후행 공백이없는 것을 알 수 있습니다.)

동일한 아이디어가 6 개의 다른 조각과 각각의 회전에 적용됩니다.

노트

  • 19 개의 최종 프로그램은 모두 동일한 프로그래밍 언어로 실행됩니다.
  • 원하는 경우 모든 프로그램에 하나의 후행 줄 바꿈을 추가 할 수 있습니다 (일부만 또는 모두 아님).
  • 코드 블록에는 줄 종결 자가 아닌 문자 (공백 포함)가 포함될 수 있습니다 .
  • 선택적인 후행 줄 바꿈을 사용하여 문자를 표준 출력 (또는 언어의 가장 가까운 대안)으로 출력하십시오.

채점

코드 블록이 가장 작은 영역 (너비 x 높이)을 가진 제출이 이깁니다. 이것은 본질적으로 가장 짧은 코드가 승리 함을 의미하므로 태그가 붙습니다 . Tiebreaker는 가장 높은 투표 응답으로 갑니다 .

ABC\n123예의 면적은 3 × 2 = 6입니다.

단편

코드 블록이 주어지면이 스 니펫은 19 개의 프로그램을 모두 생성합니다.

<script>function drawShape(X,n,v){for(var t="",e=0;e<v.length;e++)for(var l=0;l<n.length;l++){for(var r=0;r<v[e].length;r++)t+="X"===v[e][r]?n[l]:X[l];t+="\n"}return t}function go(){var X=document.getElementById("input").value;if(0!=X.length){var n=X.replace(/./g," ").split("\n");X=X.split("\n");for(var v="I (v1):|I (v2):|J (v1):|J (v2):|J (v3):|J (v4):|L (v1):|L (v2):|L (v3):|L (v4):|O:|S (v1):|S (v2):|T (v1):|T (v2):|T (v3):|T (v4):|Z (v1):|Z (v2):".split("|"),t="X\nX\nX\nX|XXXX| X\n X\nXX|XXX\n  X|XX\nX\nX|X\nXXX|X\nX\nXX|  X\nXXX|XX\n X\n X|XXX\nX|XX\nXX| XX\nXX|X\nXX\n X|XXX\n X|X\nXX\nX| X\nXXX| X\nXX\n X|XX\n XX| X\nXX\nX".split("|"),e="",l=0;l<v.length;l++)e+=v[l]+"\n\n"+drawShape(n,X,t[l].split("\n"))+"\n";e=e.substring(0,e.length-2),document.getElementById("output").value=e}}</script><style>html *{font-family: monospace;}</style>Code Block:<br><textarea id='input' rows='8' cols='64'>ABC&#010;123</textarea><br><button type='button' onclick='go()'>Go</button><br><br>All 19 Programs:<br><textarea id='output' rows='24' cols='64'></textarea>


길이 너비 비율은 2 대 3입니까? 아니면 다른 크기가 될 수 있습니까? 또한 프로그램은 최소한 무엇을해야합니까? 빈 프로그램은 계산하지 않지만 아무 것도 출력하지 않는 프로그램은 계산하지 않습니다.
ASCIIThenANSI

@ASCIIThenANSI 모든 너비와 높이가 좋습니다. 2 * 3보다 큰 것이 필요할 것이라고 생각합니다. 19 개의 서로 다른 테트로 미노 형태 중 하나로 블록을 배열 할 때마다 19 개의 프로그램이 있습니다. 해당 프로그램 중 하나가 실행되면 해당 테트리스 문자가 출력됩니다.
Calvin 's Hobbies

와우! 대단한 도전입니다! 우리가 사용하는 언어가 중요합니까?
theonlygusti

@theonlygusti이 사이트의 거의 모든 질문은 모든 언어를 허용합니다. 예외는 아닙니다.
Calvin 's Hobbies

@ Calvin'sHobbies 그래, 알아; 방금 JavaScript 코드를 실행하는 컨트롤러로 스 니펫을 잘못 해석했습니다. 분명히 코드 블록을 정렬합니다.
theonlygusti

답변:


16

<> <(물고기)-12 * 32 = 384

나는 더 우아한 해결책을 찾으려고 계획했지만 어떻게 든 이것으로 끝났습니다.

c  0  g84*%\
c2*0  g84*%\
0  84*g84*%\
c  84*g84*%\
c2*84*g84*%\
0  88*g84*%\
c  88*g84*%\
?v         \
;>?v~~?vv   
"L" o;  >   
"S" o; >~?v 
"T" o;    > 
;  >~?v"L"o 
;     >"J"o 
?v         \
 >~?v~~?vv  
"I"  o;  >  
"J"  o; >   
    \~~?vv  
"T"  o;  >  
"Z"  o; >   
?v         \
 >?v"J"o;   
   >?v"Z"o; 
"L"o;>?!v   
"J"o;   >?v 
"T"o;     > 
?v?v"I"o;  >
   >"L"o;   
 >?v"T"o;   
   >?v"O"o; 
     >"S"o; 

매우 간단합니다. 3x3 정사각형의 코드에서 텍스트를 확인하고 결과를 사용하여 코드의 모양에 해당하는 테 트리 미노를 확인합니다. 나는 아직 골프를 치기 위해 많은 노력을 기울이지 않았다.

여기 에서 코드를 사용해보십시오 (스 니펫을 사용하여 테 트리 미노 모양으로 만든 후)

모양 Z (v1)의 코드 예는 다음과 같습니다.


14

C (gcc) , 26x20 = 520 25x19 = 475 23x17 = 391

#ifndef M            //
#define M(a,b)a##b   //
#define W(z,x)M(z,x) //
char*s,*S[]={"!!!!c",//
"8M !7! M8 878","77",//
"7!!MO887","788OM!!7"//
,"N7!78","7N87!"},r[5//
],*p=r;i=7;main(){for//
(;i--;)strstr(S[i],r)//
&&putchar("ITOJLSZ"[i//
]);}                 //
#endif               //
__attribute__((      //
constructor(__LINE__)//
))W(f,__LINE__)(){s= //
"                     \
";*p++=strlen(s)+12;}//

나는 최근에 GNU의 함수 속성과 가장 흥미롭게도 constructor속성에 대해 알게 되었기 때문에이 문제에 대한 나의 초기 접근 방식에서 내가 한 일을 좀 더 간결하게 구현할 수있게되었다.

아이디어의 추력은 이전과 같습니다. 문자열을 만들고 목록에서 검색하여 코드가 배치 된 테트리스 블록을 식별합니다. 이것은 각각 문자열에 문자를 추가하는 함수를 호출하여 수행됩니다. 합병증은 기능의 수가 다양하다는 것이 었습니다.

함수를 정의 attribute((constructor(x)))하면 함수가 실행되기 전에 함수가 main()입력 x되고 옵션 이 우선 순위입니다 (낮을수록 더 빨리 실행 됨). 따라서 함수 포인터가 필요하지 않으므로 매크로, 일부 선언 및 호출 체인을 삭제할 수 있습니다.

__LINE__우선 순위 레벨 0-100이 예약되어 있으므로 우선 순위에 사용 하는 것이 iffy입니다. 그러나 오류가 발생하지 않고 경고 만 발생하며 골프를 칠 때 충분합니다. 몇 가지 더 있습니까?

우선 순위를 전혀 사용하지 않기 위해 다른 열을 제거하는 데 도움이되었지만 실행 순서는 정의되지 않은 것 같습니다. (이 경우에는 반대이지만 다른 테스트는 결정적이지 않습니다.)

여기서 L v2의 예

더 오래되고 휴대가 용이 한 접근 방식

#ifndef M              //
#define M(a,b) a##b    //
#define W(z,x)M(z,x)   //
#define F W(f,__LINE__)//
#define A W(a,__LINE__)//
char r[5],*S[]={"####k"//
,";<<US##;",";##SU<<;",//
";;",";T<;#","<S #;# S"//
"< <;<","T;#;<"},*s,*p=//
r;i;typedef(*T)();T a17//
,a36,a55,a74;main(){for//
(a17(),a36&&a36(),a55&&//
a55(),a74&&a74();i--;) //
strstr(S[i],r)&&putchar//
("ILJOZTS"[i]);}i=7;   //
#endif                 //
F();T A=F;F(){s=       //
"                       \
";*p++=strlen(s)+12;}  //

내가이 사이트에서 해결 한 가장 좋아하는 문제 중 하나입니다.

나는 각 블록이 어떻게 든 자신의 좌표를 신성한 것으로 생각하면서 시작했습니다. 행을 사용하면 쉬우 며 다음과 __LINE__같이 문자열 리터럴의 길이를 사용하여 가로로 인접한 블록 수를 찾을 수 있습니다.

char*s=//char*s=//
"       ""       "
;        ;        

결과 문자열의 길이를 가져 와서 적절한 숫자로 나누면 너비가 있습니다. 슬프게도이 방법으로 블록 앞의 빈 공간을 볼 수 없습니다. 공백 만 같은 것들에 매우 드물게 문자열의 외부를 의미하지 않았기 때문에 나는 여전히 의심 문자열, 해결책이 될 것입니다 a+++ba+ ++b. 나는 간단히 그런 것을 고려했지만 유용한 것을 생각해 낼 수 없었습니다. 또 다른 가능성은 블록이 만나는 곳에서 식별자를 함께 "접착"하는 것입니다.

A  BA  B

이것이 여전히 흥미로운 해결책이 될 수 있다면 놀라지 않을 것입니다.

단순함에도 불구하고이 블록 조각을 기반으로하는 문자열 솔루션을 찾는 데 상당한 시간이 걸렸습니다.

s=//
"  \
";//

프래그먼트에 수평 이웃이없는 경우 두 번째 줄의 줄 바꿈은 백 슬래시로 이스케이프되어 길이 2의 문자열을 만듭니다. 그러나 이웃이있는 경우 백 슬래시는 대신 줄의 시작 부분에서 따옴표를 이스케이프합니다. 다음 블록 중 2 개 :

s=//s=//
"  \"  \
";//";//

이렇게하면 길이가 5 인 문자열 "\" "가 생성됩니다.

더 중요한 것은 블록 앞에 빈 공간을 감지하는 것입니다.

    s=//
    "  \
    ";//

다시, 줄 바꿈이 이스케이프되고 왼쪽에있는 빈 블록의 공백이 길이 6의 결과 문자열 ""에 포함됩니다.

전체적으로 걱정해야 할 7 가지 블록 구성 행이 있으며 모두 고유 한 길이의 문자열을 만듭니다.

2 "  "
---
s=//
"  \
";//

5 "  \"  "
---
s=//s=//
"  \"  \
";//";//

6 "      "
---
    s=//
    "  \
    ";//

9 "  \"      "
----
    s=//s=//
    "  \"  \
    ";//";//

10 "          "
---
        s=//
        "  \
        ";//

8 "  \"  \"  "
---
s=//s=//s=//
"  \"  \"  \
";//";//";//

11 "  \"  \"  \"  "
----
s=//s=//s=//s=//
"  \"  \"  \"  \
";//";//";//";//

최종 블록은 물론 짧은 길이를 갖지는 않지만 원칙은 블록 크기에 관계없이 동일합니다. 또한 너비를 감지하기위한 별도의 메커니즘이 필요하지 않다는 이점도 있습니다. 이 문자열의 길이에 해당하는 문자를 결과 문자열에 추가하면 19 개의 각 구성마다 고유 한 문자열이 생성되며, 모든 블록이 실행 된 후에 만 ​​적합한 목록과 비교하면됩니다.

이것이 분류되면 다음 큰 문제는 각 블록의 행을 "방문"하는 방법이었습니다. C에서는 함수 외부에서 수행 할 수있는 작업이 매우 제한적입니다. 또한 main()한 번만 나타나야합니다. 후자는 일부에 의해 쉽게 달성 #define되지만 후속 블록의 코드를 안에 main()넣으려면 최종 닫는 중괄호를 넣을 때를 아는 방법에 대한 문제가 있습니다. 결국, 우리는 실제로 얼마나 많은 행의 블록이 사용 될지 모릅니다. 따라서 우리는 main()정적이어야하고 나머지는 동적이어야합니다.

다른 블록 행이 자체 포함되어야하는 경우 함수 여야하지만 각 함수의 이름은 고유해야하고에서 호출 할 수있을만큼 예측 가능해야합니다 main(). 또한 실제로 어떤 함수가 호출되는지 알기위한 메커니즘이 필요합니다. 헬퍼 매크로는 고유 이름 생성을 해결합니다.

#define M(a,b) a##b     //
#define W(z,x)M(z,x)    //
#define F W(f,__LINE__) //
#define A W(a,__LINE__) //

호출 F하면 이름이 f로 시작하고 줄 번호로 끝나는 식별자가 생성됩니다. A솔루션의 두 번째 부분에 사용되는 접두사와 동일한 기능을 수행하지만 함수 포인터입니다. 우리는 네 가지 포인터를 선언합니다.

typedef(*T)();T a17,a36,a55,a74;

이들은 전역 변수로 선언되므로 편리하게 NULL로 설정됩니다. 나중에 각 블록 행에는 다음 코드가 있습니다.

F();T A=F;F()

먼저 함수를 선언하고 해당 함수를 가리키는 적절한 함수 포인터를 정의합니다 (전역을 한 번만 정의 할 수 있지만 이전 선언은 NULL로 초기화 된 경우에도 정의로 계산되지 않습니다). 기능. 이를 통해 main()NULL이 아닌 함수 포인터를 호출 할 수 있습니다 (a17은 절대 NULL이 아님).

a17(),a36&&a36(),a55&&a55(),a74&&a74()

그렇게하면 string을 빌드 r한 다음 문자열 테이블에서 찾은 다음 해당하는 문자가 출력됩니다.

유일하게 남아있는 트릭은 모호함을 피하거나 겹치는 문자열이 얽힐 수있을 때마다 일치시킬 문자열 목록이 단축되었다는 것입니다.

여기서 L v2의 예


6

x86 opcode (.com), 86 82 바이트

시험 장치:

org 100h
macro e {
db $F6,$04,$DF,$78,$13,$75,$08,$00,$C0,$40,$83,$C6,$52,$EB,$F1,$88
db $C2,$00,$D0,$00,$D0,$46,$EB,$E8,$05,$02,$40,$73,$ED,$E8,$26,$00
db $50,$08,$43,$4D,$2C,$0C,$1C,$15,$A5,$14,$10,$13,$3F,$27,$20,$0F
db $51,$1D,$29,$49,$49,$4A,$4A,$4A,$4A,$4C,$4C,$4C,$4C,$4F,$53,$53
db $54,$54,$54,$54,$5A,$5A,$5F,$AE,$75,$FD,$8A,$55,$12,$B4,$02,$CD
db $21,$C3
}

macro n { db 82 dup $20 }

macro s { db 10 }

n
e
s
n
e
s
e
e  

출처:

BOF:    ;mov bx, 100h
p:      test [si], byte $DF
        js _a ; exist
        jnz _b ; newline
_z:     add al, al
        inc ax
q:      add si, EOF-BOF
        jmp p
_b:     mov dl, al
        add al, dl
        add al, dl
        inc si
        jmp p
_a:     add ax, 4002h
        jnc q
        call y
        db 80,8,67,77,44,12,28,21,165,20,16,19,63,39,32,15,81,29,41
        db 'IIJJJJLLLLOSSTTTTZZ'
y:      pop di
        scasb
        jnz y+1
        mov dl,[di+18]
        mov ah,2
        int $21
        ret
EOF:

init AX = 0, SI = 100, BX = 0 참조 인 win7dos에서 실행


지원되는 환경의 수를 다소 줄이는 것이 편한 경우 SI = 100h로 가정하고 인덱싱에 BX 대신 해당 레지스터를 사용 mov bx, 100h하여 시작시 3 바이트를 절약하여 3 바이트를 절약 할 수 있습니다.
gastropner

@gastropner 완료를 내가 통지를하지 않았다 곳에 지점을 고정
l4m2
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.