You are on page 1of 9

<!

DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<title></title>
<meta name="description" content="">
<meta name="viewport" content="width=device-width, initial-scale=1">
<style>
* {
margin: 0;
padding: 0;
box-sizing: border-box;
font-family: 'Arial';
}

h1 {
font-family: "PixelGameFont";
margin: 30px;
}

button {
margin: 30px;
}

button {
height: 20px;
width: 100px;
background: #48955C;
color: white;
font-family: "PixelGameFont";
outline: none;
cursor: pointer;
border: 1px solid black;
}

.card {
height: 100px;
width: 70px;
border: 1px solid black;
padding: 5px;
}

.card p {
font-size: 30px;
font-family: 'PixelGameFont';
}

.card svg {
transform: scale(1);
}

.card-red p {
color: #FF0000;
}

.card-blank {
background: #48955C;
}
.gameArea {
display: grid;
grid-template-rows: 1fr 1fr;
grid-row-gap: 50px;;
justify-content: center;
align-items: center;
}

.dealerArea {
display: flex;
gap: 5px;
justify-content: center;
align-items: center;
}

.playerArea {
display: flex;
gap: 5px;
justify-content: center;
align-items: center;
}

.rules {
margin: 30px;
}
</style>
</head>
<body>
<h1>BLACKJACK</h1>
<button onclick="startGame()">PLAY</button>
<div class="rules">
<h2>Rules</h2>
<p>At the start of each round of blackjack you are given two cards and the
dealer gets two cards — one face-up and one face-down. You should first count the
value of them. Cards with numbers are valued at their given number and
Jacks, Queens and
Kings are valued at 10. On the other hand, the ace is valued at 1 or 11,
depending on what's more beneificial to you.
Your goal is to get the value of your cards higher than the value of the
dealer's without exceeding 21. If you do, you
lose the game. It's at this point in your turn that you make a decision —
hit or stray. When you hit
you're able to get another random card from the deck. If the new total
value of your cards exceeds 21,
you automatically lose. However, if your card's values are equal or less
than 21 you get to make the choice to hit or to stray once again.
If you choose to stray, the dealer reveals his face-down card. The value
of both of your cards are comapred and whoever has a higher value wins the round.
If the value of both of your hands are tied, the round is called a tie and
played again.
</p>
</div>
<script async defer>
//Set both the player's and the computer's score to 0 as the game just
started
let playerScore = 0;
let dealerScore = 0;
//A function to check if two objects are equal. Javascript can't check if
two objects are equal so a function had to be made for it
function objectEquals(obj1, obj2) {
for (var i in obj1) {
if (obj1.hasOwnProperty(i)) {
if (!obj2.hasOwnProperty(i)) return false;
if (obj1[i] != obj2[i]) return false;
}
}
for (var i in obj2) {
if (obj2.hasOwnProperty(i)) {
if (!obj1.hasOwnProperty(i)) return false;
if (obj1[i] != obj2[i]) return false;
}
}
return true;
}

//A function to draw a random card from the deck


function drawCard() {
//All possible "numbers" for playing cards
const cards = [
"A",
"J",
"Q",
"K",
"2",
"3",
"4",
"5",
"6",
"7",
"8",
"9"
]

//All possible "variants" for playing cards


const variants = [
"clover",
"spade",
"heart",
"diamond"
]

//By picking one random number and one random variant you end up with a
completely random card
const number = cards[Math.floor(Math.random()*cards.length)];
const variant = variants[Math.floor(Math.random()*variants.length)];
return {number: number, variant: variant}
}

//A function to generate the HTML code needed to display a card


function generateHTMLCodeForCard(card) {
//if the card is red make its class "card card-red" and if it's black
make its class "card card-black"
const className = `card card-${(card.variant === "diamond" ||
card.variant == "heart" ? "red" : "black")}`

//the svg code for the different variants of the cards, this will be
added later on to add a visual element to the cards
const icons = {
clover: `<svg xmlns="http://www.w3.org/2000/svg" width="15.6978"
height="15.6753" viewBox="0 0 156.978 156.753">
<path id="path2" d="M282.308,227.8c-20.909,5.57-30.412,27.483-
20.484,47.231,2.2,4.374,4.088,7.112,10.962,15.889,6.764,8.639,11.643,16.443,10.8,17
.282-.075.075-2.955-2.062-6.4-4.748-18.165-14.159-22.365-16.153-34.112-16.2-
13.229-.047-23.477,6.426-29.067,18.359-
9.323,19.9,4.908,43.505,26.8,44.445,12.157.522,17.915-1.958,34.469-14.845,8.153-
6.348,10.257-7.794,10.257-7.049,0,.655-2.225,9.45-3.873,15.306-4.169,14.819-
10.161,29.961-15,37.908a12.308,12.308,0,0,0-
1.125,2.119c0,.32,2.155.126,7.076-.637,5.14-.8,28.572-.788,33.847.012,4.879.74,7.07
6.943,7.076.652a35.981,35.981,0,0,0-1.832-3.506c-5.778-10.281-10.732-23.532-15.652-
41.871-1.964-7.317-2.514-9.811-2.208-
10,.325-.2,3.505,2.1,11.15,8.069,14.71,11.483,19.872,13.764,31.158,13.77,28.591.014
,42.558-33.291,22.461-53.561-6.624-6.681-12.873-9.205-22.769-9.2-11.4.009-
16.016,2.251-34.459,16.728-5.781,4.537-6.176,4.785-5.836,3.652.975-3.249,3.924-
7.728,11.5-17.462,13.086-16.817,16.28-26.249,13.24-39.1-3.852-16.289-22.123-27.472-
37.981-23.248" transform="translate(-211.105 -226.906)" fill-rule="evenodd"/>
</svg>
`,
spade: `<svg xmlns="http://www.w3.org/2000/svg" width="14.462"
height="15.6914" viewBox="0 0 144.62 156.914">
<path id="path1" d="M92.067,22.808c-.7.2-3.179,2.412-
8.159,7.28A290.107,290.107,0,0,1,62,49.694C43.75,64.928,36.78,71.879,30.837,80.769c
-17.224,25.766-
8.606,57.873,17.778,66.24,5.089,1.614,6.154,1.756,13.077,1.749l6.462-.006,2.923-
1.008a59.741,59.741,0,0,0,12.087-5.87c3.554-2.3,3.378-2.327,2.622.357-2.486,8.828-
8.577,24.039-12.351,30.846-.657,1.185-1.68,3.026-2.274,4.092-1.387,2.488-
1.524,2.434,4.127,1.631a156.867,156.867,0,0,1,37.444-.029c6.384.9,6.1,1.185,3.466-
3.54a131.927,131.927,0,0,1-7.739-16.616c-2.288-5.848-6.479-18.236-6.248-
18.467a14.322,14.322,0,0,1,3.088,1.676,53.805,53.805,0,0,0,11.674,5.743l3.489,1.2,6
.461-.013c25.727-.051,42.829-20.374,39.085-46.444-2.513-17.5-11-28.8-39.393-
52.465C115.525,40.6,111.279,36.815,104.133,29.8c-7.772-7.629-8.467-8.031-12.066-
6.993" transform="translate(-21.902 -22.389)" fill-rule="evenodd"/>
</svg>
`,
heart: `<svg xmlns="http://www.w3.org/2000/svg" width="15.6981"
height="13.7105" viewBox="0 0 156.981 137.105">
<path id="path0" d="M245.64,33.356c-32.583,6.36-44.965,42.857-
24.827,73.185,6.209,9.352,12.838,15.944,33.495,33.309,15.582,13.1,20.768,17.768,27.
057,24.358,7.3,7.646,8.909,7.486,18.165-1.813,6.483-6.512,11.927-11.379,24.316-
21.742,24.576-20.556,32.766-29.341,38.615-41.422,16.312-33.689-4.95-68.627-40.471-
66.506-9.28.554-19.939,6-29.612,15.117l-2.854,2.691-2.531-2.426c-13.314-12.759-
26.839-17.583-41.353-14.751" transform="translate(-211.058 -32.572)" fill="red"
fill-rule="evenodd"/>
</svg>
`,
diamond: `<svg xmlns="http://www.w3.org/2000/svg" width="13.0473"
height="15.6971" viewBox="0 0 130.473 156.971">
<path id="path3" d="M91.867,227.564c-1.9.7-2.649,1.568-29.139,34.128-
35.712,43.9-33.313,40.73-
33.331,44l-.012,2.181,2.139,2.758c5.423,6.991,43.208,53.729,51.316,63.475,6.646,7.9
88,7.764,9.135,9.314,9.559,3.555.972,5.779.094,8.883-3.506,5.415-6.283,28.352-
34.452,48.479-59.539,11.04-13.76,11.558-14.8,9.162-18.421-2.333-3.526-52.237-
65.132-58.289-71.958-2.662-3-5.335-3.84-8.522-2.672" transform="translate(-29.369 -
227.058)" fill="red" fill-rule="evenodd"/>
</svg>`
}
//return the full HTML code for the card
return `
<div class="${className}">
<p>${card.number}</p>
${icons[card.variant]}
</div>`
}

//get the value of a set of cards (ex. get the value of the dealers hand)
function getValueOfCards(cards) {
let totalValue = 0;
for (const card of cards) {
//If the card is Jack, Queen or King the value is 10
if (card.number === "J" || card.number === "Q" || card.number === "K")
{
totalValue += 10;
} else if (card.number === "A") {
//If it's ace we have to determine which value(11 or 1) is more
beneficial
//This is why we use an if statement to check if a value of 11 will
make it go over 21
if (totalValue + 11 <= 21) {
totalValue += 11;
} else {
totalValue += 1;
}
//If the value is 10, add 10 to the totalValue
} else if (card.number == 10) {
totalValue += 10;
//If its any other value(meaning it's an integer between 1-9),
convert its number to an integer and add it to the totalValue
} else {
totalValue += Number(card.number);
}
}
return totalValue;
}

//A function to restart the game. This is used when the game finishes and
there's a play again option
function resetGame() {
//Reset the scores of the comoputer and the player
playerScore = 0;
dealerScore = 0;

startGame();
}

//Game Start
let round;
//A function to start the game
function startGame() {
alert("Welcome and good luck!")
round = new Round;
}

//This class contains everything necessary to play 1 round of blackjack,


whenever the round finishes, a new instance of Round is created to start another
round
class Round {
constructor() {
//Default values at teh start of a round
this.drawnCards = [];
this.isDone = false;

//Draw the four cards necessary to start a round of blackjack(2 for the
dealer and 2 for the player)
for (let i=0; i < 4; i++) {
//Check for duplicates
//ex. if a card that was already drawn previously is drawn, draw
another random card
let foundNewCard = false;
while (!foundNewCard) {
const newCard = drawCard();
let foundDuplicate = false;
for (const drawnCard of this.drawnCards) {
if (objectEquals(drawnCard, newCard)) {
foundDuplicate=true;
}
}
if (!foundDuplicate) {
foundNewCard = true;
this.drawnCards.push(newCard);
}
}
}

//Declaring blank HTML statements that will be


let finalHTML = ""
let dealerHTML = "";
let playerHTML = "";
//Generate HTML for the cards
dealerHTML += generateHTMLCodeForCard(this.drawnCards[0]);
dealerHTML += `<div class="card card-blank"></div>`;
finalHTML = `<div class="scoreBox">Your score: ${playerScore}, Dealer
Score: ${dealerScore}</div>`
finalHTML += `<div class="dealerArea">${dealerHTML}</div>`;
for (let i = 2; i < 4; i++) {
playerHTML += generateHTMLCodeForCard(this.drawnCards[i]);
}
finalHTML += `<div class="playerArea">${playerHTML}</div>`

finalHTML = `<div class="gameArea">${finalHTML}</div>`


finalHTML += `<button onclick="round.hit()">HIT</button><button
onclick="round.stray()">STAY</button>`

//Put the generated HTML on the DOM


document.getElementsByTagName("body")[0].innerHTML = finalHTML;

//If one of the scores is equal to 7, immediately stop the game and
display the winning or lossing message with a play again button.
if (playerScore >= 7) {
document.getElementsByTagName("body")[0].innerHTML =
`<p>Congratulations you won!</p><button onclick="resetGame()">PLAY AGAIN</button>`;
round = null;
} else if (dealerScore >= 7) {
document.getElementsByTagName("body")[0].innerHTML = `<p>Better luck
next time :(</p><button onclick="resetGame()">PLAY AGAIN</button>`;
round = null;
}
}

//Method that gets called when the loser hits


hit() {
//Draw one random card and make sure it has no duplicates
for (let i=0; i < 1; i++) {
let foundNewCard = false;
while (!foundNewCard) {
const newCard = drawCard();
let foundDuplicate = false;
for (const drawnCard of this.drawnCards) {
if (objectEquals(drawnCard, newCard)) {
foundDuplicate=true;
}
}
if (!foundDuplicate) {
foundNewCard = true;
this.drawnCards.push(newCard);
}
}
}

//Get all of the player's cards and seperate them from the dealer's
cards
let playerCards = []
for (let i=2; i < this.drawnCards.length; i++) {
playerCards.push(this.drawnCards[i]);
}
//Render all of the player's cards(they're different since one was
drawn)
this.render();
//If the player's card value is greater than 21, then show a message
saying that the player lost and start a new round after 0.5 seconds
if (getValueOfCards(playerCards) > 21 && !this.isDone) {
dealerScore += 1;
alert("YOU LOST");
this.isDone = true;
setTimeout(() => {round = new Round;}, 1000)
}
}

//Method for when the user clicks on stray


stray() {
//Generating HTML to show the dealer's hidden card(most of this was
already explained above)
let finalHTML = ""
let dealerHTML = "";
let playerHTML = "";
dealerHTML += generateHTMLCodeForCard(this.drawnCards[0]);
dealerHTML += generateHTMLCodeForCard(this.drawnCards[1]);
finalHTML = `<div class="scoreBox">Your score: ${playerScore}, Dealer
Score: ${dealerScore}</div>`
finalHTML += `<div class="dealerArea">${dealerHTML}</div>`;

for (let i = 2; i < this.drawnCards.length; i++) {


playerHTML += generateHTMLCodeForCard(this.drawnCards[i]);
}
finalHTML += `<div class="playerArea">${playerHTML}</div>`

finalHTML = `<div class="gameArea">${finalHTML}</div>`


finalHTML += `<button onclick="round.hit()">HIT</button><button
onclick="round.stray()">STAY</button>`
document.getElementsByTagName("body")[0].innerHTML = finalHTML;

//Seperate the player's cards again from the dealer's hand


let playerCards = []
for (let i=2; i < this.drawnCards.length; i++) {
playerCards.push(this.drawnCards[i]);
}
//If the dealers hand value is greater than the player's hand value,
the player loses and is displayed a messaging saying they lost
if (getValueOfCards([this.drawnCards[0], this.drawnCards[1]]) >
getValueOfCards(playerCards) && !this.isDone) {
dealerScore += 1;
alert("YOU LOST");
this.isDone = true;
setTimeout(() => {round = new Round;}, 1000)
// If the player's hand value and dealer's hand value are equal, the
round is declared a tie and no one wins
} else if (getValueOfCards([this.drawnCards[0], this.drawnCards[1]])
=== getValueOfCards(playerCards) && !this.isDone) {
alert("TIE");
this.isDone = true;
setTimeout(() => {round = new Round;}, 1000)
// If both conditions above are false then playerHandValue must be
greater than dealerHandValue, meaning that the player won
} else if (!this.isDone) {
playerScore += 1;
alert("YOU WON");
this.isDone = true;
setTimeout(() => {round = new Round;}, 1000)
}
}

//A method to render cards in the DOM when they're updated(ex. when a
card is drawn)
render() {
//Blank HTML
let finalHTML = ""
let dealerHTML = "";
let playerHTML = "";

//add the dealer's cards with his second face-down


dealerHTML += generateHTMLCodeForCard(this.drawnCards[0]);
dealerHTML += `<div class="card card-blank"></div>`;
finalHTML = `<div class="scoreBox">Your score: ${playerScore}, Dealer
Score: ${dealerScore}</div>`
finalHTML += `<div class="dealerArea">${dealerHTML}</div>`;

//add all of the player's cards both of which must be face-up


for (let i = 2; i < this.drawnCards.length; i++) {
playerHTML += generateHTMLCodeForCard(this.drawnCards[i]);
}
finalHTML += `<div class="playerArea">${playerHTML}</div>`
finalHTML = `<div class="gameArea">${finalHTML}</div>`
finalHTML += `<button onclick="round.hit()">HIT</button><button
onclick="round.stray()">STAY</button>`

//render by changing the innerHTML


document.getElementsByTagName("body")[0].innerHTML = finalHTML;
}
}
</script>
</body>
</html>

You might also like