QBasic에서의 골프 팁


13

QBasic에서의 골프에 대한 일반적인 팁은 무엇입니까? QBasic에 다소 특정한 코드 골프 문제에 적용 할 수있는 아이디어를 찾고 있습니다 (예 : "댓글 제거"는 답이 아닙니다).

QB64 에뮬레이터와 관련된 팁 도 환영합니다. Microsoft QBasic에없는 몇 가지 추가 기능이 있습니다.


당신의 동기가 궁금합니다. 저는 10 학년 프로그램 수업 이후 QBASIC을 사용하지 않았습니다. 어떤 버전 제어 방식없이 1.44 플로피 디스크에 직접 저장하고 치명적인 오류를 피했는지 놀랍습니다.
Andrew Brēza

5
@ AndrewBrēza 동기? 어떤 언어로든 골프에 대한 동기 부여와 동일 : 재미를 위해! QBasic에서 작은 프로그램을 작성하는 것을 좋아합니다 (심지어 심각한 용도로 사용하고 싶지는 않지만). 또한 내가 선호하는 "실제"언어 인 파이썬이 제공하지 않는 사운드와 그래픽 (텍스트와 픽셀 모두)이 내장되어 있다는 추가 보너스도 있습니다.
DLosc

QBasic에서 파이썬보다 그래픽 게임을 작성하는 것이 훨씬 쉽습니다.
Anush

누구나 브라우저에서 그래픽 QBasic 응용 프로그램을 직접 사용하려면 다음을 사용할 수 있습니다. github.com/nfriend/origins-host
mbomb007

답변:


10

루핑 구조 이해

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 번 실행해야 할 때 유용합니다. 그러나 루프가 적어도 한 번 실행된다는 것을 알고 있다면 GOTO1 바이트 더 짧을 수 있습니다.

    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 루프를 작성하는 가장 짧은 일반적인 방법입니다. 레이블 대신 한 자리 줄 번호를 사용하십시오. 명령문 GOTOTHEN일부 에서 a 가 유일한 IF경우에는 두 가지 간결한 단축키 구문을 사용할 수 있습니다.

    IF x>y GOTO 1
    IF x>y THEN 1
    

    GOTO보다 복잡한 제어 흐름 을 만드는 데에도 사용할 수 있습니다 . naysayers는 이것을 "스파게티 코드"라고 부르지 만 이것은 코드 골프입니다. 읽을 수없는 것은 거의 미덕입니다! GOTO자부심!

  • RUN프로그램에서 고정 된 위치로 이동해야하고 변수 값을 유지할 필요가 없을 때 유용합니다. RUN자체적으로 프로그램을 맨 위에서 다시 시작합니다. 레이블 또는 줄 번호와 함께 해당 줄에서 다시 시작됩니다. 나는 주로 무 상태 무한 루프만드는 데 사용했습니다 .

5

PRINT및 바로 가기 사용REM

당신이 사용할 수있는 ?대신 PRINT하고, '대신 REM(주석).

''char 또는 string 구문의 일부로 지원 되는 언어로 폴리 글로 팅 할 때 유용 할 수 있습니다 .


5

분 산성 테스트

하나의 정수를 다른 정수로 나눌 수 있는지 테스트 해야하는 프로그램에서 확실한 방법은 다음을 사용하는 것입니다 MOD.

x MOD 3=0

그러나 더 짧은 방법은 정수 나누기를 사용하는 것입니다.

x\3=x/3

즉, xint-div는 float-div 3와 같습니다 .x3

이 두 가지 접근 방식은 모두 0거짓과 진실로 돌아갈 -1수 있으므로 결과를 부정하거나 추가하는 대신 빼야 할 수도 있습니다.


당신이 반대 조건이 필요한 경우 (즉, x하지 로 나누어 3), 명백한 접근 방식은 운영자가 같지 않음을 사용하는 것입니다 :

x\3<>x/3

그러나 x음이 아닌 것으로 보장 되면 바이트를 절약 할 수 있습니다. 정수 나누기 결과가 잘 리므로 항상 부동 나누기보다 작거나 같습니다. 따라서 다음과 같이 조건을 작성할 수 있습니다.

x\3<x/3

마찬가지로, x음수가 보장되면 잘림 은 결과를 증가 시키고 우리는 쓸 수 있습니다 x\3>x/3. 의 표시를 모르는 x경우를 준수해야 <>합니다.


5

스캐너 남용

많은 언어에서와 같이 제거 할 수있는 문자와 제거 할 수없는 문자를 아는 것이 중요합니다.

  • 기호 옆에있는 공간을 제거 할 수 있습니다. IF""=a$THEN?0
  • 공간은 일반적으로 숫자 및 발생 편지 사이에 제거 할 수 있습니다 순서대로 : FOR i=1TO 10STEP 2. QBasic 1.1 ( archive.org 에서 사용 가능 )과 QB64 사이에는 약간의 차이점이 있습니다 .
    • QBasic 1.1은 숫자와 다음 문자 사이의 공백을 제거합니다. 또한, 인쇄 문에서, 그것은 연속 값 사이에 세미콜론을 추론됩니다 ?123x된다 PRINT 123; x. 상기에 대한 예외는 유사 서열이다 1e21d+3과학적 표기법으로 처리하고 확장되고, 100!그리고 1000#(각각 단일 및 이중 정밀도).
    • QB64은 일반적으로 동일하지만 숫자가 다음에 할 수없는 d, e또는 f그들이 잘 형성 과학적 표기법 문자의 일부가 아닌 모두에서. (예를 들어,에서 라인 번호 뒤에 공간을 생략 할 수 1 FOR또는 9 END적절한 QBASIC에서 당신이 할 수처럼.) 인쇄 문에서 그것은 단지가 추정 세미콜론 표현 중 하나가 문자열 인 경우 ?123"abc"작품,하지만 ?TAB(5)123또는 ?123x.
  • 세미콜론에 대해 말하면 QBasic 1.1 PRINTTAB또는에 대한 호출로 끝나는 명령문에 후미 세미콜론을 추가합니다 SPC. (QB64는 그렇지 않습니다.)
  • 0소수점 앞 ( .1또는 1.) 앞이나 뒤에 생략 할 수 있지만 둘 다 ( .)는 사용할 수 없습니다 .
  • ENDIF와 같습니다 END IF.
  • 줄의 끝에서 문자열의 큰 따옴표를 생략 할 수 있습니다.

endif실제로 QB64에서 작동합니다. 이 답변
wastl

@wastl 그렇습니다. QB64에서 처음 테스트 할 때 구문 오류 인 이전 버전을 사용하고있었습니다. 언급 해 주셔서 감사합니다!
DLosc

4

결합 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

4

입력 방법을 알고

QBASIC는 사용자의 키보드 입력을받을 수있는 몇 가지 방법이있다 : INPUT, LINE INPUT, INPUT$,와 INKEY$.

  • INPUT표준 다목적 입력 문입니다. 프로그램은 수행중인 작업을 중지하고 커서를 표시하며 사용자가 입력을 입력하도록 Enter합니다. INPUT숫자 나 문자열을 읽을 수 있으며 쉼표로 구분 된 여러 값을 읽을 수 있습니다. 문자열을 프롬프트로 지정할 수 있으며 기본 물음표 프롬프트로 이동할 수 있으며 프롬프트를 전혀 표시하지 않을 수도 있습니다. 일부 샘플 호출 :
    • INPUT x$,y
      기본 ? 프롬프트를 사용하고 쉼표로 구분 된 문자열과 숫자를 읽습니다.
    • INPUT"Name";n$
      Name? 문자열로 프롬프트 하고 읽습니다.
    • INPUT"x=",x
      x=(물음표 없음! 구문에서 쉼표를 확인하십시오)로 프롬프트 하고 숫자를 읽습니다.
    • INPUT;"",s$
      빈 프롬프트 문자열과 함께 위의 쉼표 구문을 사용하여 프롬프트를 억제하고 문자열을 읽은 다음 사용자가 Enter 키를 누르면 다음 줄로 이동하지 않습니다 (세미콜론 뒤에 나오는 것 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


3

LOCATE는 정말 강력 할 수 있습니다

LOCATE명령문을 사용하면 커서를 화면의 임의의 위치 (일반적인 80x40 문자 공간 제한 내)에 놓고 해당 위치에 무언가를 인쇄 할 수 있습니다. 도전에 대한 대답 은 실제로 이것을 보여줍니다 (이 주제의 다른 많은 팁과 결합되어 있음).

이 과제는 사용자가 16x6 그리드에서 누른 모든 문자를 출력하도록 요청합니다. 로 LOCATE이 (ASCII 코드를 통해 사업부와 모드의 문제가 단순히 a이 코드는)

LOCATE a\16-1,1+2*(a MOD 16)

그런 다음 문자를 인쇄하십시오.

?CHR$(a)

3

QBasic에서는 DIM명령문을 사용하여 변수를 작성하여 이름과 유형을 지정 하는 것이 일반적 입니다. 그러나 이것은 필수 사항은 아니며 QBasic은 변수 이름의 접미사로 유형을 파생시킬 수도 있습니다. 변수를 동시에 선언하고 초기화 할 수 없으므로 DIMin codegolf 를 건너 뛰는 것이 현명합니다 . 기능적으로 동일한 두 개의 스 니펫 * :

DIM a AS STRING: a = "example"
a$ = "example"

* 이렇게하면 두 개의 다른 변수 이름이 만들어집니다.

$문자열, !단일 정밀도 숫자 및 %배가 에 대한 변수 이름 끝에 변수를 추가하여 변수 유형을 지정할 수 있습니다 . 유형이 지정되지 않은 경우 단일이 가정됩니다.

a$ = "Definitely a string"
b! = "Error!"

이것은 배열에도 적용됩니다. 일반적으로 배열은 다음과 같이 정의됩니다.

DIM a(20) AS STRING

그러나 배열도 DIMmed 할 필요가 없습니다 .

a$(2) = "QBasic 4 FUN!"

a$이제는 인덱스 0에서 인덱스 10까지 11 개의 슬롯이있는 문자열에 대한 배열입니다 . QBasic에는 배열에 대해 0 기반 및 1 기반 색인을 생성 할 수있는 옵션이 있기 때문에 수행됩니다. 기본 배열 종류는이 방법을 모두 지원합니다.

DIM위 의 20 슬롯 배열을 기억 하십니까? 동일한 원리가 희미한 배열과 희미한 배열 모두에 적용되기 때문에 실제로는 21 개의 슬롯이 있습니다.


나는 이것이 배열에도 적용되는 것을 깨닫지 못했습니다. 흥미 롭군
trichoplax 2016 년

3

단축 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<.5false ( 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합니다.


3

때로는 배열을 피해야합니다

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$()하여 수정하십시오.

당신은 행동이 기술을 볼 수 있습니다 여기에 .


3

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입니다.
DLosc

2

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:

  • with와 같은 구분 기호없이 여러 값을 출력 할 방법이 없습니다 PRINT a;b.
  • 출력이 끝날 때 줄 바꿈을 억제하는 방법은 없습니다. (이 문제를 해결할 수는 LOCATE있지만 많은 비용이 듭니다.)

1

때때로 QBasic은 입력을 함수에 맹 글링합니다. 남용하세요!

문자열 대신 문자에서 작동하는 몇 가지 함수가 있지만 charQBasic 에는 데이터 유형 이 없으며 유형 만 string ($)있습니다. 예를 들어 ASC()문자의 ASCII 키 코드를 반환 하는 함수 를 예로 들어 보겠습니다 . 우리가 들어가면

PRINT ASC("lala")

lQBasic 은 첫 번째 만 고려합니다. 이런 식으로 문자열을 길이 1로 자르지 않아도됩니다.

또 다른 예에서 오는 이 질문에STRING$() 기능이 답변 중 하나에 사용됩니다.

STRING $ 함수는 숫자 n과 문자열 s $의 두 인수를 사용하고 s $의 첫 문자의 n 개 사본으로 구성된 문자열을 구성합니다.

@DLosc, 여기

다중 문자 문자열을 제공하고 하나의 문자 만 필요한 QBasic은 자동으로 첫 번째 문자를 사용하고 나머지 문자는 무시합니다.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.