QBasic에서의 골프에 대한 일반적인 팁은 무엇입니까? QBasic에 다소 특정한 코드 골프 문제에 적용 할 수있는 아이디어를 찾고 있습니다 (예 : "댓글 제거"는 답이 아닙니다).
QB64 에뮬레이터와 관련된 팁 도 환영합니다. Microsoft QBasic에없는 몇 가지 추가 기능이 있습니다.
QBasic에서의 골프에 대한 일반적인 팁은 무엇입니까? QBasic에 다소 특정한 코드 골프 문제에 적용 할 수있는 아이디어를 찾고 있습니다 (예 : "댓글 제거"는 답이 아닙니다).
QB64 에뮬레이터와 관련된 팁 도 환영합니다. Microsoft QBasic에없는 몇 가지 추가 기능이 있습니다.
답변:
QBASIC는 여러 루프 구조를 가지고 FOR ... NEXT
, WHILE ... WEND
하고 DO ... LOOP
. GOTO
또는 (일부 상황에서) RUN
루프를 사용할 수도 있습니다 .
FOR ... NEXT
그것이하는 일을 꽤 잘합니다. 파이썬과는 달리 , 조금 더 멋진 경우에도 거의 항상 동등 WHILE
하거나 GOTO
루프 보다 짧습니다 .
FOR i=1TO 19STEP 2:?i:NEXT
i=1:WHILE i<20:?i:i=i+2:WEND
i=1:9?i:i=i+2:IF i<20GOTO 9
뒤에 변수 이름을 반복 할 필요가 없으며 NEXT
숫자와 가장 많이 따르는 키워드 사이의 공백을 제거 할 수 있습니다.
WHILE ... WEND
루프를 0 번 실행해야 할 때 유용합니다. 그러나 루프가 적어도 한 번 실행된다는 것을 알고 있다면 GOTO
1 바이트 더 짧을 수 있습니다.
WHILE n>1:n=n\2:WEND
1n=n\2:IF n>1GOTO 1
DO ... LOOP
무한 루프 에만 사용 합니다 ( RUN
대신 사용할 수있는 곳 은 제외 ). 무조건 문자와 동일한 수의 문자 GOTO
를 사용하지만 읽는 것이 조금 더 직관적입니다. ( "무한 루프가"당신은을 사용하는 탈옥 것을 루프를 포함 할 수 있음을 참고 GOTO
하십시오.) DO WHILE
/ DO UNTIL
/ LOOP WHILE
/ LOOP UNTIL
구문 너무 장황; WHILE
또는 GOTO
적절하게 사용하는 것이 좋습니다 .GOTO
위에서 언급했듯이 do / while 루프를 작성하는 가장 짧은 일반적인 방법입니다. 레이블 대신 한 자리 줄 번호를 사용하십시오. 명령문 GOTO
의 THEN
일부 에서 a 가 유일한 IF
경우에는 두 가지 간결한 단축키 구문을 사용할 수 있습니다.
IF x>y GOTO 1
IF x>y THEN 1
GOTO
보다 복잡한 제어 흐름 을 만드는 데에도 사용할 수 있습니다 . naysayers는 이것을 "스파게티 코드"라고 부르지 만 이것은 코드 골프입니다. 읽을 수없는 것은 거의 미덕입니다! GOTO
자부심!
RUN
프로그램에서 고정 된 위치로 이동해야하고 변수 값을 유지할 필요가 없을 때 유용합니다. RUN
자체적으로 프로그램을 맨 위에서 다시 시작합니다. 레이블 또는 줄 번호와 함께 해당 줄에서 다시 시작됩니다. 나는 주로 무 상태 무한 루프 를 만드는 데 사용했습니다 .하나의 정수를 다른 정수로 나눌 수 있는지 테스트 해야하는 프로그램에서 확실한 방법은 다음을 사용하는 것입니다 MOD
.
x MOD 3=0
그러나 더 짧은 방법은 정수 나누기를 사용하는 것입니다.
x\3=x/3
즉, x
int-div는 float-div 3
와 같습니다 .x
3
이 두 가지 접근 방식은 모두 0
거짓과 진실로 돌아갈 -1
수 있으므로 결과를 부정하거나 추가하는 대신 빼야 할 수도 있습니다.
당신이 반대 조건이 필요한 경우 (즉, x
인 하지 로 나누어 3
), 명백한 접근 방식은 운영자가 같지 않음을 사용하는 것입니다 :
x\3<>x/3
그러나 x
음이 아닌 것으로 보장 되면 바이트를 절약 할 수 있습니다. 정수 나누기 결과가 잘 리므로 항상 부동 나누기보다 작거나 같습니다. 따라서 다음과 같이 조건을 작성할 수 있습니다.
x\3<x/3
마찬가지로, x
음수가 보장되면 잘림 은 결과를 증가 시키고 우리는 쓸 수 있습니다 x\3>x/3
. 의 표시를 모르는 x
경우를 준수해야 <>
합니다.
많은 언어에서와 같이 제거 할 수있는 문자와 제거 할 수없는 문자를 아는 것이 중요합니다.
IF""=a$THEN?0
FOR i=1TO 10STEP 2
. QBasic 1.1 ( archive.org 에서 사용 가능 )과 QB64 사이에는 약간의 차이점이 있습니다 .
?123x
된다 PRINT 123; x
. 상기에 대한 예외는 유사 서열이다 1e2
및 1d+3
과학적 표기법으로 처리하고 확장되고, 100!
그리고 1000#
(각각 단일 및 이중 정밀도).d
, e
또는 f
그들이 잘 형성 과학적 표기법 문자의 일부가 아닌 모두에서. (예를 들어,에서 라인 번호 뒤에 공간을 생략 할 수 1 FOR
또는 9 END
적절한 QBASIC에서 당신이 할 수처럼.) 인쇄 문에서 그것은 단지가 추정 세미콜론 표현 중 하나가 문자열 인 경우 ?123"abc"
작품,하지만 ?TAB(5)123
또는 ?123x
.PRINT
은 TAB
또는에 대한 호출로 끝나는 명령문에 후미 세미콜론을 추가합니다 SPC
. (QB64는 그렇지 않습니다.)0
소수점 앞 ( .1
또는 1.
) 앞이나 뒤에 생략 할 수 있지만 둘 다 ( .
)는 사용할 수 없습니다 .ENDIF
와 같습니다 END IF
.Next
문Next:Next:Next
응축 될 수 있습니다
Next k,j,i
에 대한 반복자 곳 For
루프가 i
, j
그리고 k
- 순서이다.
예를 들어 아래 (69 바이트)
Input n,m,o
For i=0To n
For j=0To m
For k=0To o
?i;j;k
Next
Next
Next
65 바이트로 압축 될 수 있음
Input n,m,o
For i=0To n
For j=0To m
For k=0To o
?i;j;k
Next k,j,i
그리고 이것이 형식 및 들여 쓰기에 미치는 영향에 관해서는, 이것을 처리하는 가장 좋은 방법은 다음 명령문을 가장 외부 명령문과 정렬시키는 것입니다. 예 :
Input n,m,o
For i=0To n
For j=0To m
For k=0To o
?i;j;k
Next k,j,i
QBASIC는 사용자의 키보드 입력을받을 수있는 몇 가지 방법이있다 : INPUT
, LINE INPUT
, INPUT$
,와 INKEY$
.
INPUT
표준 다목적 입력 문입니다. 프로그램은 수행중인 작업을 중지하고 커서를 표시하며 사용자가 입력을 입력하도록 Enter합니다. INPUT
숫자 나 문자열을 읽을 수 있으며 쉼표로 구분 된 여러 값을 읽을 수 있습니다. 문자열을 프롬프트로 지정할 수 있으며 기본 물음표 프롬프트로 이동할 수 있으며 프롬프트를 전혀 표시하지 않을 수도 있습니다. 일부 샘플 호출 :
INPUT x$,y
?
프롬프트를 사용하고 쉼표로 구분 된 문자열과 숫자를 읽습니다.INPUT"Name";n$
Name?
문자열로
프롬프트 하고 읽습니다.INPUT"x=",x
x=
(물음표 없음! 구문에서 쉼표를 확인하십시오)로
프롬프트 하고 숫자를 읽습니다.INPUT;"",s$
INPUT
). 예를 들어,이 PRINT s$
직후에 화면은 다음과 같습니다 User_inputUser_input
.INPUT
있는 문자열을 읽을 수 없다는 것 INPUT
입니다. 임의의 한 줄의 인쇄 가능한 ASCII 문자를 읽으려면을 사용하십시오 LINE INPUT
. INPUT
문자열 변수 여야하는 하나의 변수 만 사용한다는 점을 제외하고 와 동일한 구문 옵션이 있습니다 . 다른 차이점은 LINE INPUT
기본적으로 프롬프트를 표시하지 않는다는 것입니다. 원하는 경우 명시 적으로 지정해야합니다.INPUT$(n)
프롬프트 나 커서를 표시하지 않고 사용자가 n
문자를 입력 할 때까지 기다린 다음 해당 문자가 포함 된 문자열을 반환합니다. 달리 INPUT
거나 LINE INPUT
, 사용자가 언론에 필요하지 않습니다 Enter이후, 실제로 Enter문자 중 하나가 될 수 있습니다 (이것은 알려진 ASCII 문자 (13)을주지 C와 같은 언어와 같은 \r
).
대부분의 경우 이것은 INPUT$(1)
일반적으로 루프에서 유용 합니다. INPUT$
에 좋은 하나의 키 누름이 일을 대화 형 프로그램 . 불행히도 ASCII 코드가있는 키에서만 작동합니다. 이 같은 것들을 포함 Esc하고 Backspace있지만 화살표 키, Insert그리고 Delete, 그리고 다른 사람을.
어느 키가 나오는지. 단일 키 누르기 1 의 결과를 반환한다는 점 INKEY$
과 비슷 하지만 다음과는 다릅니다.INPUT$(1)
INKEY$
논쟁이 없다.INPUT$(n)
사용자가 n
문자를 입력 할 때까지 실행 이 중단 되는 동안 실행 INKEY$
은 중단되지 않습니다. 사용자가 현재 키를 누르면 INKEY$
해당 키를 나타내는 문자열을 반환합니다. 그렇지 않으면를 반환합니다 ""
. 즉 INKEY$
, 다음 키 누르기를 얻기 위해 사용 하려면 통화 중 대기 루프 에서 키를 감아 야합니다 . 2
k$=""
WHILE""=k$
k$=INKEY$
WEND
모두 INPUT$
와 INKEY$
키에 대한 반환 ASCII 문자가 (탈출, 탭 및 백 스페이스와 같은 제어 문자 포함) ASCII 문자에 해당합니다. 그러나 INKEY$
ASCII 코드가없는 일부 키를 처리 할 수도 있습니다. "도움말 파일에서"INKEY $는 널 문자 (ASCII 0)와 키보드 스캔 코드로 구성된 2 바이트 문자열을 반환합니다. "
진흙처럼 맑습니까? 몇 가지 예가 있습니다. INKEY$
위 의 루프 를 사용하여 왼쪽 화살표 키의 키 누르기를 캡처 k$
하면 문자열 "␀K"
( K
스캔 코드 75를 나타냄)이 포함됩니다. 오른쪽 화살표는 "␀M"
(77)입니다. 페이지 다운은 "␀Q"
(81)입니다. F5는 "␀?"
(63)입니다.
아직도 진흙처럼 맑습니까? 네. 세상에서 가장 직관적 인 것은 아닙니다. 도움말 파일에는 스캔 코드 테이블이 있지만 항상 결과를 인쇄하고 INKEY$
많은 키를 눌러 올바른 값을 찾는 작은 프로그램을 작성합니다 . 어떤 문자가 어떤 키에 해당하는지 알고 나면 발생하는 모든 다른 경우를 사용 RIGHT$(k$,1)
하고 LEN(k$)
구별 할 수 있습니다.
결론? INKEY$
기묘하지만, 프로그램에 비 차단 입력이 필요 하거나 화살표 키를 사용해야하는 경우 갈 수있는 유일한 방법 입니다.
1 포함되지 않음 Shift, Ctrl, Alt, PrntScr, Caps Lock,와 유사한. 그것들은 계산되지 않습니다. : ^ P
2WHILE ... WEND
여기 의 관용구는 QBasic 책에서 배운 것입니다. 목적을 골프를 위해, 그러나, 루프는 짧습니다 .GOTO
이 LOCATE
명령문을 사용하면 커서를 화면의 임의의 위치 (일반적인 80x40 문자 공간 제한 내)에 놓고 해당 위치에 무언가를 인쇄 할 수 있습니다. 이 도전에 대한 대답 은 실제로 이것을 보여줍니다 (이 주제의 다른 많은 팁과 결합되어 있음).
이 과제는 사용자가 16x6 그리드에서 누른 모든 문자를 출력하도록 요청합니다. 로 LOCATE
이 (ASCII 코드를 통해 사업부와 모드의 문제가 단순히 a
이 코드는)
LOCATE a\16-1,1+2*(a MOD 16)
그런 다음 문자를 인쇄하십시오.
?CHR$(a)
QBasic에서는 DIM
명령문을 사용하여 변수를 작성하여 이름과 유형을 지정 하는 것이 일반적 입니다. 그러나 이것은 필수 사항은 아니며 QBasic은 변수 이름의 접미사로 유형을 파생시킬 수도 있습니다. 변수를 동시에 선언하고 초기화 할 수 없으므로 DIM
in codegolf 를 건너 뛰는 것이 현명합니다 . 기능적으로 동일한 두 개의 스 니펫 * :
DIM a AS STRING: a = "example"
a$ = "example"
* 이렇게하면 두 개의 다른 변수 이름이 만들어집니다.
$
문자열, !
단일 정밀도 숫자 및 %
배가 에 대한 변수 이름 끝에 변수를 추가하여 변수 유형을 지정할 수 있습니다 . 유형이 지정되지 않은 경우 단일이 가정됩니다.
a$ = "Definitely a string"
b! = "Error!"
이것은 배열에도 적용됩니다. 일반적으로 배열은 다음과 같이 정의됩니다.
DIM a(20) AS STRING
그러나 배열도 DIM
med 할 필요가 없습니다 .
a$(2) = "QBasic 4 FUN!"
a$
이제는 인덱스 0에서 인덱스 10까지 11 개의 슬롯이있는 문자열에 대한 배열입니다 . QBasic에는 배열에 대해 0 기반 및 1 기반 색인을 생성 할 수있는 옵션이 있기 때문에 수행됩니다. 기본 배열 종류는이 방법을 모두 지원합니다.
DIM
위 의 20 슬롯 배열을 기억 하십니까? 동일한 원리가 희미한 배열과 희미한 배열 모두에 적용되기 때문에 실제로는 21 개의 슬롯이 있습니다.
IF
진술IF
문은 다소 비싸므로 골프를 치면 많은 바이트를 절약 할 수 있습니다.
다음을 고려하십시오 ( Outgolfer Erik의 답변 에서 수정).
IF RND<.5THEN
x=x-1
a(i)=1
ELSE
y=y-1
a(i)=0
ENDIF
우리가 할 수있는 첫 번째 일은 ENDIF
한 줄짜리 IF
문장 을 사용하여를 저장하는 것입니다 .
IF RND<.5THEN x=x-1:a(i)=1ELSE y=y-1:a(i)=0
이것은 다른 것과 같은 줄에 넣으려고하지 않는 한 작동합니다. 특히 중첩 된 IF
명령문이있는 경우 가장 안쪽의 명령문 만 한 줄로 묶을 수 있습니다.
그러나이 경우 우리는 IF
완전히 수학을 사용하여 제거 할 수 있습니다 . 실제로 원하는 것을 고려하십시오.
RND<.5
(사실 -1
), 우리가 원하는 :
x
1 씩 감소y
동일하게 유지a(i)
1이되기 위해RND<.5
false ( 0
)이면 다음을 원합니다.
x
동일하게 유지y
1 씩 감소a(i)
0이된다우리가 (변수에 조건의 결과를 저장할 이제 경우 r=RND<.5
), 우리는 새로운 값을 계산할 수 있습니다 x
, y
그리고 a(i)
:
r
이다 -1
, x=x-1
; 때 r
이다 0
, x=x+0
.r
이다 -1
, y=y+0
; 때 r
이다 0
, y=y-1
.r
이다 -1
, a(i)=1
; 때 r
이다 0
, a(i)=0
.최종 코드는 다음과 같습니다.
r=RND<.5
x=x+r
y=y-1-r
a(i)=-r
원래 버전보다 무려 20 바이트 (40 %) 절약.
수학 접근법은 놀랍게도 자주 적용될 수 있지만 두 경우간에 논리에 차이가있는 경우 (예를 들어 한 경우에는 입력해야하지만 다른 경우는 입력하지 않는 경우)을 사용해야 IF
합니다.
QBasic의 배열은 DIM
슬롯이 11 개 없이 인스턴스화 될 때 챌린지에 11 개 이상의 슬롯 (또는 N 개, N이 11보다 클 수있는 슬롯)이 필요한 DIM
경우 어레이 를 사용해야 합니다. 또한이 배열을 데이터로 채우려 고한다고 가정 해 봅시다.
DIM a$(12)
a$(0) = "Value 1"
a$(1) = "Value 2"
...
골프를 타더라도 많은 공간을 차지할 수 있습니다. 이런 경우 바이트 단위로 더 저렴할 수 있습니다.
a$ = "value 1value 2"
여기에서는 모든 것을 하나의 연결된 문자열에 넣습니다. 나중에 다음과 같이 액세스합니다.
?MID$(a$,i*7,7)
이 방법에서는 모든 값의 길이가 동일해야합니다. 가장 긴 값을 가지고 다른 모든 것을 제거하십시오.
a$="one two threefour "
마지막 값을 채울 필요가 없으며 닫는 따옴표를 건너 뛸 수도 있습니다! 챌린지에서 답변에 공백이 허용되지 않는다고 지정하면이를 사용 RTRIM$()
하여 수정하십시오.
당신은 행동이 기술을 볼 수 있습니다 여기에 .
PRINT
( ?
)에 단점이 있습니다숫자는 선행 및 후행 공백으로 인쇄됩니다.
인쇄하면 줄 바꿈이 추가됩니다. 명령문 끝에 쉼표를 추가하여 탭을 삽입하거나 세미콜론을 삽입하여 삽입을 피함으로써이 동작을 변경할 수 있습니다.
사용할 필요가 없습니다 &
또는 ;
예를 들어, 인쇄 할 때 별개의 작업 사이. 각면에 공백이 ?1"x"s$
있는 숫자 1
와 문자 x
및 내용을 인쇄해야합니다.s$
?"foo"
?"bar"
?10
?"foo",
?"bar"
?"foo";
?"bar"
?1CHR$(65)
?1" "CHR$(65)
?"A","B
출력
foo
bar
10
foo bar
foobar
1 A
1 A
A B
줄 바꿈 인쇄는 ?
-
가 인쇄됩니다. 숫자 뒤에 공백도 인쇄됩니다. 이 공간을 제거하는 가장 좋은 방법은 PRINT USING
이 답변에 추가하거나 별도의 답변 이 필요한 경우 --dunno입니다.
WRITE
대신에 유용 할 수 있습니다 PRINT
PRINT
그것은 매우 유연하고 ?
지름길 이 있기 때문에 일반적으로 출력을하고 싶은 방법 입니다. 그러나이 WRITE
명령은 특정 상황에서 바이트를 절약 할 수 있습니다.
WRITE
큰 따옴표 ( "
)로 묶습니다 . 큰 따옴표가있는 출력이 필요한 경우 WRITE s$
보다 훨씬 짧습니다 ?CHR$(34);s$;CHR$(34)
. 예를 들어 가장 짧은 알려진 QBasic quine을 참조하십시오 .WRITE
처럼 전후에 공백을 추가하지 마십시오 PRINT
. WRITE n
보다 훨씬 짧습니다 ?MID$(STR$(n),2)
. 예를 들어, QB64의 FizzBuzz를 참조하십시오 .WRITE
쉼표로 구분하여 WRITE 123,"abc"
출력하십시오 123,"abc"
. 이것이 유용한 시나리오를 생각할 수는 없지만 이것이 없다는 것을 의미하지는 않습니다.제한 사항 WRITE
:
PRINT a;b
.LOCATE
있지만 많은 비용이 듭니다.)문자열 대신 문자에서 작동하는 몇 가지 함수가 있지만 char
QBasic 에는 데이터 유형 이 없으며 유형 만 string ($)
있습니다. 예를 들어 ASC()
문자의 ASCII 키 코드를 반환 하는 함수 를 예로 들어 보겠습니다 . 우리가 들어가면
PRINT ASC("lala")
l
QBasic 은 첫 번째 만 고려합니다. 이런 식으로 문자열을 길이 1로 자르지 않아도됩니다.
또 다른 예에서 오는 이 질문에STRING$()
기능이 답변 중 하나에 사용됩니다.
STRING $ 함수는 숫자 n과 문자열 s $의 두 인수를 사용하고 s $의 첫 문자의 n 개 사본으로 구성된 문자열을 구성합니다.
@DLosc, 여기
다중 문자 문자열을 제공하고 하나의 문자 만 필요한 QBasic은 자동으로 첫 번째 문자를 사용하고 나머지 문자는 무시합니다.