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 루프를 작성하는 가장 짧은 일반적인 방법입니다. 레이블 대신 한 자리 줄 번호를 사용하십시오. 명령문 GOTO의 THEN일부 에서 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. 상기에 대한 예외는 유사 서열이다 1e2및 1d+3과학적 표기법으로 처리하고 확장되고, 100!그리고 1000#(각각 단일 및 이중 정밀도).
    • QB64은 일반적으로 동일하지만 숫자가 다음에 할 수없는 d, e또는 f그들이 잘 형성 과학적 표기법 문자의 일부가 아닌 모두에서. (예를 들어,에서 라인 번호 뒤에 공간을 생략 할 수 1 FOR또는 9 END적절한 QBASIC에서 당신이 할 수처럼.) 인쇄 문에서 그것은 단지가 추정 세미콜론 표현 중 하나가 문자열 인 경우 ?123"abc"작품,하지만 ?TAB(5)123또는 ?123x.
  • 세미콜론에 대해 말하면 QBasic 1.1 PRINT은 TAB또는에 대한 호출로 끝나는 명령문에 후미 세미콜론을 추가합니다 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.