2025 / 01 / 31
오늘은 수업 시간에 받은 과제를 포스팅하겠습니다!
지금까지 배운 내용을 활용해서 블랙잭이라는 게임을 만들어보았습니다.
예외처리도 좀 있고 조건도 많아서 좀 어려웠지만! 최대한 쉽게 작성해보겠습니다.
만드는 순서
- 사용자와 컴퓨터가 나눠 받을 카드의 숫자를 배열에 담아줍니다.
- 처음에 사용자는 카드 2개 컴퓨터는 1개의 카드를 받습니다. (처음 11은 11로 두번째부터는 1로 사용합니다. (Ace 처리))
- 카드를 받고 사용자의 편의성을 위해 현재 어떤 값을 가지고 있는지 소지한 카드와 해당 카드들의 합계를 각각 출력해서 띄워줍니다.
- 사용자에게 숫자 카드를 더 받을건지 묻습니다. yes - 1장 더 / no - 결과 출력
- 이때 컴퓨터 카드가 17이하인 경우 17초과가 될 때까지 컴퓨터는 카드를 받습니다.
- 합계가 21이 되기 전 no일 경우 21에 더 가까운 사람이 승리합니다.
- 합계가 21이 되면 게임이 끝나고 바로 승패가 갈립니다.
- 합계가 21이 넘을 경우에도 바로 승패가 갈립니다.
- 게임이 끝난 후 게임을 다시 할 것인지 질문합니다.
사용자와 컴퓨터가 나눠 받을 카드의 숫자를 배열에 담아줍니다.
- 여기서 A는 11 / J, Q, K는 10으로 처리하였습니다.
let cards = [11, 2, 3, 4, 5, 6, 7, 8, 9, 10, 10, 10, 10];
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()); }
카드를 받고 현재 소지한 카드와 해당 카드들의 합계를 각각 출력해서 띄워줍니다.
- 합계도 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);
사용자에게 숫자 카드를 더 받을건지 묻습니다.
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); }
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); // 카드를 뽑은 후 컴퓨터 카드 갱신 }
합계가 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; // 게임 종료 } }
게임이 끝난 후 게임을 다시 할 것인지 질문합니다.
- 앞의 코드를 모두 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번 블랙잭을 만들었습니다.
- 객체와 분할 대입에 관련한 내용은 따로 개념 정리 포스팅을 하겠습니다!
- 많이 만들어봐도 좀 헷갈리고.. 힘든 것 같습니다. 그래도 화이팅! (۶•̀ᴗ•́)۶