17일차(과제)[블랙잭 게임 만들기]

진하의 메모장·2025년 1월 31일
2

공부일기

목록 보기
20/66
post-thumbnail

2025 / 01 / 31

오늘은 수업 시간에 받은 과제를 포스팅하겠습니다!
지금까지 배운 내용을 활용해서 블랙잭이라는 게임을 만들어보았습니다.
예외처리도 좀 있고 조건도 많아서 좀 어려웠지만! 최대한 쉽게 작성해보겠습니다.



💌 블랙잭 게임

만드는 순서

  1. 사용자와 컴퓨터가 나눠 받을 카드의 숫자를 배열에 담아줍니다.
  2. 처음에 사용자는 카드 2개 컴퓨터는 1개의 카드를 받습니다. (처음 11은 11로 두번째부터는 1로 사용합니다. (Ace 처리))
  3. 카드를 받고 사용자의 편의성을 위해 현재 어떤 값을 가지고 있는지 소지한 카드와 해당 카드들의 합계를 각각 출력해서 띄워줍니다.
  4. 사용자에게 숫자 카드를 더 받을건지 묻습니다. yes - 1장 더 / no - 결과 출력
  5. 이때 컴퓨터 카드가 17이하인 경우 17초과가 될 때까지 컴퓨터는 카드를 받습니다.
  6. 합계가 21이 되기 전 no일 경우 21에 더 가까운 사람이 승리합니다.
  7. 합계가 21이 되면 게임이 끝나고 바로 승패가 갈립니다.
  8. 합계가 21이 넘을 경우에도 바로 승패가 갈립니다.
  9. 게임이 끝난 후 게임을 다시 할 것인지 질문합니다.


1. 배열에 담기

사용자와 컴퓨터가 나눠 받을 카드의 숫자를 배열에 담아줍니다.

  • 여기서 A는 11 / J, Q, K는 10으로 처리하였습니다.
let cards = [11, 2, 3, 4, 5, 6, 7, 8, 9, 10, 10, 10, 10];


2. 카드 뽑기

Math.floor(Math.random( ))을 사용해서 랜덤으로 숫자를 받습니다.
카드를 받을 때 처음 11은 11로 두번째부터는 1로 사용합니다. (Ace 처리)

  • 카드를 뽑는 것은 반복적으로 이루어지기 때문에 함수로 만들어주었습니다.
  • random_Index라는 변수에 랜덤 난수를 담아주고 해당 숫자를 cards라는 배열에서 인덱스로 사용하였습니다. -> 매번 배열 안의 다른 숫자를 나눠줌(중복 o)
  • aceCount라는 변수를 생성하여 11이 나올 때 마다 값을 1씩 증가시킵니다.
  • aceCount가 1이라도 증가된 이후로 부터는 모두 1로 리턴하도록 하였습니다.
let aceCount = 0; // A 카드가 몇 번 사용되었는지 추적하는 변수

function random_card() {
	let random_Index = Math.floor(Math.random() * cards.length);
	let card = cards[random_Index];

	// A 카드가 처음 나올 때는 11로, 두 번째 이후는 1로 사용
	if (card === 11) {
		if (aceCount === 0) {
			aceCount++;
			return card; // 첫 번째 A는 11로 사용
		} else {
			return 1; // 두 번째 이후 A는 1로 사용
		}
	}

	return card;
}

처음에 사용자는 카드 2개 컴퓨터는 1개의 카드를 받습니다.

  • 게임을 시작할 것인지 묻고 y를 선택한 경우 카드를 랜덤으로 뽑습니다.
  • 사용자는 2장, 컴퓨터는 1장의 카드를 받게됩니다.
  • 받은 카드를 저장할 빈 배열을 생성합니다.
  • 카드를 받은 후 그 값을 배열에 push로 각각 담아줍니다.
let user_cards = []; // 사용자의 카드를 저장할 빈 배열 생성
let computer_cards = []; // 컴퓨터의 카드를 저장할 빈 배열 생성
let start = prompt("게임을 시작하시겠습니까? (y/n)");

if (start === "y") {
	user_cards.push(random_card(), random_card());
	computer_cards.push(random_card());
}


3. 현재 카드 보기

카드를 받고 현재 소지한 카드와 해당 카드들의 합계를 각각 출력해서 띄워줍니다.

  • 합계도 sum이라는 함수로 만들어주었습니다.
  • for문을 사용해 각각의 배열을 순회하여 합을 구해주었습니다.
  • 각각의 값을 객체로 반환하여 분할 대입으로 사용하였습니다.
function sum(array_user_cards, array_computer_cards) {
	let user_sum = 0;
	let computer_sum = 0;

	// user_cards의 합 구하기
	for (let i = 0; i < user_cards.length; i++) {
		user_sum += user_cards[i];
	}

	// computer_cards의 합 구하기
	for (let i = 0; i < computer_cards.length; i++) {
		computer_sum += computer_cards[i];
	}

	return { user_sum, computer_sum };
}

현재 소지한 카드와 카드의 합계를 보여줄 출력문을 작성합니다.

  • sum에서 받아오는 리턴값인 user_sum, computer_sum를 total이라는 변수에 담아줍니다.
  • total이라는 변수를 선언하지만 담긴 것은 객체이기에 total 자체를 객체라고 할 수 있습니다.
  • total이라는 객체에 접근해서 해당 값을 가져옵니다.
  • write라는 함수가 사용될 때 안에 받는 인수에 따라 조건을 걸어줍니다.
// player (user, computer)에 맞는 메시지를 출력
function write(player, total) {
	let message = "";

	if (player === "user") {
		message = `현재 유저 카드 : ${user_cards} \n숫자의 총 합계는 ${total.user_sum}입니다.`;
	} else {
		message = `현재 컴퓨터 카드 : ${computer_cards} \n총 합계는 ${total.computer_sum}입니다.`;
	}

	alert(message);
}

메인 코드에서의 함수 사용

  • total에 해당 합계를 sum함수를 사용해 미리 계산합니다.
  • write함수를 사용해 total값과 함께 인수를 받아옵니다.
  • 해당 인수에 따라 write함수 내의 if문이 실행됩니다.
let total = sum(user_cards, computer_cards); // 총합 미리 계산
write("user", total);
write("computer", total);


4. 추가 뽑기

사용자에게 숫자 카드를 더 받을건지 묻습니다.
yes - 1장 더 / no - 결과 출력

  • no일 경우 결과 출력은 밑에서 다루겠습니다.
  • 만들어 놓은 함수를 사용해 카드를 더 뽑습니다.
// 카드 뽑을지 여부 묻기
let question = prompt("카드를 더 뽑으시겠습니까? (y/n)");

if (question.toLowerCase() === "y") {
	user_cards.push(random_card()); // 유저 카드 뽑기
	total = sum(user_cards, computer_cards); // 다시 총합을 계산
	write("user", total);
}


5. 컴퓨터 예외

no일 때 컴퓨터 카드가 17이하인 경우 17초과가 될 때까지 컴퓨터는 카드를 받습니다.

  • while문을 활용해 반복을 돌리고 / 매번 total의 총 합을 갱신해줍니다.
  • 반복을 돌려 뽑은 카드는 push로 배열에 추가해줍니다.
while (total.computer_sum < 18) {
	alert("컴퓨터의 총 합계가 17이하이므로 카드를 뽑습니다.");
	computer_cards.push(random_card());
	total = sum(user_cards, computer_cards); // 총합을 갱신
	write("computer", total); // 카드를 뽑은 후 컴퓨터 카드 갱신
}


6-8. 결과 계산

합계가 21이 되기 전 no일 경우 21에 더 가까운 사람이 승리합니다.
합계가 21이 되면 게임이 끝나고 바로 승패가 갈립니다.
합계가 21이 넘을 경우에도 바로 승패가 갈립니다.

// 승자 결정 함수
function Winner(total) {
	if (total.user_sum > 21) {
		alert("유저가 21을 넘어서 컴퓨터가 승리하였습니다.");
	} else if (total.computer_sum > 21) {
		alert("컴퓨터가 21을 넘어서 유저가 승리하였습니다.");
	} else if (total.user_sum === 21) {
		alert("유저가 21을 만들어서 승리하였습니다.");
	} else if (total.computer_sum === 21) {
		alert("컴퓨터가 21을 만들어서 승리하였습니다.");
	} else if (total.user_sum < 21 && total.computer_sum < 21) {
		if (total.user_sum > total.computer_sum) {
			alert("유저가 승리하였습니다.");
		} else if (total.user_sum < total.computer_sum) {
			alert("컴퓨터가 승리하였습니다.");
		} else {
			alert("비겼습니다.");
		}
	}
}

21이 되거나 21이 넘을 경우 바로 종료하기 위해 따로 부분적으로 추가합니다.

  • 처음 gameOver변수를 false로 지정합니다.
  • if 조건을 넘을 경우 지정해놓은 false를 true를 재할당하여 반복문을 종료합니다.
let gameOver = false; // 게임 종료 여부를 추적하는 변수

while (!gameOver) {
	// 유저나 컴퓨터가 21을 만들면 게임 종료
	if (total.user_sum === 21 || total.computer_sum === 21) {
		Winner(total); // 21을 만들면 승자 판별
		gameOver = true;
	}
   
    if (total.user_sum > 21) {
		Winner(total); // 유저가 21을 넘었을 경우 승자 결정
		gameOver = true; // 게임 종료
	} else {
		computer_cards.push(random_card()); // 컴퓨터 카드 뽑기
		total = sum(user_cards, computer_cards); // 다시 총합을 계산
		write("computer", total);
	}
   
	if (total.computer_sum > 21) {
		Winner(total); // 컴퓨터가 21을 넘었을 경우 승자 결정
		gameOver = true; // 게임 종료
	}
}


9. 재시작 여부

게임이 끝난 후 게임을 다시 할 것인지 질문합니다.

  • 앞의 코드를 모두 startGame( )이라는 함수에 담고 재귀 호출해줍니다.
  • 다시 시작하기 전에 필요한 변수들을 모두 초기화하고 함수를 호출합니다.
  • 코드를 모두 startGame( )에 담아주었기 때문에 함수 밖에서 꼭 한번 호출을 해주셔야합니다.
// 게임이 끝난 후 다시 시작할지 여부 묻기
let restart = prompt("게임을 다시 시작하시겠습니까? (y/n)");

if (restart === "y" || restart === "") {
	// 게임을 초기화하고 다시 시작
	user_cards = [];
	computer_cards = [];
	aceCount = 0;
	alert("처음으로 되돌아갑니다.");
	startGame(); // 다시 게임 시작 함수 호출
} else {
	alert("게임을 종료하셨습니다.");
}


💌 전체 코드

  • 위에서 정리한 코드를 하나로 정리한 것입니다.
  • 함수도 사용하고 반복문도 꽤나 있어서 복잡할 수 있습니다.
<script>
  let cards = [11, 2, 3, 4, 5, 6, 7, 8, 9, 10, 10, 10, 10];
  let user_cards = [];
  let computer_cards = [];
  let aceCount = 0; // A 카드가 몇 번 사용되었는지 추적하는 변수

  // 게임 시작을 묻는 프롬프트
  startGame();

  function startGame() {
    let start = prompt("게임을 시작하시겠습니까? (y/n)");

    if (start === "y") {
      user_cards.push(random_card(), random_card());
      computer_cards.push(random_card());
      let total = sum(user_cards, computer_cards); // 총합 미리 계산
      write("user", total);
      write("computer", total);

      let gameOver = false; // 게임 종료 여부를 추적하는 변수

      while (!gameOver) {
        // 유저나 컴퓨터가 21을 만들면 게임 종료
        if (total.user_sum === 21 || total.computer_sum === 21) {
          Winner(total); // 21을 만들면 승자 판별
          gameOver = true;
        }

        // 카드 뽑을지 여부 묻기
        let question = prompt("카드를 더 뽑으시겠습니까? (y/n)");

        if (question === null || question.trim() === "") {
          alert("잘못된 입력입니다. y 또는 n을 입력해주세요.");
          continue; // 잘못된 입력이 들어오면 다시 묻기
        }

        if (question.toLowerCase() === "n") {
          // 컴퓨터가 17 이하일 경우 계속 카드를 뽑음
          while (total.computer_sum < 18) {
            alert("컴퓨터의 총 합계가 17이하이므로 카드를 뽑습니다.");
            computer_cards.push(random_card());
            total = sum(user_cards, computer_cards); // 총합을 갱신
            write("computer", total); // 카드를 뽑은 후 컴퓨터 카드 갱신
          }
          alert("현재 상황은?");
          write("user", total);
          write("computer", total);

          // 승자를 결정하는 함수 호출
          Winner(total);
          gameOver = true;
        } else if (question.toLowerCase() === "y") {
          user_cards.push(random_card()); // 유저 카드 뽑기
          total = sum(user_cards, computer_cards); // 다시 총합을 계산
          write("user", total);

          if (total.user_sum > 21) {
            Winner(total); // 유저가 21을 넘었을 경우 승자 결정
            gameOver = true; // 게임 종료
          } else {
            computer_cards.push(random_card()); // 컴퓨터 카드 뽑기
            total = sum(user_cards, computer_cards); // 다시 총합을 계산
            write("computer", total);

            if (total.computer_sum > 21) {
              Winner(total); // 컴퓨터가 21을 넘었을 경우 승자 결정
              gameOver = true; // 게임 종료
            }
          }
        }
      }
    } else {
      alert("게임을 포기하셨습니다.");
    }
  }

  // 승자 결정 함수
  function Winner(total) {
    if (total.user_sum > 21) {
      alert("유저가 21을 넘어서 컴퓨터가 승리하였습니다.");
    } else if (total.computer_sum > 21) {
      alert("컴퓨터가 21을 넘어서 유저가 승리하였습니다.");
    } else if (total.user_sum === 21) {
      alert("유저가 21을 만들어서 승리하였습니다.");
    } else if (total.computer_sum === 21) {
      alert("컴퓨터가 21을 만들어서 승리하였습니다.");
    } else if (total.user_sum < 21 && total.computer_sum < 21) {
      if (total.user_sum > total.computer_sum) {
        alert("유저가 승리하였습니다.");
      } else if (total.user_sum < total.computer_sum) {
        alert("컴퓨터가 승리하였습니다.");
      } else {
        alert("비겼습니다.");
      }
    }

    // 게임이 끝난 후 다시 시작할지 여부 묻기
    let restart = prompt("게임을 다시 시작하시겠습니까? (y/n)");

    if (restart === "y" || restart === "") {
      // 게임을 초기화하고 다시 시작
      user_cards = [];
      computer_cards = [];
      aceCount = 0;
      alert("처음으로 되돌아갑니다.");
      startGame(); // 다시 게임 시작 함수 호출
    } else {
      alert("게임을 종료하셨습니다.");
    }
  }

  // 랜덤 인덱스를 받아서 cards 안에 있는 숫자를 랜덤으로 반환
  function random_card() {
    let random_Index = Math.floor(Math.random() * cards.length);
    let card = cards[random_Index];

    // A 카드가 처음 나올 때는 11로, 두 번째 이후는 1로 사용
    if (card === 11) {
      if (aceCount === 0) {
        aceCount++;
        return card; // 첫 번째 A는 11로 사용
      } else {
        return 1; // 두 번째 이후 A는 1로 사용
      }
    }

    return card;
  }

  // user의 배열 안에 있는 숫자의 합을 반환
  function sum(array_user_cards, array_computer_cards) {
    let user_sum = 0;
    let computer_sum = 0;

    // user_cards의 합 구하기
    for (let i = 0; i < user_cards.length; i++) {
      user_sum += user_cards[i];
    }

    // computer_cards의 합 구하기
    for (let i = 0; i < computer_cards.length; i++) {
      computer_sum += computer_cards[i];
    }

    return { user_sum, computer_sum };
  }

  // player (user, computer)에 맞는 메시지를 출력
  function write(player, total) {
    let message = "";

    if (player === "user") {
      message = `현재 유저 카드 : ${user_cards} \n숫자의 총 합계는 ${total.user_sum}입니다.`;
    } else {
      message = `현재 컴퓨터 카드 : ${computer_cards} \n총 합계는 ${total.computer_sum}입니다.`;
    }

    alert(message);
  }
</script>



과제 후기

  • 블랙잭이라는 게임 자체를 몰라서 좀 어려웠습니다.
  • 원하는대로 배열에 값이 안담긴다던가 안뜨면 오히려 오류 검출이 쉬울텐데 함수에 관련된 오류는 콘솔로 찾는 것도 한계가 있어서 너무 힘들었습니다.
  • 제가 만든 변수를 헷갈리고.. 여러 번 사용을 하는게 많다보니 함수로 만든 부분이 많은데.. 이것 때문에 조금 더 오래 걸린 것 같습니다.
  • 코드 작성 조차 애매하고 어떤 부분을 함수로 빼야할지 막막해서 그냥 쭉 코드를 작성했었는데.. 그 결과 리펙토링과 함께 총 3번 블랙잭을 만들었습니다.
  • 객체와 분할 대입에 관련한 내용은 따로 개념 정리 포스팅을 하겠습니다!
  • 많이 만들어봐도 좀 헷갈리고.. 힘든 것 같습니다. 그래도 화이팅! (۶•̀ᴗ•́)۶
profile
૮꒰ ྀི〃´꒳`〃꒱ა

0개의 댓글