Computer >> 컴퓨터 >  >> 프로그램 작성 >> BASH 프로그래밍

지뢰 찾기를 구축하여 고급 Bash 기술 연마

저는 프로그래밍을 가르치는 전문가는 아니지만, 무언가를 더 잘하고 싶을 때 그것을 즐길 수 있는 방법을 찾으려고 노력합니다. 예를 들어, 쉘 스크립팅을 더 잘하고 싶었을 때 Bash에서 Minesweeper 게임 버전을 프로그래밍하여 연습하기로 결정했습니다.

경험이 풍부한 Bash 프로그래머이고 재미있게 기술을 연마하고 싶다면 터미널에서 자신만의 지뢰 찾기 버전을 작성하십시오. 전체 소스 코드는 이 GitHub 저장소에서 찾을 수 있습니다.

준비하기

코드 작성을 시작하기 전에 게임을 만드는 데 필요한 구성 요소를 간략하게 설명했습니다.

  1. 지뢰밭 인쇄
  2. 게임플레이 로직 생성
  3. 사용 가능한 지뢰밭을 결정하는 논리 만들기
  4. 사용 가능하고 발견된(추출된) 광산 수를 유지
  5. 종료 로직 생성

지뢰 찾기에서 게임 세계는 숨겨진 셀의 2D 배열(열과 행)입니다. 각 셀은 폭발성 지뢰를 포함하거나 포함하지 않을 수 있습니다. 플레이어의 목표는 지뢰가 없는 세포를 밝히고 지뢰를 절대 드러내지 않는 것입니다. 게임의 Bash 버전은 단순한 bash 배열을 사용하여 구현된 10x10 매트릭스를 사용합니다.

먼저 임의의 변수를 할당합니다. 이것은 보드에 광산을 놓을 수 있는 위치입니다. 위치 수를 제한하면 이 위에 쉽게 구축할 수 있습니다. 논리가 더 나을 수도 있지만 게임을 단순하고 약간 미숙하게 보이도록 하고 싶었습니다. (재미로 썼지만 더 나은 모습을 보여주기 위한 여러분의 기여를 기꺼이 환영합니다.)

아래 변수는 a-g 변수와 같이 필드 배치를 위해 무작위로 호출하도록 선언된 일부 기본 변수입니다. 이를 사용하여 추출 가능한 광산을 계산합니다.

#개의 변수
score=0 # 게임의 점수를 저장하는 데 사용됩니다.
아래 #개의 변수는 광산에서 추출 가능한 셀/필드를 무작위로 가져오는 데 사용됩니다.
a="1 10 -10 -1"
b="-1 0 1"
c="0 1"
d="-1 0 1 -2 -3"
e="1 2 20 21 10 0 -10 -20 -23 -2 -1"
f="1 2 3 35 30 20 22 10 0 -10 -20 -25 -30 -35 - 3 -2 -1"
g="1 4 6 9 10 15 20 25 30 -30 -24 -11 -10 -9 -8 -7"
#
# 선언
declare -a room  # 배열실을 선언합니다. 이것은 우리 광산의 각 셀/필드를 나타냅니다.

다음으로 열(0-9)과 행(a-j)이 있는 보드를 인쇄하여 게임의 지뢰밭 역할을 하는 10x10 매트릭스를 형성합니다. (M[10][10]은 인덱스가 0-99인 100개 값 배열입니다.) Bash 배열에 대해 더 알고 싶다면 당신은 Bash를 모릅니다:Bash 배열 소개 .

쟁기, 기능이라고 부를 수 있습니다. 머리글을 먼저 인쇄합니다:두 개의 빈 줄, 열 머리글, 그리고 경기장 상단을 설명하는 줄:

printf '\n\n'
printf '%s' "     a   b   c   d   e   f   g   h   i   j"
printf '\n   %s\n' "----- ------------------------------------"

다음으로 r이라는 카운터 변수를 설정합니다. , 채워진 가로 행 수를 추적합니다. 동일한 카운터 변수 'r을 사용합니다. ' 나중에 게임 코드에서 배열 인덱스로 사용합니다. Bash에서 for 루프, seq 사용 0에서 9로 증가하는 명령, 숫자(d% ) 행 번호($row, seq로 정의됨)를 나타냅니다. ):

r=0 # 행에 대한 카운터
$(seq 0 9); do
  printf '%d  ' "$row" # 0-9 사이의 행 번호 인쇄

여기에서 진행하기 전에 지금까지 만든 것을 확인합시다. [a-j]  시퀀스를 인쇄했습니다. 가로로 먼저 인쇄한 다음 [0-9] 범위의 행 번호를 인쇄했습니다. , 우리는 사용자가 추출할 광산을 찾기 위해 좌표를 입력하는 역할을 하기 위해 이 두 범위를 사용할 것입니다. 

다음은  각 행 내에는 열 교차점이 있으므로 새 for 고리. 이것은 각 열을 관리하므로 본질적으로 경기장에서 각 셀을 생성합니다. 소스 코드에서 전체 정의를 볼 수 있는 몇 가지 도우미 함수를 추가했습니다. 각 셀에 대해 필드를 지뢰처럼 보이게 하는 것이 필요하므로 is_null_field라는 맞춤 함수를 사용하여 빈 셀을 점(.)으로 초기화합니다. . 또한 각 셀의 값을 저장할 배열 변수가 필요하며 사전 정의된 전역 배열 변수인 room 을 사용합니다. 색인 변수 r과 함께 . r로 증분, 우리는 셀을 반복하여 도중에 지뢰를 떨어뜨립니다.

$(seq 0 9)의 열에 대한
 do
    ((r+=1))  # 열 시퀀스에서 앞으로 이동할 때 카운터를 증가
    is_null_field $r  # 필드가 비어 있는지 확인하는 함수를 가정하고 비어 있으면 다음으로 초기화합니다. 점(.)
    printf '%s \e[33m%s\e[0m ' "|" "${room[$r]}" # 마지막으로 구분 기호를 인쇄합니다. ${room[$r]}의 첫 번째 값은 방금 초기화되었으므로 '.'입니다.
  #close col 루프
완료

마지막으로 각 행의 하단을 선으로 둘러싸서 보드를 잘 정의한 상태로 유지한 다음 행 루프를 닫습니다.

printf '%s\n' "|" # 줄 끝 구분 기호를 인쇄합니다.
printf '   %s\n' "-------------------------------- ---------"
# 루프 행 닫기
완료
printf '\n\n'

완전한 쟁기 기능은 다음과 같습니다. 

쟁기()
{
  r=0
  printf '\n\n'
  printf '%s' "     a   b   c   d   e   f   g   h   i   j"
  printf '\n   %s\n' "------------------------------------ -----"
  행 $(seq 0 9); do
    printf '%d  ' "$row"
    $(seq 0 9)의 열; do
       ((r+=1))
       is_null_field $r
       printf '%s \e[33m%s\e[0m ' "|" "${room[$r]}"
    완료
    printf '%s\n' "|"
    printf '   %s\n' "---------------------------------------------------- ---"
 완료
  printf '\n\n'
}

is_null_field가 필요한지 결정하는 데 시간이 좀 걸렸습니다. , 그래서 그것이 무엇을하는지 자세히 살펴 보겠습니다. 게임 시작부터 신뢰할 수 있는 상태가 필요합니다. 그 선택은 임의적입니다. 숫자나 임의의 문자일 수 있습니다. 나는 그것이 게임 보드를 예쁘게 보이게 만들기 때문에 모든 것이 점(.)으로 선언되었다고 가정하기로 결정했습니다. 다음과 같습니다.

is_null_field()
{
  local e=$1 # 배열실에 인덱스 'r'을 이미 사용했습니다. 'e'라고 부르겠습니다.
    if [[ -z "${room [$e]}" ]];그럼
      방[$r]="." # 셀/지뢰밭을 초기화하기 위해 점(.)을 넣는 곳입니다.
    fi
}

이제 광산의 모든 셀이 초기화되었으므로 아래에 표시된 간단한 함수를 선언하고 나중에 호출하여 사용 가능한 모든 광산 수를 얻습니다.

get_free_fields()
{
  free_fields=0    # 변수 초기화
  in $(seq 1 ${#room[@]});
    if [[ "${room[$n]}" ="." ]]; then  # 셀에 초기 값 점(.)이 있는지 확인한 다음 빈 필드로 계산합니다.
      ((free_fields+=1))
    fi
  done
}

다음은 인쇄된 지뢰밭입니다. [a-j] 열이며 [0-9 ]는 행입니다.

지뢰 찾기를 구축하여 고급 Bash 기술 연마

플레이어를 구동하는 로직 생성

플레이어 로직은 stdin에서 광산에 대한 좌표로 옵션을 읽고 지뢰밭에서 정확한 필드를 추출합니다. Bash의 매개변수 확장을 사용하여 열과 행 입력을 추출한 다음 보드에서 해당하는 정수 표기법을 가리키는 스위치에 열을 공급합니다. 이를 이해하려면 변수 'o' 아래의 switch case 문에서. 예를 들어 플레이어는 c3를 입력할 수 있습니다. , Bash는 c 두 문자로 나뉩니다. 및 3 . 편의상 유효하지 않은 항목을 처리하는 방법은 건너뛰겠습니다.

  colm=${opt:0:1}  # 첫 번째 문자 가져오기, 알파벳
  ro=${opt:1:1}    # 두 번째 문자, 숫자 가져오기
  case $colm in
    a) o=1; # 마지막으로 알파벳을 해당하는 정수 표기법으로 변환합니다.
    b ) o=2;;
    c ) o=3;;
    d ) o=4;;
    e ) o=5;;
    f ) o=6;;
    g ) o=7;;
    h ) o=8;;
    i ) o=9;;
    j ) o=10;;
  esac

그런 다음 정확한 인덱스를 계산하고 해당 필드에 입력 좌표의 인덱스를 할당합니다.

shuf도 많이 사용됩니다. 여기에서 명령, 셔프 -i에서 정보의 무작위 순열을 제공하도록 설계된 Linux 유틸리티입니다. 옵션은 셔플할 색인 또는 가능한 범위를 나타내며 -n 반환된 최대 수 또는 출력을 나타냅니다. 이중 괄호는 Bash에서 수학적 평가를 허용하며 여기에서 많이 사용합니다.

이전 예가 c3 를 수신했다고 가정해 보겠습니다. 표준 입력을 통해. 그런 다음 ro=3o=3 위의 switch case 문에서 변환된 c 최종 색인 'i'를 계산하기 위해 공식에 대입합니다.

  i=$(((ro*10)+o))   # BODMAS 규칙에 따라 최종 인덱스를 계산합니다. 
  is_free_field $i $(shuf -i 0-5 -n 1)   # 최종 인덱스 값이 비어 있거나 비어 있는 셀/필드를 가리키는지 확인하는 맞춤 함수를 호출합니다.

이 수학을 통해 최종 색인 'i ' 계산됨:

i=$(((ro*10)+o))
i=$(((3*10)+3))=$((30+3))=33

최종 색인 값은 33입니다. 위에 인쇄된 최종 색인은 33번째 셀을 가리키며 3번째(0에서 시작하지 않으면 4번째) 행과 3번째(C) 열이어야 합니다.

사용 가능한 지뢰밭을 결정하는 논리 만들기

광산을 추출하기 위해 좌표가 디코딩되고 색인이 발견된 후 프로그램은 해당 필드를 사용할 수 있는지 확인합니다. 그렇지 않은 경우 프로그램은 경고를 표시하고 플레이어는 다른 좌표를 선택합니다.

이 코드에서 셀에 점(. ) 캐릭터. 사용 가능하다고 가정하면 셀의 값이 재설정되고 점수가 업데이트됩니다. 점이 포함되지 않아 셀을 사용할 수 없는 경우 변수는 허용되지 않음 설정됩니다. 간결함을 위해 게임 로직에서 경고 문구의 내용에 대한 게임 소스 코드를 보는 것은 여러분에게 맡기겠습니다.

is_free_field()
{
  로컬 f=$1
  로컬 val=$2
  not_allowed=0
  if [[ "${room[$f]} " ="." ]]; then
    room[$f]=$val
    score=$((score+val))
  else
    not_allowed=1
  fi
}

지뢰 찾기를 구축하여 고급 Bash 기술 연마

입력한 좌표가 있으면 아래와 같이 광산이 발견됩니다. h6 일 때 입력으로 제공되며 일부 값은 무작위로 지뢰밭에 채워지며 이 값은 최소값이 추출된 후 사용자 점수에 추가됩니다.

지뢰 찾기를 구축하여 고급 Bash 기술 연마

이제 시작 부분에서 선언한 변수 [a-g]를 기억하십시오. 이제 여기에서 변수 m 에 값을 할당하는 임의의 지뢰를 추출하는 데 사용하겠습니다. Bash 간접 참조를 사용합니다. 따라서 입력 좌표에 따라 프로그램은 임의의 추가 숫자 집합(m ) 여기에서 i (로 표시됨) 원래 입력 좌표에 추가하여 채워질 추가 필드를 계산 위에서 계산됨) .

X 문자를 주목하세요. 아래 코드 스니펫에서 유일한 GAME-OVER 트리거이며 shuf의 아름다움과 함께 무작위로 나타나도록 셔플 목록에 추가했습니다. 명령을 사용하면 여러 번의 기회 후에 나타날 수 있으며 운이 좋은 당첨 사용자에게는 나타나지 않을 수도 있습니다.

m=$(shuf -e a b c d e f g X -n 1)   # 셔플에 추가 문자 X를 추가합니다. m=X일 때 GAMEOVER
  if [[ "$m" !="X" ]]; 그러면        # X는 ${!m}의 제한을 위한 폭발 지뢰(GAME-OVER) 트리거입니다.
   ; do          # !m은 m의 값을 나타냅니다.
      field=$(shuf -i 0-5 -n 1)     # 다시 난수를 얻고
      index=$((i+limit)) # m 값을 인덱스에 추가하고 m이 마지막 요소에 도달할 때까지 새 인덱스를 계산합니다.
      is_free_field $index $field
    done

모든 노출된 셀이 플레이어가 선택한 셀에 인접하게 하고 싶습니다.

지뢰 찾기를 구축하여 고급 Bash 기술 연마

사용 가능하고 추출된 광산 수를 유지

프로그램은 지뢰밭에서 사용 가능한 세포를 추적해야 합니다. 그렇지 않으면 모든 셀이 공개된 후에도 플레이어에게 계속 입력을 요청합니다. 이를 구현하기 위해 free_fields라는 변수를 만듭니다. , 처음에는 0으로 설정합니다. for에서 지뢰밭에서 사용 가능한 셀/필드의 나머지 수로 정의된 루프입니다. 셀에 점(. ), free_fields 수 증가합니다.

get_free_fields()
{
free_fields=0
  for n in $(seq 1 ${#room[@]});
    if [[ "${room[$n]}" ="." ]]; 그럼
      ((free_fields+=1))
    fi
  완료
}

free_fields=0 ? 즉, 사용자가 모든 광산을 추출했습니다. 더 나은 이해를 위해 정확한 코드를 자유롭게 살펴보시기 바랍니다.

if [[ $free_fields -eq 0 ]]; then   # 모든 지뢰를 추출했다는 뜻입니다.
      printf '\n\n\t%s:%s %d\n\n' "You Win" "you득점" "$score"
      0번 출구
fi

Gameover를 위한 논리 만들기

Gameover 상황에서 우리는 멋진 논리를 사용하여 터미널 중앙에 인쇄합니다. 어떻게 작동하는지 알아보기 위해 독자에게 맡기는 것입니다.

if [[ "$m" ="X" ]]; then
    g=0                    # 매개변수 확장에 사용
    room[$i]=X               # 색인을 무시하고 {42..49}에서 j에 대해 X
   를 인쇄합니다. do    # 지뢰밭 한가운데,
      out="gameover"
      k=${out:$g:1}        # 각 셀에 하나의 알파벳 인쇄
      room[$j]=${k^^}
      ((g+=1))
    완료
fi

마지막으로 가장 기다리고 있는 두 줄을 인쇄할 수 있습니다.

if [[ "$m" ="X" ]]; then
      printf '\n\n\t%s:%s %d\n' "GAMEOVER" "득점" "$score"
      printf '\n\n\t%s\n \n' "당신은 $free_fields 지뢰에 불과했습니다."
      0번 출구
fi

지뢰 찾기를 구축하여 고급 Bash 기술 연마

그게 다야, 여러분! 더 알고 싶다면 내 GitHub 리포지토리에서 이 지뢰 찾기 게임 및 Bash의 다른 게임에 대한 소스 코드에 액세스하세요. Bash를 더 많이 배우고 즐기면서 영감을 얻을 수 있기를 바랍니다.