내가 어렸을 때, 나는 Intellivision 게임 Advanced Dungeons and Dragons : Treasure of Tarmin을했다 . 3D 그래픽을 사용하면 충격적인 사실감으로 1 인칭 시점을 볼 수 있습니다.
그러나 나는 C-64를 얻었다. 그리고 화면 주위를 커서로 움직이고 Ctrl 키와 숫자로 색상을 설정하고 원하는 곳에 기호를두면 (왜 그렇게하지 bash
않을까요?) 40×25 문자 그리드에 그릴 수있었습니다 . 문자 집합에는 삼각형 구성 요소와 솔리드 블록 구성 요소가있었습니다. 그래서 나는 그 매체를 통해 그리드에서 자신의 원근을 렌더링하는 방법을 통해 추론 할 수있었습니다.
나는 이번 주에 “던전 건설 세트”에 관한 거의 3 십년 전의 나선 묶인 공책에서 발견했다.
( 업데이트 :주의 깊은 독자들은 이것이 기울어 진 부분에 잘 맞지 않는 것을 알 수 있습니다. 수정 된 숫자는 아래에 제공됩니다.)
타민의 보물은 격자에서 재생되었지만 벽 은 격자 사각형 의 가장자리 에만 존재했습니다 . 바이트가 무엇인지 알았을 때, 맵을 바이트로 만들면 맵의 각 사각형이 각 가장자리에 대해 네 가지 가능한 상태를 가질 수 있음을 깨달았습니다.
- 막힘
- 벽
- 문
- 다른 것?
나는 (어제 밤까지) 그것을 작성하지 않았다. 다른 사람들이 시도하는 것이 재미있을 것이라고 생각했습니다.
따라서 귀하의 작업은 2013 년 기술을 사용하여 내 (수정 된) 사양 을 구현하는 문자 모드 기반 미로 렌더러를 구현 하는 것입니다.
입력
스펙은 문에 대한 렌더링을 정의하지 않으므로 벽과 벽이 아닌 유일한 옵션 만 가정합니다. 간단히하기 위해 입력은 다음과 같은 문자열 줄로 구성된 맵입니다.
WN.. .N.. .N.. .N.. .N.E
W... .... .... ..S. ...E
W... .N.E W... .N.. ...E
W... .... .... .... ...E
W.S. ..S. ..S. ..S. ..SE
5×5 맵입니다. 왼쪽 상단 (1,1)는이 W
추정치와 N
노스 벽 세트를. 오른쪽 하단 (5,5)에는 S
바깥 쪽 E
벽 과 벽이 있습니다.
지도 내비게이션이 없으면 재미가 떨어집니다. 따라서 최소한 플레이어를 북쪽을 향한 (1,1)에 놓고 다음을 제공하십시오.
[F]orward, [B]ackward, turn [L]eft, turn [R]ight or [Q]uit?
각 단계에서 노트북 용지 사양에 정의 된대로 1 인칭 시점의 16×15 디스플레이를 출력합니다. 계산하지 않아도되도록 세 거리의 평평한 벽의 크기는 다음과 같습니다.
14x13 (directly in front of you; e.g. wall is in same cell)
8x7 (one step away)
6x5 (two steps away)
경사 벽의 경계 크기는 다음과 같습니다.
1x15 (your direct left or right; e.g. wall is in same cell)
3x13 (one step away)
1x7 (two steps away)
설명
-
인접한 셀은 공유 벽에 대해 동의하지 않을 수 있습니다. 따라서 정사각형의 남쪽 가장자리는 벽이 될 수 있지만 정사각형의 남쪽 가장자리는 막히지 않습니다. 원래 디자인에서 나는 이것을 특징으로 생각했습니다. 단방향 문이나 보이지 않는 벽과 같은 흥미로운 아이디어를 허용합니다. 이 단순화를 위해 동일한 규칙을 따르십시오. 탐색 및 렌더링의 경우, 사용자가 직면 한 방향으로 가장 가까운 셀의 가장자리 상태에만주의하십시오 .
-
“음영”으로보기가 훨씬 좋습니다. 따라서 전체 블록의 경우 유니 코드 2593 ▓ 및 2591 alternate를 대체하거나 사용
X
하고+
구현이 ASCII 인 경우 사용 하십시오. -
유니 코드 삼각형 문자 (25E2, 25E3 ◣, 25E4 ◤, 25E5 ◥)는이를 그리기위한 약간 불충분합니다. 음영 처리 된 변형이없는 것 외에도 고정 너비 글꼴에서도 문자의 너비 만 늘리고 전체 높이는 늘리지 않습니다. 내가 원하는 대각선에 전체 블록이나 슬래시 문자 또는 선택한 것을 그릴 수 있습니다. 색상을 통합하고 음영 대신 이러한 문자를 사용하는 흥미로운 창의적인 솔루션.
-
가장 바깥 쪽 벽이 연주 영역을 경계로 설정되어 있다고 가정 할 수 있으므로 미로 외부에 아무것도 렌더링하지 않아도됩니다. 사양보다 멀리 떨어진 벽은 무시되고 빈 공간 만 남습니다.
-
(1,1)에서 북쪽을 향하면 정면에서 보이는 벽의 음영은 DARK 여야합니다. 맵의 인접한 벽에 다른 음영을 적용하여 모든 벽이 존재하는 경우 밝은 벽은 절대 어두운 벽과 접하지 않습니다.
-
내가 원래 의도했던 것을 대각선 문자와 모두로 실제로 수행하는 C-64 구현은 다른 진입 기준보다 우선합니다. 🙂
예
위에 주어진 샘플 맵의 경우 …
남쪽을 향한 (1,3)에서 :
/
/+
/X+
/XX+
/XXX+
+++++XXXXXX+XXX+
+++++XXXXXX+XXX+
+++++XXXXXX+XXX+
+++++XXXXXX+XXX+
+++++XXXXXX+XXX+
\XXX+
\XX+
\X+
\+
\
남쪽을 향한 (3,2)에서 :
/* blank line */
X /
X /+
X /++
X +++
X +++
X +++
X +++
X +++
X +++
X +++
X \++
X \+
X \
/* blank line */
동쪽을 향한 (3,2)에서 :
/* blank line */
/
/X
/XX
XXX
+++++XXXXXX+XXX+
+++++XXXXXX+XXX+
+++++XXXXXX+XXX+
+++++XXXXXX+XXX+
+++++XXXXXX+XXX+
XXX
\XX
\X
\
/* blank line */
북쪽을 향한 (2,3)에서 :
/
++++++++++++++X
++++++++++++++X
++++++++++++++X
++++++++++++++X
X++++++++++++++X
X++++++++++++++X
X++++++++++++++X
X++++++++++++++X
X++++++++++++++X
++++++++++++++X
++++++++++++++X
++++++++++++++X
++++++++++++++X
\
답변
코모도어 64 기본
남자, 재미 있었어. 그리고 열심히. C64 Basic은 거의 논쟁의 여지가 없으며, print
던전을 렌더링하기 위해 화면이 이미 만들어져 있기 때문에 디버깅을 사용할 수도 없습니다 . 와 같은 코드를 작성할 때 재미 있다는 것을 알고 있습니다 55250 goto 55110
. Dijkstra가 나를 죽일 것입니다.
이 프로그램은 두 가지 색상과 대각선 문자를 사용합니다.
말할 것도없이 나는 골프를하지 않았다. 결국 코드 챌린지 라고 합니다. 그것은의 7183 당신이 관심이 있다면 바이트.
속도가 느립니다. 기본 속도에서는 장면을 렌더링하는 데 몇 초가 걸립니다. 최대지도 크기는 10 x 10이지만 편집 선 120을 통해 변경할 수 있습니다.
VICE 에뮬레이터를 사용하여 이것을 개발하고 테스트했습니다 . 아래 코드는 ASCII로 표시되므로 PETSCII가 이동 했음을 의미 합니다. 그러나 맵을 입력 할 때는 시프트되지 않은 PETSCII 를 사용해야합니다 .
스크린 샷 :
암호:
10 rem c64 dungeon construction set.
20 rem enter using lowercase mode
99 rem DDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDD
100 rem initialisation
110 poke 53272,21
115 poke 53280,0
120 dim m%(10,10)
121 dim di$(3),wa$(1),ma%(2,2)
122 di$(0)="north"
123 di$(1)="east "
124 di$(2)="south"
125 di$(3)="west "
126 wa$(1)="-wall"
127 wa$(0)=" "
130 x=0:y=0:di=0:xs=0:ys=0:wa=0
134 rem read map
135 print "input map"
140 l$="":input l$
150 if len(l$)=0 goto 250
160 cz=0
170 for i=1 to len(l$)
180 c$=mid$(l$,i,1)
190 if c$="n" then cz=cz or 8
200 if c$="e" then cz=cz or 4
205 if c$="s" then cz=cz or 2
210 if c$="w" then cz=cz or 1
215 if c$=" " then m%(x,y)=cz:cz=0:x=x+1
220 if x>=xs then xs=x
225 next
230 m%(x,y)=cz:x=0:y=y+1
240 goto 140
250 rem come from 150
260 print chr$(147)
265 ys=y:xs=xs+1
270 x=0:y=0
500 rem loop
510 gosub 1000: rem status
515 gosub 2000: rem render
520 gosub 55000: rem input
530 goto 500
1000 rem display current (x,y) value
1010 sx=5
1020 sy=17
1030 sl$=" "
1035 sw=14
1040 gosub 63900
1050 cz=m%(x,y)
1060 sx=5:sl$=".":if cz and 8 then sl$="n"
1065 gosub 63900
1070 sx=6:sl$=".":if cz and 4 then sl$="e"
1075 gosub 63900
1080 sx=7:sl$=".":if cz and 2 then sl$="s"
1085 gosub 63900
1090 sx=8:sl$=".":if cz and 1 then sl$="w"
1095 gosub 63900
1100 return
2000 rem render dungeon
2010 rem DDDDDDDDDDDDDD
2020 rem clear area
2030 sw=14:sz=32
2040 for sy=0 to 15
2050 for sx=0 to 16
2060 gosub 63950
2070 next
2080 next
2090 rem find cells / reorient sw
2100 rem store in ma% - we're at (0,1)
2110 sx=x:sy=y
2113 co=di+x+y and 1
2115 for ty=0 to 2
2120 gosub 59800:rem left/right sx/sy
2125 ma%(1,ty)=0
2126 if sx>=0 and sy>=0 and sx<xs and sy<ys then ma%(1,ty)=m%(sx,sy)
2130 ma%(0,ty)=rl
2140 ma%(2,ty)=rr
2150 gosub 59900:rem advance
2160 next
2170 rem draw back walls
2180 sa=ma%(1,2):gosub 59700
2190 if rf=0 goto 2245
2195 sw=14-11*co:sz=160
2200 for sy=5 to 9
2210 for sx=5 to 10
2220 gosub 63950
2230 next
2240 next
2245 sw=3:if co=1 then sw=14
2250 for de=0 to 2 step 2
2260 sa=ma%(de,2):gosub 59700
2270 if rf=0 goto 2350
2280 for sx=de*5.5 to 4+de*5.5
2290 for sy=5 to 9
2300 gosub 63950
2310 next
2340 next
2350 next
2360 rem 1,2 left wall
2370 sa=ma%(1,2):gosub 59700
2380 if rl=0 goto 2430
2390 sx=4:sz=160
2400 for sy=5 to 9:gosub 63950:next
2410 sy=4:sz=223:gosub 63950
2420 sy=10:sz=105:gosub 63950
2430 rem 1,2 right wall
2440 if rr=0 goto 2490
2450 sx=11:sz=160
2460 for sy=5 to 9:gosub 63950:next
2470 sy=4:sz=233:gosub 63950
2480 sy=10:sz=95:gosub 63950
2490 rem 1,1 back wall
2500 sa=ma%(1,1):gosub 59700
2510 sz=160
2520 sw=14:if co=1 then sw=3
2520 if rf=0 goto 2580
2530 for sy=4 to 10
2540 for sx=4 to 11
2550 gosub 63950
2560 next
2570 next
2580 rem (0-2),1 back walls
2590 sw=14:if co=1 then sw=3
2600 for de=0 to 2 step 2
2610 sa=ma%(de,1):gosub 59700
2620 if rf=0 goto 2680
2630 for sx=de*6 to 3+de*6
2640 for sy=4 to 10
2650 gosub 63950
2660 next
2670 next
2680 next
2690 rem 1,1 left side wall
2700 sw=14:if co=1 then sw=3
2710 sa=ma%(1,1):gosub 59700
2720 if rl=0 goto 2760
2730 for sx=1 to 3
2735 sy=sx:sz=223:gosub 63950
2736 sy=14-sx:sz=105:gosub 63950
2737 sz=160
2740 for sy=1+sx to 13-sx:gosub 63950:next
2750 next
2760 rem 1,1 right side wall
2770 if rr=0 goto 2850
2780 for qx=1 to 3
2790 sx=15-qx
2800 sy=qx:sz=233:gosub 63950
2810 sy=14-qx:sz=95:gosub 63950
2820 sz=160
2830 for sy=1+qx to 13-qx:gosub 63950:next
2840 next
2850 rem 0,1 back wall
2860 sa=ma%(1,0):gosub 59700
2870 if rf=0 goto 2930
2880 for sy=1 to 13
2890 for sx=1 to 14
2900 gosub 63950
2910 next
2920 next
2930 rem (0,2)-0 back walls
2940 sw=3:if co=1 then sw=14
2950 for de=0 to 2 step 2
2960 sa=ma%(de,0):gosub 59700
2970 if rf=0 goto 3000
2980 sx=de*7.5
2990 for sy=1 to 13:gosub 63950:next
3000 next
3010 rem (1,0) left side wall
3020 sa=ma%(1,0):gosub 59700
3030 if rl=0 goto 3080
3040 sx=0:sy=0:sz=223:gosub 63950
3050 sy=14:sz=105:gosub 63950
3060 sz=160
3070 for sy=1 to 13:gosub 63950:next
3080 rem (1,0) right side wall
3085 if rr=0 goto 3130
3090 sx=15:sy=0:sz=233:gosub 63950
3100 sy=14:sz=95:gosub 63950
3110 sz=160
3120 for sy=1 to 13:gosub 63950:next
3130 rem done
3140 return
55000 rem ask for prompt & handle input
55010 sx=0:sy=20:gosub 63850
55013 print "at";x+1;y+1;"going ";di$(di);" size";xs;ys;wa$(wa)
55020 print "{f}rwd {b}kwd {l}eft {r}ight {q}uit"
55030 input c$
55040 if c$="q" goto 63999
55050 if c$="f" then dm=1:goto 55100
55060 if c$="b" then dm=-1:goto 55100
55070 if c$="l" then di=(di-1)and 3
55080 if c$="r" then di=(di+1)and 3
55090 return
55100 goto 55200:rem check walls
55110 if di=0 then y=y-dm
55120 if di=1 then x=x+dm
55130 if di=2 then y=y+dm
55140 if di=3 then x=x-dm
55145 wa=0
55146 if y>=ys then y=0
55147 if y<0 then y=ys-1
55148 if x>=xs then x=0
55149 if x<0 then x=xs-1
55150 return
55200 rem check walls
55205 cz=m%(x,y)
55207 if dm=-1 goto 55280
55210 if (di=0) and (cz and 8) goto 55260
55220 if (di=1) and (cz and 4) goto 55260
55230 if (di=2) and (cz and 2) goto 55260
55240 if (di=3) and (cz and 1) goto 55260
55250 goto 55110
55260 wa=1
55270 return : rem wall in the way
55280 rem backward
55290 if (di=2) and (cz and 8) goto 55260
55300 if (di=3) and (cz and 4) goto 55260
55310 if (di=0) and (cz and 2) goto 55260
55320 if (di=1) and (cz and 1) goto 55260
55330 goto 55110
59700 rem return front/back/left/right
59710 rem given sa and d
59720 sn=0:if sa and 8 then sn=1
59725 se=0:if sa and 4 then se=1
59730 ss=0:if sa and 2 then ss=1
59735 zw=0:if sa and 1 then zw=1
59740 if di=0 then rf=sn:rr=se:rb=ss:rl=zw
59745 if di=1 then rf=se:rr=ss:rb=zw:rl=sn
59750 if di=2 then rf=ss:rr=zw:rb=sn:rl=se
59755 if di=3 then rf=zw:rr=sn:rb=se:rl=ss
59760 return
59800 rem return left/right from sx/sy/d
59810 if di=0 then ly=sy:ry=sy:lx=sx-1:rx=sx+1
59820 if di=1 then lx=sx:rx=sx:ly=sy-1:ry=sy+1
59830 if di=2 then ly=sy:ry=sy:lx=sx+1:rx=sx-1
59840 if di=3 then lx=sx:rx=sx:ly=sy+1:ry=sy-1
59850 rl=0:rr=0
59860 if lx<0 or lx>=xs or ly<0 or ly>=ys goto 59880
59870 rl=m%(lx,ly)
59880 if rx<0 or rx>=xs or ry<0 or ry>=ys goto 59895
59890 rr=m%(rx,ry)
59895 return
59900 rem step forward
59910 if di=0 then sy=sy-1:rem N
59920 if di=1 then sx=sx+1:rem E
59930 if di=2 then sy=sy+1:rem S
59940 if di=3 then sx=sx-1:rem W
59950 return
63850 rem set cursor position
63851 rem sx=x sy=y
63860 poke 781,sy
63870 poke 782,sx
63880 poke 783,0
63890 sys 65520
63895 return
63900 rem write str to screen
63901 rem sl$ = string
63910 gosub 63850
63920 print sl$;
63930 return
63950 rem write chr to screen
63951 rem sx = x coordinate
63952 rem sy = y coordinate
63953 rem sz = character code
63954 rem sw = color
63950 sv=sx+sy*40
63960 poke 1024+sv,sz
63970 poke 55296+sv,sw
63980 return
63998 rem quit program
63999 print chr$(147):end
테이프 이미지 : 여기에서 다운로드하십시오 .
예를 들면 다음과 같습니다.
답변
(왜 그렇게하지
bash
못하게합니까?)
나는 지금 막 가야했다.
배쉬, 12743 자
#!/bin/bash
IFS=
declare -a term
typeset -i term[0] term[1]
IFS=' ' read -a term <<< `stty size`
front[0]='\e[2;2H██████████████
\e[3;2H██████████████
\e[4;2H██████████████
\e[5;2H██████████████
\e[6;2H██████████████
\e[7;2H██████████████
\e[8;2H██████████████
\e[9;2H██████████████
\e[10;2H██████████████
\e[11;2H██████████████
\e[12;2H██████████████
\e[13;2H██████████████
\e[14;2H██████████████'
front[1]='\e[5;5H████████
\e[6;5H████████
\e[7;5H████████
\e[8;5H████████
\e[9;5H████████
\e[10;5H████████
\e[11;5H████████'
front[2]='\e[6;6H██████
\e[7;6H██████
\e[8;6H██████
\e[9;6H██████
\e[10;6H██████'
lfront[0]='\e[2;1H█
\e[3;1H█
\e[4;1H█
\e[5;1H█
\e[6;1H█
\e[7;1H█
\e[8;1H█
\e[9;1H█
\e[10;1H█
\e[11;1H█
\e[12;1H█
\e[13;1H█
\e[14;1H█'
lfront[1]='\e[5;1H████
\e[6;1H████
\e[7;1H████
\e[8;1H████
\e[9;1H████
\e[10;1H████
\e[11;1H████'
lfront[2]='\e[6;1H█████
\e[7;1H█████
\e[8;1H█████
\e[9;1H█████
\e[10;1H█████'
rfront[0]='\e[2;16H█
\e[3;16H█
\e[4;16H█
\e[5;16H█
\e[6;16H█
\e[7;16H█
\e[8;16H█
\e[9;16H█
\e[10;16H█
\e[11;16H█
\e[12;16H█
\e[13;16H█
\e[14;16H█'
rfront[1]='\e[5;13H████
\e[6;13H████
\e[7;13H████
\e[8;13H████
\e[9;13H████
\e[10;13H████
\e[11;13H████'
rfront[2]='\e[6;12H█████
\e[7;12H█████
\e[8;12H█████
\e[9;12H█████
\e[10;12H█████'
left[0]='\e[1;1H▙
\e[2;1H█
\e[3;1H█
\e[4;1H█
\e[5;1H█
\e[6;1H█
\e[7;1H█
\e[8;1H█
\e[9;1H█
\e[10;1H█
\e[11;1H█
\e[12;1H█
\e[13;1H█
\e[14;1H█
\e[15;1H▛'
left[1]='\e[2;2H▙
\e[3;2H█▙
\e[4;2H██▙
\e[5;2H███
\e[6;2H███
\e[7;2H███
\e[8;2H███
\e[9;2H███
\e[10;2H███
\e[11;2H███
\e[12;2H██▛
\e[13;2H█▛
\e[14;2H▛'
left[2]='\e[5;5H▙
\e[6;5H█
\e[7;5H█
\e[8;5H█
\e[9;5H█
\e[10;5H█
\e[11;5H▛'
right[0]='\e[1;16H▟
\e[2;16H█
\e[3;16H█
\e[4;16H█
\e[5;16H█
\e[6;16H█
\e[7;16H█
\e[8;16H█
\e[9;16H█
\e[10;16H█
\e[11;16H█
\e[12;16H█
\e[13;16H█
\e[14;16H█
\e[15;16H▜'
right[1]='\e[2;13H ▟
\e[3;13H ▟█
\e[4;13H▟██
\e[5;13H███
\e[6;13H███
\e[7;13H███
\e[8;13H███
\e[9;13H███
\e[10;13H███
\e[11;13H███
\e[12;13H▜██
\e[13;13H ▜█
\e[14;13H ▜'
right[2]='\e[5;12H▟
\e[6;12H█
\e[7;12H█
\e[8;12H█
\e[9;12H█
\e[10;12H█
\e[11;12H▜'
echo -e "\e[2J"
# Read map
typeset -i cout
cout=0
echo "Please input your map!"
echo "Please input the next row (or leave it blank if you're finished!)"
read input
declare -A map
typeset -i xlen ylen
ylen=0
until [ -z $input ]
do
IFS=' ' read -a inputmap <<< "$input"
xlen=${#inputmap[*]}
let ylen++
for index in "${!inputmap[@]}"
do
typeset -i map[$index,$cout]
map[$index,$cout]=0
el=${inputmap[index]}
if [[ $el == W??? ]]
then
let "map[$index,$cout]|=1"
fi
if [[ $el == ?N?? ]]
then
let "map[$index,$cout]|=2"
fi
if [[ $el == ??S? ]]
then
let "map[$index,$cout]|=4"
fi
if [[ $el == ???E ]]
then
let "map[$index,$cout]|=8"
fi
done
echo "Please input the next row (or leave it blank if you're finished!)"
read input
cout+=1
done
echo -ne "\e[2J"
typeset -i dir x y
dir=0
x=0
y=0
move() {
if ((dir == 0)) && ( ((${map[$x,$y]} & 2)) || ((y == 0)) )
then
return 1
elif ((dir == 1)) && ( ((${map[$x,$y]} & 8)) || (($x == $xlen)) )
then
return 1
elif ((dir == 2)) && ( ((${map[$x,$y]} & 4)) || ((y == $ylen)) )
then
return 1
elif ((dir == 3)) && ( ((${map[$x,$y]} & 1)) || ((x == 0)) )
then
return 1
fi
x=$1
y=$2
}
input=
until [[ $input == [qQ] ]]
do
if [[ $input == [DlL] ]]
then
let dir-=1
if (( dir == -1 ))
then
dir=3
fi
elif [[ $input == [CrR] ]]
then
let dir+=1
if (( dir == 4 ))
then
dir=0
fi
elif [[ $input == [AfF] ]]
then
if (( dir == 0 ))
then
move $x $(( y-1 ))
elif (( dir == 1 ))
then
move $(( x+1 )) $y
elif (( dir == 2 ))
then
move $x $(( y+1 ))
elif (( dir == 3 ))
then
move $(( x-1 )) $y
fi
elif [[ $input == [bB] ]]
then
if (( dir == 0 ))
then
dir=2
move $x $(( y+1 ))
dir=0
elif (( dir == 1 ))
then
dir=3
move $(( x-1 )) $y
dir=1
elif (( dir == 2 ))
then
dir=0
move $x $(( y-1 ))
dir=2
elif (( dir == 3 ))
then
dir=1
move $(( x+1 )) $y
dir=3
fi
fi
echo -ne "\e[2J"
echo -ne "\e[16;1Hd=$dir; x=$x; y=$y\e[48;5;29m"
for (( y2=1; y2 <= 15; y2++ ))
do
echo -ne "\e[$y2;16H\e[1K"
done
if (( dir == 0 ))
then
for (( y2=(y-2); y2 <= y; y2++ ))
do
if (( y2 < 0 )); then continue; fi
let i=y-y2
if (( x > 0 )) && (( ${map[$((x-1)),$y2]} & 2 ))
then
if (( ((x-1) + y2) & 1 ))
then
echo -ne "\e[38;5;40m"
else
echo -ne "\e[38;5;28m"
fi
echo -ne ${lfront[$i]}
fi
if (( (x+1) < xlen )) && (( ${map[$((x+1)),$y2]} & 2 ))
then
if (( ((x-1) + y2) & 1 ))
then
echo -ne "\e[38;5;40m"
else
echo -ne "\e[38;5;28m"
fi
echo -ne ${rfront[$i]}
fi
if (( ${map[$x,$y2]} & 1 ))
then
if (( (x + y2) & 1 ))
then
echo -ne "\e[38;5;28m"
else
echo -ne "\e[38;5;40m"
fi
echo -ne ${left[$i]}
fi
if (( ${map[$x,$y2]} & 8 ))
then
if (( (x + y2) & 1 ))
then
echo -ne "\e[38;5;28m"
else
echo -ne "\e[38;5;40m"
fi
echo -ne ${right[$i]}
fi
if (( ${map[$x,$y2]} & 2 ))
then
if (( (x + y2) & 1 ))
then
echo -ne "\e[38;5;40m"
else
echo -ne "\e[38;5;28m"
fi
echo -ne ${front[$i]}
fi
done
elif (( dir == 1 ))
then
for (( x2=x+2; x2 >= x; x2-- ))
do
if (( x2 > 16 )) || (( x2 >= xlen )); then continue; fi
let i=x2-x
if (( y > 0 )) && (( ${map[$x2,$((y-1))]} & 8 ))
then
if (( (x2 + (y-1)) & 1 ))
then
echo -ne "\e[38;5;28m"
else
echo -ne "\e[38;5;40m"
fi
echo -ne ${lfront[$i]}
fi
if (( (y+1) < ylen )) && (( ${map[$x2,$((y+1))]} & 8 ))
then
if (( (x2 + (y-1)) & 1 ))
then
echo -ne "\e[38;5;28m"
else
echo -ne "\e[38;5;40m"
fi
echo -ne ${rfront[$i]}
fi
if (( ${map[$x2,$y]} & 2 ))
then
if (( (x2 + y) & 1 ))
then
echo -ne "\e[38;5;40m"
else
echo -ne "\e[38;5;28m"
fi
echo -ne ${left[$i]}
fi
if (( ${map[$x2,$y]} & 4 ))
then
if (( (x2 + y) & 1 ))
then
echo -ne "\e[38;5;40m"
else
echo -ne "\e[38;5;28m"
fi
echo -ne ${right[$i]}
fi
if (( ${map[$x2,$y]} & 8 ))
then
if (( (x2 + y) & 1 ))
then
echo -ne "\e[38;5;28m"
else
echo -ne "\e[38;5;40m"
fi
echo -ne ${front[$i]}
fi
done
elif (( dir == 2 ))
then
for (( y2=(y+2); y2 >= y; y2-- ))
do
if (( y2 > 15 )) || (( y2 >= ylen )); then continue; fi
let i=y2-y
if (( x > 0 )) && (( ${map[$((x-1)),$y2]} & 4 ))
then
if (( ((x-1) + y2) & 1 ))
then
echo -ne "\e[38;5;40m"
else
echo -ne "\e[38;5;28m"
fi
echo -ne ${rfront[$i]}
fi
if (( (x+1) < xlen )) && (( ${map[$((x+1)),$y2]} & 4 ))
then
if (( ((x+1) + y2) & 1 ))
then
echo -ne "\e[38;5;40m"
else
echo -ne "\e[38;5;28m"
fi
echo -ne ${lfront[$i]}
fi
if (( ${map[$x,$y2]} & 8 ))
then
if (( (x + y2) & 1 ))
then
echo -ne "\e[38;5;28m"
else
echo -ne "\e[38;5;40m"
fi
echo -ne ${left[$i]}
fi
if (( ${map[$x,$y2]} & 1 ))
then
if (( (x + y2) & 1 ))
then
echo -ne "\e[38;5;28m"
else
echo -ne "\e[38;5;40m"
fi
echo -ne ${right[$i]}
fi
if (( ${map[$x,$y2]} & 4 ))
then
if (( (x + y2) & 1 ))
then
echo -ne "\e[38;5;40m"
else
echo -ne "\e[38;5;28m"
fi
echo -ne ${front[$i]}
fi
done
elif (( dir == 3 ))
then
for (( x2=(x-2); x2 <= x; x2++ ))
do
if (( x2 < 0 )); then continue; fi
let i=x-x2
if (( y > 0 )) && (( ${map[$x2,$((y-1))]} & 1 ))
then
if (( (x2 + (y-1)) & 1 ))
then
echo -ne "\e[38;5;28m"
else
echo -ne "\e[38;5;40m"
fi
echo -ne ${rfront[$i]}
fi
if (( (y+1) < ylen )) && (( ${map[$x2,$((y+1))]} & 1 ))
then
if (( (x2 + (y+1)) & 1 ))
then
echo -ne "\e[38;5;28m"
else
echo -ne "\e[38;5;40m"
fi
echo -ne ${lfront[$i]}
fi
if (( ${map[$x2,$y]} & 4 ))
then
if (( (x2 + y) & 1 ))
then
echo -ne "\e[38;5;40m"
else
echo -ne "\e[38;5;28m"
fi
echo -ne ${left[$i]}
fi
if (( ${map[$x2,$y]} & 2 ))
then
if (( (x2 + y) & 1 ))
then
echo -ne "\e[38;5;40m"
else
echo -ne "\e[38;5;28m"
fi
echo -ne ${right[$i]}
fi
if (( ${map[$x2,$y]} & 1 ))
then
if (( (x2 + y) & 1 ))
then
echo -ne "\e[38;5;28m"
else
echo -ne "\e[38;5;40m"
fi
echo -ne ${front[$i]}
fi
done
fi
echo -ne "\e[0m"
echo -ne "\e[${term[0]};0H[F]orward, [B]ackward, turn [L]eft, turn [R]ight or [Q]uit?"
read -n 1 input
done
echo
이것이 내가 한 첫 번째 작업 bash
은 몇 가지 명령을 함께 파이핑하는 것 이상이라는 것을 명심하십시오 . 모든 벽을 하드 코딩하지 않았다면 아마도 상당히 많이 줄일 수 있지만 더 쉬워 보였습니다. 일관성이 없습니다. 각 사각형의 바이트 형식은 끔찍한 방식으로 선택됩니다. 그러나 작동합니다.
나는 심지어 화살표 키를 통한 움직임에 대한 지원을 추가했습니다 🙂
다음은 샘플 입력에 대한 스크린 샷입니다 (내지도는 (0 | 0)에서 시작합니다).
네 번째 것 외에도 샘플 샘플처럼 보입니다 (OP에 대한 내 의견 참조).
이 스크린 샷은 256 색을 지원하는 urxvt v9.15에서 찍은 것으로, 88 색 터미널에서는 엉망이 될 수 있으며 유니 코드를 지원하지 않는 터미널은 전혀 작동하지 않습니다. 내가 사용한 글꼴 은 Adobe의 Source Code Pro 였습니다 .
답변
다음은 Python 3의 내 버전입니다. 3k 문자와 비슷하며 약간의 노력으로 조금 더 작아 질 수 있습니다 (제거 할 수있는 많은 공백이 있습니다).
현재 +X/\
그리기 문자로 사용되지만 너비가 고정 된 글꼴을 사용하여 올바르게 렌더링하는 경우 유니 코드 문자로 그리도록 설정되어 있습니다. 이 기능은 사용하지 않지만 서로 다른 벽의 각진 부분에 별도의 타일 사용을 지원합니다. 또한 천장, 바닥 및 “먼”타일을 제공 할 수 있으며 플레이어가 동쪽 또는 서쪽 대 북쪽 또는 남쪽을 향할 때 다른 타일을 사용할 수 있습니다. 아아, 이것은 결코 좋아 보지 않았으므로 아마도 모두 비어 있어야합니다 (또는 같은 단단한 것 █
).
아아, 내 Windows 7 시스템에서 전체 블록 문자 세트 (예 : ▜
및 ▟
)가 있는 고정 폭 글꼴을 찾으려고 끔찍한 시간을 보냈습니다 . 내가 찾은 대부분은 cmd
어떤 이유로 콘솔 에서 사용할 수 없었습니다 (아마도 완전히 공백이 아니기 때문일 수 있습니다). 콘솔이 더 기능적이라고 생각되면 파일 상단 근처에서 주석 처리 한 대체 문자 세트를 사용해보십시오. 단 두 가지 색상으로도 나쁘지 않습니다. 그것은 천장과 바닥과 대부분 투명한 벽으로 채워져 있습니다.
코드:
from itertools import product as p
r=range
cs=r"+X//\\//\\ " #" ░▛▛▜▜▟▟▙▙██████"
shapes=[(1,[(x,y,0)for x,y in p(r(5),r(5,10))]),
(0,[(x,y,0)for x,y in p(r(5,11),r(5,10))]),
(1,[(x,y,0)for x,y in p(r(11,16),r(5,10))]),
(1,[(4,4,4),(4,10,6)]+[(4,y,0)for y in r(5,10)]),
(1,[(11,4,2),(11,10,8)]+[(11,y,0)for y in r(5,10)]),
(0,[(x,y,0)for x,y in p(r(4),r(4,11))]),
(1,[(x,y,0)for x,y in p(r(4,12),r(4,11))]),
(0,[(x,y,0)for x,y in p(r(12,16),r(4,11))]),
(0,[(1,1,4),(2,2,4),(3,3,4),(1,13,6),(2,12,6),(3,11,6)]+
[(x,y,0)for x,y in p(r(1,4),r(2,14)) if x<y<14-x]),
(0,[(14,1,2),(13,2,2),(12,3,2),(14,13,8),(13,12,8),(12,11,8)]+
[(x,y,0)for x,y in p(r(12,15),r(2,14)) if 15-x<y<x-1]),
(1,[(0,y,0) for y in r(1,14)]),
(0,[(x,y,0) for x,y in p(r(1,15),r(1,14))]),
(1,[(15,y,0) for y in r(1,14)]),
(1,[(0,0,4),(0,14,6)]+[(0,y,0)for y in r(1,14)]),
(1,[(15,0,2),(15,14,8)]+[(15,y,0) for y in r(1,14)])]
def rr(s):
for r in s:print("".join(r))
def dw(s,a,p,d):
for i,r in enumerate(s):r[:]=cs[10+i//5*2+d%2]*16
for w,(pl,sh) in zip(a,shapes):
if w:
for x,y,c in sh:
s[y][x]=cs[c+(p+d+pl)%2]
dx=[1,0,-1,0]
def ga(x,y,d,m):
fx=dx[d];fy=lx=dx[d-1];ly=dx[d-2]
return [m[y+2*fy+ly][x+2*fx+lx][d],m[y+2*fy][x+2*fx][d],
m[y+2*fy-ly][x+2*fx-lx][d],m[y+2*fy][x+2*fx][d-1],
m[y+2*fy][x+2*fx][d-3],m[y+fy+ly][x+fx+lx][d],
m[y+fy][x+fx][d],m[y+fy-ly][x+fx-lx][d],
m[y+fy][x+fx][d-1],m[y+fy][x+fx][d-3],
m[y+ly][x+lx][d],m[y][x][d],
m[y-ly][x-lx][d],m[y][x][d-1],m[y][x][d-3]]
def rd():
l=input();
while l!="":
if "\n" in l:yield from l.split("\n")
else:yield l
l=input()
def rm():
m=[[[d in s for d in"ESWN"]for s in r.strip().split()]+[[1]*4]*2
for r in rd()]
return m+[[[1]*4 for _ in m[0]]]*2
def cl():print("\n"*30)
def gl():
print("Enter map, followed by a blank line.")
x=y=0;d=3;m=rm();mv="";s=[[""]*16 for _ in r(15)]
while True:
cl();dw(s,ga(x,y,d,m),x+y,d);rr(s)
print("X:",x+1,"Y:",y+1,"Facing:","ESWN"[d])
if mv:print("Last move:",mv)
mv=input("[FBLRQ]? ").upper()
if mv=="F":
if not m[y][x][d]:x+=dx[d];y+=dx[d-1]
else:mv+=" (Blocked)"
elif mv=="B":
if not m[y][x][d-2]:x+=dx[d-2];y+=dx[d-3]
else:mv+=" (Blocked)"
elif mv=="L":d=(d-1)%4
elif mv=="R":d=(d+1)%4
elif mv=="Q":break
else:mv="I didn't understand %r."%mv
gl()
문자 세트는 파일 상단 근처에 지정됩니다. 문자의 순서는 다음과 같습니다.
- 심지어 패리티 벽
- 홀수 패리티 벽
- 패리티 상단 오른쪽 벽 각도 (예 :
/
벽 아래) - 홀수 패리티 오른쪽 상단 벽 각도
- 패리티 상단 왼쪽 벽 각도
- 홀수 패리티 왼쪽 상단 벽 각도
- 패리티 하단 오른쪽 벽 각도
- 홀수 패리티 오른쪽 아래 벽 각도
- 짝수 패리티 왼쪽 하단 벽 각도
- 홀수 패리티 왼쪽 하단 벽 각도
- E / W를 향한 천장
- 천장 직면 N / S
- 수평선이 E / W를 향함 (벽이없는 경우 화면 중앙)
- 수평선 대면 N / S
- 바닥면 E / W
- 바닥면 N / S
다음과 같은 패턴으로 게임에서 렌더링해야 할 15 개의 벽이 있습니다 ( V
플레이어의 위치 및 시야각 표시).
_ _ _
_|_|_
_|_|_
|V|
15 개의 벽에 사용 된 타일이 shapes
목록에 정의되어 있습니다. 2 개의 튜플 목록입니다. 튜플의 첫 번째 값은 벽의 “패리티”를 나타내며, 벽 0
은 캐릭터 바로 앞에 벽과 동일한 문자로 그려야 1
하며 대체 패턴 (예 : +
vs X
) 이어야한다는 것을 나타냅니다 . 두 번째 값은 x,y,t
한 픽셀의 화면 좌표와 타일 인덱스를 나타내는 튜플 목록입니다 (홀수 패리티로 렌더링되는 벽 1
은 이러한 각 인덱스에 추가됨). 모양은 거리에 따라 순서가 정해 지므로 처음 3 개는 캐릭터보다 2 타일 앞의 수직 벽, 2 개의 타일 2 개 앞의 타일 등을 나타냅니다.
기능은 다음과 같습니다.
rr
: 화면을 “렌더링”합니다 (스크린 버퍼에 타일을 인쇄하여).dw
: 제공된 스크린 버퍼에 “벽 그리기”. 이것은 painters 알고리즘을 사용하므로 가장 먼 벽이 먼저 그려지고 더 가까운 벽으로 덮여있을 수 있습니다.ga
: “get area”는 주어진 맵 위치와 마주 보는 벽이 불투명 한 부울 값 목록을 반환합니다.rd
: “읽기”,지도를 읽고 선을 생성하는 생성기. IDLE의 콘솔은 한 번에 한 줄을 입력하지 않고 여러 줄 입력을 붙여 넣을 때 이상한 일을하기 때문에 필요합니다.rm
: “지도 읽기”는지도를m[y][x][d]
(d=0
동쪽과d=1
남쪽으로) 색인화 된 부울 목록으로 구문 분석합니다 . 또한 다른 코드에서 인덱스 오류를 피하기 위해 두 행과 두 열의 패딩 사각형을 추가합니다.cl
: 출력을 “지우십시오”(대부분의 콘솔 상단에서 이전보기를 스크롤하기에 충분한 줄 바꿈을 작성하여).gl
: “game loop”, 입력이 수집되고 위의 것들이 호출됩니다.
몇 가지 “스크린 샷”:
시작 위치 :
\
+XXXXXXXXXXXXXX+
+XXXXXXXXXXXXXX+
+XXXXXXXXXXXXXX+
+XXXXXXXXXXXXXX+
+XXXXXXXXXXXXXX+
+XXXXXXXXXXXXXX+
+XXXXXXXXXXXXXX+
+XXXXXXXXXXXXXX+
+XXXXXXXXXXXXXX+
+XXXXXXXXXXXXXX+
+XXXXXXXXXXXXXX+
+XXXXXXXXXXXXXX+
+XXXXXXXXXXXXXX+
/
X: 1 Y: 1 Facing: N
[FBLRQ]?
북쪽 벽을 따라 보면 :
\
X\
X+\
X++\
X+++\
X+++X
X+++X
X+++X
X+++X
X+++X
X+++/
X++/
X+/
X/
/
X: 1 Y: 1 Facing: E
Last move: R
[FBLRQ]?
예제와 일치하는 몇 샷 (스택 오버플로로 첫 번째 빈 줄이 잘 리며 프로그램 출력에 있음) :
X /
X /+
X /++
X +++
X +++
X +++
X +++
X +++
X +++
X +++
X \++
X \+
X \
X: 3 Y: 2 Facing: S
Last move: F
[FBLRQ]?
과:
/
/X
/XX
XXX
+++++XXXXXX+XXX+
+++++XXXXXX+XXX+
+++++XXXXXX+XXX+
+++++XXXXXX+XXX+
+++++XXXXXX+XXX+
XXX
\XX
\X
\
X: 3 Y: 2 Facing: E
Last move: L
[FBLRQ]?
제공된 맵의 낯선 뷰 중 하나는 뷰와 평행 한 벽이 그 뒤에 튀어 나오는 수직 벽과 같은 색이기 때문입니다.
\
+\
++\
++++ ++++
++++ ++++
++++ ++++
++++ ++++
++++ ++++
++++ ++++
++++ ++++
++/
+/
/
X: 3 Y: 4 Facing: N
Last move: R
[FBLRQ]?
마지막 샷 영역은 다음과 같습니다.
_ _
|
V