diff --git a/index.html b/index.html index d2c3c254..701a74a5 100644 --- a/index.html +++ b/index.html @@ -16,13 +16,13 @@ -

TypeScript Casino

+

Casnio Royale With Cheese

- +
diff --git a/js/app.js b/js/app.js new file mode 100644 index 00000000..4edea0d5 --- /dev/null +++ b/js/app.js @@ -0,0 +1,758 @@ +"use strict"; +var __extends = (this && this.__extends) || (function () { + var extendStatics = Object.setPrototypeOf || + ({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) || + function (d, b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; }; + return function (d, b) { + extendStatics(d, b); + function __() { this.constructor = d; } + d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __()); + }; +})(); +var Startup = /** @class */ (function () { + function Startup() { + } + Startup.main = function () { + var casino = new Casino(); + casino.start(); + }; + return Startup; +}()); +var Profile = /** @class */ (function () { + function Profile(name, balance) { + this._id = Profile._lastId; + Profile._lastId++; + this._name = name; + this._balance = balance; + } + Object.defineProperty(Profile.prototype, "id", { + get: function () { + return this._id; + }, + enumerable: true, + configurable: true + }); + Object.defineProperty(Profile.prototype, "name", { + get: function () { + return this._name; + }, + enumerable: true, + configurable: true + }); + Object.defineProperty(Profile.prototype, "balance", { + get: function () { + return this._balance; + }, + set: function (newBalance) { + this._balance = newBalance; + }, + enumerable: true, + configurable: true + }); + Profile.prototype.addToBalance = function (amount) { + this._balance += amount; + }; + Profile._lastId = 1; + return Profile; +}()); +var Player = /** @class */ (function () { + function Player(playerProfile) { + this._playerProfile = playerProfile; + } + Player.prototype.getProfile = function () { + return this._playerProfile; + }; + Player.prototype.getName = function () { + return this._playerProfile.name; + }; + Player.prototype.getId = function () { + return this._playerProfile.id; + }; + return Player; +}()); +var CardPlayer = /** @class */ (function (_super) { + __extends(CardPlayer, _super); + function CardPlayer(profile) { + var _this = _super.call(this, profile) || this; + _this._hand = new Hand(); + return _this; + } + CardPlayer.prototype.takeCard = function (card) { + this._hand.cards.push(card); + }; + CardPlayer.prototype.discardAll = function () { + while (this._hand.cards.length > 0) { + this._hand.cards.pop(); + } + }; + Object.defineProperty(CardPlayer.prototype, "hand", { + get: function () { + return this._hand; + }, + enumerable: true, + configurable: true + }); + return CardPlayer; +}(Player)); +var BlackJackPlayer = /** @class */ (function (_super) { + __extends(BlackJackPlayer, _super); + function BlackJackPlayer(profile) { + var _this = _super.call(this, profile) || this; + _this.escrow = new Escrow(); + return _this; + } + BlackJackPlayer.prototype.bet = function (amount) { + this.escrow.addToEscrowBalance(amount); + this.getProfile().balance -= amount; + }; + BlackJackPlayer.prototype.win = function (multiplier) { + var winnings = this.escrow.escrowBalance + (this.escrow.escrowBalance * multiplier); + this.getProfile().addToBalance(winnings); + this.escrow.escrowBalance = 0; + }; + BlackJackPlayer.prototype.lose = function () { + this.escrow.escrowBalance = 0; + }; + Object.defineProperty(BlackJackPlayer.prototype, "busted", { + get: function () { + return this.busted; + }, + set: function (state) { + this._busted = state; + }, + enumerable: true, + configurable: true + }); + Object.defineProperty(BlackJackPlayer.prototype, "stand", { + get: function () { + return this._stand; + }, + set: function (state) { + this._stand = state; + }, + enumerable: true, + configurable: true + }); + Object.defineProperty(BlackJackPlayer.prototype, "score", { + get: function () { + return this._score; + }, + set: function (amount) { + this._score = amount; + }, + enumerable: true, + configurable: true + }); + BlackJackPlayer.prototype.isBusted = function () { + if (this._score > 21) { + return true; + } + else { + return false; + } + }; + BlackJackPlayer.prototype.calculateScore = function () { + var hasAce = false; + var tempScore = 0; + this.hand.cards.forEach(function (element) { + if (element.rank === Rank.TWO) + tempScore += 2; + else if (element.rank === Rank.THREE) + tempScore += 3; + else if (element.rank === Rank.FOUR) + tempScore += 4; + else if (element.rank === Rank.FIVE) + tempScore += 5; + else if (element.rank === Rank.SIX) + tempScore += 6; + else if (element.rank === Rank.SEVEN) + tempScore += 7; + else if (element.rank === Rank.EIGHT) + tempScore += 8; + else if (element.rank === Rank.NINE) + tempScore += 9; + else if (element.rank === Rank.TEN) + tempScore += 10; + else if (element.rank === Rank.JACK) + tempScore += 10; + else if (element.rank === Rank.QUEEN) + tempScore += 10; + else if (element.rank === Rank.KING) + tempScore += 10; + else if (element.rank === Rank.ACE) { + tempScore += 11; + hasAce = true; + } + }); + if (tempScore > 21 && hasAce) { + tempScore = 0; + this.hand.cards.forEach(function (element) { + if (element.rank === Rank.TWO) + tempScore += 2; + else if (element.rank === Rank.THREE) + tempScore += 3; + else if (element.rank === Rank.FOUR) + tempScore += 4; + else if (element.rank === Rank.FIVE) + tempScore += 5; + else if (element.rank === Rank.SIX) + tempScore += 6; + else if (element.rank === Rank.SEVEN) + tempScore += 7; + else if (element.rank === Rank.EIGHT) + tempScore += 8; + else if (element.rank === Rank.NINE) + tempScore += 9; + else if (element.rank === Rank.TEN) + tempScore += 10; + else if (element.rank === Rank.JACK) + tempScore += 10; + else if (element.rank === Rank.QUEEN) + tempScore += 10; + else if (element.rank === Rank.KING) + tempScore += 10; + else if (element.rank === Rank.ACE) { + tempScore += 1; + } + }); + } + this._score = tempScore; + }; + return BlackJackPlayer; +}(CardPlayer)); +var Escrow = /** @class */ (function () { + function Escrow() { + this._escrowBalance = 0; + } + Object.defineProperty(Escrow.prototype, "escrowBalance", { + get: function () { + return this._escrowBalance; + }, + set: function (amount) { + this._escrowBalance = amount; + }, + enumerable: true, + configurable: true + }); + Escrow.prototype.addToEscrowBalance = function (amount) { + this._escrowBalance; + amount; + this.escrowBalance = this.escrowBalance + amount; + }; + return Escrow; +}()); +var Suit; +(function (Suit) { + Suit[Suit["HEARTS"] = 0] = "HEARTS"; + Suit[Suit["CLUBS"] = 1] = "CLUBS"; + Suit[Suit["DIAMONDS"] = 2] = "DIAMONDS"; + Suit[Suit["SPADES"] = 3] = "SPADES"; +})(Suit || (Suit = {})); +var Rank; +(function (Rank) { + Rank[Rank["TWO"] = 0] = "TWO"; + Rank[Rank["THREE"] = 1] = "THREE"; + Rank[Rank["FOUR"] = 2] = "FOUR"; + Rank[Rank["FIVE"] = 3] = "FIVE"; + Rank[Rank["SIX"] = 4] = "SIX"; + Rank[Rank["SEVEN"] = 5] = "SEVEN"; + Rank[Rank["EIGHT"] = 6] = "EIGHT"; + Rank[Rank["NINE"] = 7] = "NINE"; + Rank[Rank["TEN"] = 8] = "TEN"; + Rank[Rank["JACK"] = 9] = "JACK"; + Rank[Rank["QUEEN"] = 10] = "QUEEN"; + Rank[Rank["KING"] = 11] = "KING"; + Rank[Rank["ACE"] = 12] = "ACE"; +})(Rank || (Rank = {})); +var Card = /** @class */ (function () { + function Card(rank, suit) { + this._suit = suit; + this._rank = rank; + } + Object.defineProperty(Card.prototype, "suit", { + get: function () { + return this._suit; + }, + enumerable: true, + configurable: true + }); + Object.defineProperty(Card.prototype, "rank", { + get: function () { + return this._rank; + }, + enumerable: true, + configurable: true + }); + Card.prototype.toString = function () { + if (this._suit === Suit.CLUBS) { + return Rank[this._rank] + " \u2663"; + } + else if (this._suit === Suit.DIAMONDS) { + return Rank[this._rank] + " \u2666"; + } + else if (this._suit === Suit.SPADES) { + return Rank[this._rank] + " \u2660"; + } + else if (this._suit === Suit.HEARTS) { + return Rank[this._rank] + " \u2665"; + } + else { + throw new Error("Something has gone horribly wrong"); + } + }; + return Card; +}()); +var Deck = /** @class */ (function () { + function Deck() { + this._cards = new Array(); + this.populate(); + } + Deck.prototype.deal = function () { + return this._cards.pop(); + }; + Deck.prototype.shuffle = function () { + this._cards.sort(function (a, b) { return 0.5 - Math.random(); }); + }; + Deck.prototype.populate = function () { + for (var suit = Suit.HEARTS; suit <= Suit.SPADES; suit++) { + for (var rank = Rank.TWO; rank <= Rank.ACE; rank++) { + this._cards.push(new Card(rank, suit)); + } + } + }; + Deck.prototype.getSize = function () { + return this._cards.length; + }; + return Deck; +}()); +var Hand = /** @class */ (function () { + function Hand() { + this._cards = new Array(); + } + Object.defineProperty(Hand.prototype, "cards", { + get: function () { + return this._cards; + }, + enumerable: true, + configurable: true + }); + return Hand; +}()); +var GameEngine = /** @class */ (function () { + function GameEngine() { + } + return GameEngine; +}()); +var CardGame = /** @class */ (function (_super) { + __extends(CardGame, _super); + function CardGame() { + var _this = _super.call(this) || this; + _this._players = new Array(); + _this._deck = new Deck(); + _this._deck.shuffle(); + return _this; + } + Object.defineProperty(CardGame.prototype, "deck", { + get: function () { + return this._deck; + }, + enumerable: true, + configurable: true + }); + CardGame.prototype.replaceDeck = function () { + this._deck = new Deck(); + this._deck.shuffle(); + }; + CardGame.prototype.getPlayers = function () { + return this._players; + }; + CardGame.prototype.getPlayer = function (playerId) { + this._players.forEach(function (element) { + if (element.getId() === playerId) { + return element; + } + }); + throw new Error("Player not found"); + }; + CardGame.prototype.addPlayer = function (player) { + this._players.push(player); + }; + CardGame.prototype.removePlayer = function (player) { + this._players.splice(this._players.indexOf(player), 1); + }; + CardGame.prototype.contains = function (player) { + this._players.forEach(function (element) { + if (element === player) { + return true; + } + }); + return false; + }; + return CardGame; +}(GameEngine)); +var BlackJackGame = /** @class */ (function (_super) { + __extends(BlackJackGame, _super); + function BlackJackGame(playerProfile) { + var _this = _super.call(this) || this; + _this.dealer = new BlackJackPlayer(new Profile('Dealer', 0)); + _this.currentPlayer = new BlackJackPlayer(playerProfile); + _this.addPlayer(_this.dealer); + _this.addPlayer(_this.currentPlayer); + _this.startRound = _this.startRound.bind(_this); + _this.placeBet = _this.placeBet.bind(_this); + _this.run = _this.run.bind(_this); + _this.initialDeal = _this.initialDeal.bind(_this); + _this.restart = _this.restart.bind(_this); + _this.naturalCheck = _this.naturalCheck.bind(_this); + _this.nextMove = _this.nextMove.bind(_this); + _this.hitOrStand = _this.hitOrStand.bind(_this); + return _this; + } + BlackJackGame.prototype.start = function () { + UI.clearScreen(); + this.header(); + UI.display("Welcome to Black Jack"); + UI.display("Press [submit] to begin"); + UI.button.addEventListener("click", this.run, { once: true }); + }; + BlackJackGame.prototype.run = function () { + this.startRound(); + }; + BlackJackGame.prototype.evaluateTurn = function () { + UI.clearScreen(); + this.tallyScores(); + this.dealerTurn(); + this.tallyScores(); + this.header(); + this.showCards(false); + if (!this.isWinner()) { + this.nextMove(false); + } + if (this.currentPlayer.stand) { + this.evaluateTurn(); + } + }; + BlackJackGame.prototype.isWinner = function () { + if (this.currentPlayer.isBusted() && this.dealer.isBusted()) { + this.currentPlayer.win(0); + this.endScreen(); + UI.display("You and the Dealer are both Bust"); + UI.display("You break even"); + this.restart(); + return true; + } + else if (this.currentPlayer.isBusted()) { + this.currentPlayer.lose(); + this.endScreen(); + UI.display("You went Bust"); + UI.display("You lose your bet"); + this.restart(); + return true; + } + else if (this.dealer.isBusted()) { + this.currentPlayer.win(1); + this.endScreen(); + UI.display("The Dealer went Bust!"); + UI.display("Your bet pays even money!"); + this.restart(); + return true; + } + else if (this.currentPlayer.stand && this.dealer.stand) { + if (this.currentPlayer.score === this.dealer.score) { + this.currentPlayer.win(0); + this.endScreen(); + UI.display("The Dealer has the same score as you. You push"); + UI.display("You break even"); + this.restart(); + return true; + } + else if (this.currentPlayer.score > this.dealer.score) { + this.currentPlayer.win(1); + this.endScreen(); + UI.display("You have a higher score. You win!"); + UI.display("Yor bet pays even money!"); + this.restart(); + return true; + } + else if (this.currentPlayer.score < this.dealer.score) { + this.currentPlayer.lose(); + this.endScreen(); + UI.display("The Dealer has a higher score. You lose"); + UI.display("You lose your bet"); + this.restart(); + return true; + } + } + else { + return false; + } + }; + BlackJackGame.prototype.endScreen = function () { + UI.clearScreen(); + this.header(); + this.showCards(true); + }; + BlackJackGame.prototype.startRound = function (errorMessage) { + this.currentPlayer.discardAll(); + this.dealer.discardAll(); + UI.clearScreen(); + this.header(); + UI.display("How much would you like to bet?"); + UI.display("The minimum bet is $10"); + if (typeof errorMessage !== "undefined") + UI.display(errorMessage); + UI.button.addEventListener("click", this.placeBet); + }; + BlackJackGame.prototype.placeBet = function () { + UI.button.removeEventListener("click", this.placeBet); + UI.clearScreen(); + if (UI.lastInput <= this.currentPlayer.getProfile().balance && UI.lastInput > 10) { + this.currentPlayer.bet(parseInt(UI.lastInput)); + this.initialDeal(); + } + else if (UI.lastInput < 10) { + this.startRound("That amount is below the minimum bet"); + } + else if (UI.lastInput > this.currentPlayer.getProfile().balance) { + this.startRound("You cannot bet more money than you have"); + } + else { + this.startRound("You must input a number to place a bet"); + } + }; + BlackJackGame.prototype.initialDeal = function () { + UI.clearScreen(); + this.currentPlayer.takeCard(this.deck.deal()); + this.dealer.takeCard(this.deck.deal()); + this.currentPlayer.takeCard(this.deck.deal()); + this.dealer.takeCard(this.deck.deal()); + this.tallyScores(); + this.header(); + this.showCards(false); + var natural = this.naturalCheck(); + if (!natural) { + this.nextMove(false); + } + }; + BlackJackGame.prototype.dealerTurn = function () { + if (this.dealer.score < 17) { + this.dealer.takeCard(this.deck.deal()); + } + else { + this.dealer.stand = true; + } + }; + BlackJackGame.prototype.nextMove = function (secondTime) { + if (secondTime === true) { + UI.clearScreen(); + this.header(); + this.showCards(false); + UI.display("Invalid input detected"); + UI.display("Would you like to [hit] or [stand]?"); + UI.button.addEventListener("click", this.hitOrStand); + } + else { + UI.display("Would you like to [hit] or [stand]?"); + UI.button.addEventListener("click", this.hitOrStand); + } + }; + BlackJackGame.prototype.hitOrStand = function () { + UI.button.removeEventListener("click", this.hitOrStand); + if (UI.lastInput === 'hit') { + this.currentPlayer.takeCard(this.deck.deal()); + this.evaluateTurn(); + } + else if (UI.lastInput === 'stand') { + this.currentPlayer.stand = true; + this.evaluateTurn(); + } + else { + this.nextMove(true); + } + }; + BlackJackGame.prototype.header = function () { + UI.display("Current Player: " + this.currentPlayer.getProfile().name + "\t|\tCurrent Balance: $" + this.currentPlayer.getProfile().balance + "\t|\t Amount Wagered: $" + this.currentPlayer.escrow.escrowBalance); + UI.display(""); + }; + BlackJackGame.prototype.score = function () { + UI.display("Current Score: " + this.currentPlayer.score); + }; + BlackJackGame.prototype.showCards = function (showHole) { + UI.display("Your Cards"); + var yourCards = this.currentPlayer.hand.cards[0].toString() + ' '; + for (var i = 1; i < this.currentPlayer.hand.cards.length; i++) { + yourCards += "| " + this.currentPlayer.hand.cards[i]; + } + UI.display(yourCards); + this.score(); + UI.display(''); + UI.display("Dealer Cards"); + if (showHole === false) { + var dealerCards = "UNKNOWN "; + for (var i = 1; i < this.dealer.hand.cards.length; i++) { + dealerCards += "| " + this.dealer.hand.cards[i]; + } + UI.display(dealerCards); + } + else if (showHole === true) { + var dealerCards = this.dealer.hand.cards[0].toString() + ' '; + for (var i = 1; i < this.dealer.hand.cards.length; i++) { + dealerCards += "| " + this.dealer.hand.cards[i]; + } + UI.display(dealerCards); + UI.display("Dealer Score: " + this.dealer.score); + } + UI.display(''); + }; + BlackJackGame.prototype.tallyScores = function () { + this.dealer.calculateScore(); + this.currentPlayer.calculateScore(); + }; + BlackJackGame.prototype.naturalCheck = function () { + if (this.currentPlayer.score === 21 && this.dealer.score === 21) { + this.currentPlayer.win(0); + this.endScreen(); + UI.display("Improbably, both you and the Dealer got natural Black Jack"); + UI.display("You break even"); + this.restart(); + return true; + } + else if (this.currentPlayer.score === 21) { + this.currentPlayer.win(1.5); + this.endScreen(); + UI.display("You got a natural Black Jack!"); + UI.display("Your bet pays 3:2!"); + this.restart(); + return true; + } + else if (this.dealer.score === 21) { + this.currentPlayer.lose(); + this.endScreen(); + UI.display("The Dealer got a natural Black Jack"); + UI.display("You lose your bet"); + this.restart(); + return true; + } + else { + return false; + } + }; + BlackJackGame.prototype.restart = function () { + UI.display("Press [submit] to play again"); + this.currentPlayer.stand = false; + this.dealer.stand = false; + this.newDeck(); + UI.button.addEventListener("click", this.run, { once: true }); + }; + BlackJackGame.prototype.newDeck = function () { + if (this.deck.getSize() <= 20) { + this.replaceDeck(); + } + }; + return BlackJackGame; +}(CardGame)); +var Casino = /** @class */ (function () { + function Casino() { + this.profiles = new Array(); + this.chooseGame = this.chooseGame.bind(this); + this.stepTwo = this.stepTwo.bind(this); + this.mainMenu = this.mainMenu.bind(this); + this.register = this.register.bind(this); + this.start = this.start.bind(this); + this.stepOne = this.stepOne.bind(this); + } + Casino.prototype.start = function () { + UI.display("Welcome to Casino Royale With Cheese!"); + UI.display("Let's start by registering your profile"); + UI.display("What is your name?"); + UI.button.addEventListener("click", this.stepOne, { once: true }); + }; + Casino.prototype.stepOne = function () { + this.name = UI.lastInput; + this.stepTwo(); + }; + Casino.prototype.stepTwo = function (errorMessage) { + //UI.button.removeEventListener("click", this.stepOne); + UI.clearScreen(); + UI.display("Nice to meet you " + this.name); + UI.display("How much money would you like to change into chips?"); + UI.display("The minimum desposit is $1000"); + if (typeof errorMessage !== "undefined") + UI.display(errorMessage); + UI.button.addEventListener("click", this.register); + }; + Casino.prototype.register = function () { + UI.button.removeEventListener("click", this.register); + if (parseInt(UI.lastInput) > 1000) { + this.amount = parseInt(UI.lastInput); + this.currentPlayer = new Profile(this.name, this.amount); + this.profiles.push(this.currentPlayer); + this.mainMenu(); + } + else if (parseInt(UI.lastInput) < 1000) { + // UI.button.addEventListener("Click", this.register); + this.stepTwo("You must change at least $1000 into chips to play in our casino"); + } + else { + //UI.button.addEventListener("Click", this.register); + this.stepTwo("You must enter a number for your deposit"); + } + }; + Casino.prototype.mainMenu = function (errorMessage) { + UI.clearScreen(); + this.header(); + UI.display("What game would you like to play?"); + UI.display("[Black Jack]"); + UI.display(''); + if (typeof errorMessage !== "undefined") + UI.display(errorMessage); + UI.button.addEventListener("click", this.chooseGame); + }; + Casino.prototype.header = function () { + UI.display("Current Player: " + this.currentPlayer.name + "\t|\tCurrent Balance: $" + this.currentPlayer.balance); + UI.display(""); + }; + Casino.prototype.chooseGame = function () { + UI.button.removeEventListener("click", this.chooseGame); + if (UI.lastInput === "Black Jack") { + var currentGame = new BlackJackGame(this.currentPlayer); + currentGame.start(); + } + else { + this.mainMenu("I'm sorry. We don't have that game yet."); + } + }; + return Casino; +}()); +var UI = /** @class */ (function () { + function UI() { + UI.button.addEventListener("click", function (e) { UI._lastInput = UI.userInput.value; }); + UI.button.addEventListener("click", function (e) { UI.userInput.value = ''; }); + } + UI.display = function (input) { + this.window.innerText += input + '\n'; + }; + UI.clearScreen = function () { + this.window.innerText = ''; + }; + Object.defineProperty(UI, "Instance", { + get: function () { + return this._instance || (this._instance = new UI()); + }, + enumerable: true, + configurable: true + }); + Object.defineProperty(UI, "lastInput", { + get: function () { + return this._lastInput; + }, + enumerable: true, + configurable: true + }); + UI.userInput = document.getElementById("user_input"); + UI.window = document.getElementById('display'); + UI.button = document.getElementById('submit'); + return UI; +}()); +var UIInstance = UI.Instance; +Startup.main(); diff --git a/js/app.ts b/js/app.ts new file mode 100644 index 00000000..e809e4e3 --- /dev/null +++ b/js/app.ts @@ -0,0 +1,833 @@ +class Startup { + + public static main(): void { + var casino = new Casino(); + casino.start(); + } +} + + +class Profile { + private static _lastId: number = 1; + private _id: number; + private _name: string; + private _balance: number; + + constructor(name: string, balance: number) { + this._id = Profile._lastId; + Profile._lastId++; + this._name = name; + this._balance = balance; + } + + public get id(): number { + return this._id; + } + + public get name(): string { + return this._name; + } + + public get balance(): number { + return this._balance; + } + + public set balance(newBalance: number) { + this._balance = newBalance; + } + + public addToBalance(amount: number): void { + this._balance += amount; + } + +} + +interface PlayerInterface { + + getProfile(): Profile; + getName(): string; + getId(): number; + +} + +abstract class Player implements PlayerInterface { + + private _playerProfile: Profile; + + constructor(playerProfile: Profile) { + this._playerProfile = playerProfile; + } + + public getProfile(): Profile { + return this._playerProfile; + } + + public getName(): string { + return this._playerProfile.name; + } + + public getId(): number { + return this._playerProfile.id; + } + +} + +abstract class CardPlayer extends Player { + + private _hand: Hand; + + constructor(profile: Profile) { + super(profile); + this._hand = new Hand(); + } + + public takeCard(card: Card): void { + this._hand.cards.push(card); + } + + public discardAll(): void { + while (this._hand.cards.length > 0) { + this._hand.cards.pop(); + } + } + + public get hand(): Hand { + return this._hand; + } + +} + +class BlackJackPlayer extends CardPlayer implements Gamble { + + escrow: Escrow; + private _busted: boolean; + private _stand: boolean; + private _score: number; + + constructor(profile: Profile) { + super(profile); + this.escrow = new Escrow(); + } + + bet(amount: number): void { + this.escrow.addToEscrowBalance(amount); + this.getProfile().balance -= amount; + } + win(multiplier: number): void { + let winnings: number = this.escrow.escrowBalance + (this.escrow.escrowBalance * multiplier); + this.getProfile().addToBalance(winnings); + this.escrow.escrowBalance = 0; + } + lose(): void { + this.escrow.escrowBalance = 0; + } + + public get busted(): boolean { + return this.busted; + } + + public set busted(state: boolean) { + this._busted = state; + } + + public get stand(): boolean { + return this._stand; + } + + public set stand(state: boolean) { + this._stand = state; + } + + public get score(): number { + return this._score; + } + + public set score(amount: number) { + this._score = amount; + } + + public isBusted(): boolean { + if (this._score > 21) { + return true; + } + else { + return false; + } + } + + public calculateScore(): void { + let hasAce: boolean = false; + let tempScore: number = 0; + this.hand.cards.forEach(element => { + if (element.rank === Rank.TWO) tempScore += 2; + else if (element.rank === Rank.THREE) tempScore += 3; + else if (element.rank === Rank.FOUR) tempScore += 4; + else if (element.rank === Rank.FIVE) tempScore += 5; + else if (element.rank === Rank.SIX) tempScore += 6; + else if (element.rank === Rank.SEVEN) tempScore += 7; + else if (element.rank === Rank.EIGHT) tempScore += 8; + else if (element.rank === Rank.NINE) tempScore += 9; + else if (element.rank === Rank.TEN) tempScore += 10; + else if (element.rank === Rank.JACK) tempScore += 10; + else if (element.rank === Rank.QUEEN) tempScore += 10; + else if (element.rank === Rank.KING) tempScore += 10; + else if (element.rank === Rank.ACE) { + tempScore += 11; + hasAce = true; + } + }); + if (tempScore > 21 && hasAce) { + tempScore = 0; + this.hand.cards.forEach(element => { + if (element.rank === Rank.TWO) tempScore += 2; + else if (element.rank === Rank.THREE) tempScore += 3; + else if (element.rank === Rank.FOUR) tempScore += 4; + else if (element.rank === Rank.FIVE) tempScore += 5; + else if (element.rank === Rank.SIX) tempScore += 6; + else if (element.rank === Rank.SEVEN) tempScore += 7; + else if (element.rank === Rank.EIGHT) tempScore += 8; + else if (element.rank === Rank.NINE) tempScore += 9; + else if (element.rank === Rank.TEN) tempScore += 10; + else if (element.rank === Rank.JACK) tempScore += 10; + else if (element.rank === Rank.QUEEN) tempScore += 10; + else if (element.rank === Rank.KING) tempScore += 10; + else if (element.rank === Rank.ACE) { + tempScore += 1; + } + }); + } + this._score = tempScore; + } + +} + +class Escrow { + + private _escrowBalance: number; + + constructor() { + this._escrowBalance = 0; + } + + public get escrowBalance(): number { + return this._escrowBalance; + } + + public set escrowBalance(amount: number) { + this._escrowBalance = amount; + } + + public addToEscrowBalance(amount: number) { + this._escrowBalance; + amount; + this.escrowBalance = this.escrowBalance + amount; + } + + + +} + +enum Suit { + HEARTS, + CLUBS, + DIAMONDS, + SPADES + +} + +enum Rank { + TWO, + THREE, + FOUR, + FIVE, + SIX, + SEVEN, + EIGHT, + NINE, + TEN, + JACK, + QUEEN, + KING, + ACE +} + +class Card { + + private _suit: Suit; + private _rank: Rank; + + constructor(rank: Rank, suit: Suit) { + this._suit = suit; + this._rank = rank; + } + + public get suit(): Suit { + return this._suit; + } + + public get rank(): Rank { + return this._rank; + } + + public toString(): string { + if (this._suit === Suit.CLUBS) { + return Rank[this._rank] + ' \u{2663}'; + } + else if (this._suit === Suit.DIAMONDS) { + return Rank[this._rank] + ' \u{2666}'; + } + else if (this._suit === Suit.SPADES) { + return Rank[this._rank] + ' \u{2660}'; + } + else if (this._suit === Suit.HEARTS) { + return Rank[this._rank] + ' \u{2665}'; + } + else { + throw new Error("Something has gone horribly wrong"); + } + + } + + +} + +class Deck { + + private _cards: Card[]; + + constructor() { + this._cards = new Array(); + this.populate(); + } + + public deal(): Card { + return this._cards.pop(); + } + + public shuffle(): void { + this._cards.sort(function (a, b) { return 0.5 - Math.random() }); + } + + private populate(): void { + for (let suit = Suit.HEARTS; suit <= Suit.SPADES; suit++) { + for (let rank = Rank.TWO; rank <= Rank.ACE; rank++) { + this._cards.push(new Card(rank, suit)) + } + } + } + + public getSize():number{ + return this._cards.length; + } + +} + +class Hand { + private _cards: Card[]; + + constructor() { + this._cards = new Array(); + } + + public get cards(): Card[] { + return this._cards; + } + +} + +interface GameInterface { + + getPlayers(): PlayerInterface[]; + getPlayer(playerId: number): PlayerInterface; + addPlayer(player: PlayerInterface): void; + removePlayer(player: PlayerInterface): void; + contains(player: PlayerInterface): boolean; + +} + +interface GameEngineInterface { + + run(): void; + evaluateTurn(player: PlayerInterface): void; + +} + +abstract class GameEngine implements GameEngineInterface, PlayerInterface>{ + + + abstract run(): void; + abstract evaluateTurn(): void; + + + +} + +interface Gamble { + + escrow: Escrow; + + bet(amount: number): void; + win(multiplier: number): void; + lose(): void; + +} + + +abstract class CardGame extends GameEngine implements GameInterface { + + private _players: CardPlayer[]; + private _deck: Deck; + + constructor() { + super(); + this._players = new Array(); + this._deck = new Deck(); + this._deck.shuffle(); + } + + + public get deck(): Deck { + return this._deck; + } + + public replaceDeck(){ + this._deck = new Deck(); + this._deck.shuffle(); + } + + + getPlayers(): CardPlayer[] { + return this._players; + + } + + getPlayer(playerId: number): CardPlayer { + this._players.forEach(element => { + if (element.getId() === playerId) { + return element; + } + }); + throw new Error("Player not found"); + } + + addPlayer(player: CardPlayer): void { + this._players.push(player); + } + + removePlayer(player: CardPlayer): void { + this._players.splice(this._players.indexOf(player), 1); + } + + contains(player: CardPlayer): boolean { + this._players.forEach(element => { + if (element === player) { + return true; + } + }); + return false; + } +} + +class BlackJackGame extends CardGame { + + currentPlayer: BlackJackPlayer; + dealer: BlackJackPlayer; + + constructor(playerProfile: Profile) { + super(); + this.dealer = new BlackJackPlayer(new Profile('Dealer', 0)); + this.currentPlayer = new BlackJackPlayer(playerProfile); + this.addPlayer(this.dealer); + this.addPlayer(this.currentPlayer); + this.startRound = this.startRound.bind(this); + this.placeBet = this.placeBet.bind(this); + this.run = this.run.bind(this); + this.initialDeal = this.initialDeal.bind(this); + this.restart = this.restart.bind(this); + this.naturalCheck = this.naturalCheck.bind(this); + this.nextMove = this.nextMove.bind(this); + this.hitOrStand = this.hitOrStand.bind(this); + } + + start():void{ + UI.clearScreen(); + this.header(); + UI.display("Welcome to Black Jack"); + UI.display("Press [submit] to begin"); + UI.button.addEventListener("click", this.run, { once: true }); + } + + run(): void { + this.startRound(); + } + + evaluateTurn(): void { + UI.clearScreen(); + this.tallyScores(); + this.dealerTurn(); + this.tallyScores(); + this.header(); + this.showCards(false); + if (!this.isWinner()) { + this.nextMove(false); + } + if (this.currentPlayer.stand) { + this.evaluateTurn(); + } + + } + + private isWinner(): boolean { + if (this.currentPlayer.isBusted() && this.dealer.isBusted()) { + this.currentPlayer.win(0); + this.endScreen(); + UI.display("You and the Dealer are both Bust"); + UI.display("You break even"); + this.restart(); + return true; + } + else if (this.currentPlayer.isBusted()) { + this.currentPlayer.lose(); + this.endScreen(); + UI.display("You went Bust"); + UI.display("You lose your bet"); + this.restart(); + return true; + } + else if (this.dealer.isBusted()) { + this.currentPlayer.win(1); + this.endScreen(); + UI.display("The Dealer went Bust!"); + UI.display("Your bet pays even money!"); + this.restart(); + return true; + } + else if (this.currentPlayer.stand && this.dealer.stand) { + if (this.currentPlayer.score === this.dealer.score) { + this.currentPlayer.win(0); + this.endScreen(); + UI.display("The Dealer has the same score as you. You push"); + UI.display("You break even"); + this.restart(); + return true; + } + else if (this.currentPlayer.score > this.dealer.score) { + this.currentPlayer.win(1); + this.endScreen(); + UI.display("You have a higher score. You win!"); + UI.display("Yor bet pays even money!"); + this.restart(); + return true; + } + else if (this.currentPlayer.score < this.dealer.score) { + this.currentPlayer.lose(); + this.endScreen(); + UI.display("The Dealer has a higher score. You lose"); + UI.display("You lose your bet"); + this.restart(); + return true; + } + } + else { + return false; + } + } + + private endScreen(): void { + UI.clearScreen(); + this.header(); + this.showCards(true); + } + + private startRound(errorMessage?: string): void { + this.currentPlayer.discardAll(); + this.dealer.discardAll(); + UI.clearScreen(); + this.header(); + UI.display("How much would you like to bet?"); + UI.display("The minimum bet is $10"); + if (typeof errorMessage !== "undefined") UI.display(errorMessage); + UI.button.addEventListener("click", this.placeBet); + } + + private placeBet(): void { + UI.button.removeEventListener("click", this.placeBet); + UI.clearScreen(); + if (UI.lastInput <= this.currentPlayer.getProfile().balance && UI.lastInput > 10) { + this.currentPlayer.bet(parseInt(UI.lastInput)); + this.initialDeal(); + } + else if (UI.lastInput < 10) { + this.startRound("That amount is below the minimum bet"); + } + else if (UI.lastInput > this.currentPlayer.getProfile().balance) { + this.startRound("You cannot bet more money than you have"); + } + else { + this.startRound("You must input a number to place a bet"); + } + } + + private initialDeal(): void { + UI.clearScreen(); + this.currentPlayer.takeCard(this.deck.deal()); + this.dealer.takeCard(this.deck.deal()); + this.currentPlayer.takeCard(this.deck.deal()); + this.dealer.takeCard(this.deck.deal()); + this.tallyScores(); + this.header(); + this.showCards(false); + let natural: boolean = this.naturalCheck(); + if (!natural) { + this.nextMove(false); + } + + + + } + + private dealerTurn(): void { + if (this.dealer.score < 17) { + this.dealer.takeCard(this.deck.deal()); + } + else { + this.dealer.stand = true; + } + } + + private nextMove(secondTime: boolean) { + if (secondTime === true) { + UI.clearScreen(); + this.header(); + this.showCards(false); + UI.display("Invalid input detected"); + UI.display("Would you like to [hit] or [stand]?"); + UI.button.addEventListener("click", this.hitOrStand); + } + else { + UI.display("Would you like to [hit] or [stand]?"); + UI.button.addEventListener("click", this.hitOrStand); + } + + } + + private hitOrStand(): void { + UI.button.removeEventListener("click", this.hitOrStand); + if (UI.lastInput === 'hit') { + this.currentPlayer.takeCard(this.deck.deal()); + this.evaluateTurn(); + } + else if (UI.lastInput === 'stand') { + this.currentPlayer.stand = true; + this.evaluateTurn(); + } + else { this.nextMove(true) } + + } + + private header(): void { + UI.display("Current Player: " + this.currentPlayer.getProfile().name + "\t|\tCurrent Balance: $" + this.currentPlayer.getProfile().balance + "\t|\t Amount Wagered: $" + this.currentPlayer.escrow.escrowBalance); + UI.display(""); + } + + private score(): void { + UI.display("Current Score: " + this.currentPlayer.score) + } + + private showCards(showHole: boolean): void { + UI.display("Your Cards"); + let yourCards: string = this.currentPlayer.hand.cards[0].toString() + ' '; + for (let i = 1; i < this.currentPlayer.hand.cards.length; i++) { + yourCards += "| " + this.currentPlayer.hand.cards[i]; + } + UI.display(yourCards); + this.score(); + UI.display(''); + UI.display("Dealer Cards"); + if (showHole === false) { + let dealerCards: string = "UNKNOWN "; + for (let i = 1; i < this.dealer.hand.cards.length; i++) { + dealerCards += "| " + this.dealer.hand.cards[i]; + } + UI.display(dealerCards); + } + else if (showHole === true) { + let dealerCards: string = this.dealer.hand.cards[0].toString() + ' '; + for (let i = 1; i < this.dealer.hand.cards.length; i++) { + dealerCards += "| " + this.dealer.hand.cards[i]; + } + UI.display(dealerCards); + UI.display("Dealer Score: " + this.dealer.score); + } + UI.display(''); + } + + private tallyScores() { + this.dealer.calculateScore(); + this.currentPlayer.calculateScore(); + } + + private naturalCheck(): boolean { + if (this.currentPlayer.score === 21 && this.dealer.score === 21) { + this.currentPlayer.win(0); + this.endScreen(); + UI.display("Improbably, both you and the Dealer got natural Black Jack"); + UI.display("You break even"); + this.restart(); + return true; + } + else if (this.currentPlayer.score === 21) { + this.currentPlayer.win(1.5); + this.endScreen(); + UI.display("You got a natural Black Jack!"); + UI.display("Your bet pays 3:2!"); + this.restart(); + return true; + } + else if (this.dealer.score === 21) { + this.currentPlayer.lose(); + this.endScreen(); + UI.display("The Dealer got a natural Black Jack"); + UI.display("You lose your bet"); + this.restart(); + return true; + } + else { return false; } + } + + private restart(): void { + UI.display("Press [submit] to play again"); + this.currentPlayer.stand = false; + this.dealer.stand = false; + this.newDeck(); + UI.button.addEventListener("click", this.run, { once: true }) + } + + private newDeck(){ + if(this.deck.getSize()<=20){ + this.replaceDeck(); + } + } + + +} + +class Casino { + + private name: string; + private amount: number; + private profiles: Profile[]; + private currentPlayer: Profile; + constructor() { + this.profiles = new Array(); + this.chooseGame = this.chooseGame.bind(this); + this.stepTwo = this.stepTwo.bind(this); + this.mainMenu = this.mainMenu.bind(this); + this.register = this.register.bind(this); + this.start = this.start.bind(this); + this.stepOne = this.stepOne.bind(this); + } + + start() { + UI.display("Welcome to Casino Royale With Cheese!"); + UI.display("Let's start by registering your profile"); + UI.display("What is your name?") + UI.button.addEventListener("click", this.stepOne,{once:true}); + } + + stepOne(): void { + this.name = UI.lastInput; + this.stepTwo(); + } + + stepTwo(errorMessage?: string): void { + //UI.button.removeEventListener("click", this.stepOne); + UI.clearScreen(); + UI.display("Nice to meet you " + this.name); + UI.display("How much money would you like to change into chips?") + UI.display("The minimum desposit is $1000"); + if (typeof errorMessage !== "undefined") UI.display(errorMessage); + UI.button.addEventListener("click", this.register); + } + + register(): void { + UI.button.removeEventListener("click", this.register); + if (parseInt(UI.lastInput) > 1000) { + this.amount = parseInt(UI.lastInput); + this.currentPlayer = new Profile(this.name, this.amount); + this.profiles.push(this.currentPlayer); + this.mainMenu(); + } + else if (parseInt(UI.lastInput) < 1000) { + // UI.button.addEventListener("Click", this.register); + this.stepTwo("You must change at least $1000 into chips to play in our casino"); + } + else { + //UI.button.addEventListener("Click", this.register); + this.stepTwo("You must enter a number for your deposit"); + } + + } + + mainMenu(errorMessage?: string): void { + UI.clearScreen(); + this.header(); + UI.display("What game would you like to play?") + UI.display("[Black Jack]"); + UI.display(''); + if (typeof errorMessage !== "undefined") UI.display(errorMessage); + UI.button.addEventListener("click", this.chooseGame); + + } + + private header(): void { + UI.display("Current Player: " + this.currentPlayer.name + "\t|\tCurrent Balance: $" + this.currentPlayer.balance); + UI.display(""); + } + + + chooseGame(): void { + UI.button.removeEventListener("click", this.chooseGame); + if (UI.lastInput === "Black Jack") { + var currentGame = new BlackJackGame(this.currentPlayer); + currentGame.start(); + } + + else { + this.mainMenu("I'm sorry. We don't have that game yet."); + } + } +} + +class UI { + static userInput = document.getElementById("user_input"); + static window = document.getElementById('display'); + static button = document.getElementById('submit'); + static _lastInput: any; + private static _instance: UI; + + private constructor() { + UI.button.addEventListener("click", (e: Event) => { UI._lastInput = UI.userInput.value }); + UI.button.addEventListener("click", (e: Event) => { UI.userInput.value = '' }); + } + + static display(input: any): void { + this.window.innerText += input + '\n'; + } + + static clearScreen(): void { + this.window.innerText = ''; + } + + public static get Instance(): UI { + return this._instance || (this._instance = new UI()); + } + + public static get lastInput(): any { + return this._lastInput; + } + +} + +const UIInstance = UI.Instance; +Startup.main(); \ No newline at end of file diff --git a/tsconfig.json b/tsconfig.json new file mode 100644 index 00000000..5617cd44 --- /dev/null +++ b/tsconfig.json @@ -0,0 +1,57 @@ +{ + "compilerOptions": { + /* Basic Options */ + "target": "es5", /* Specify ECMAScript target version: 'ES3' (default), 'ES5', 'ES2015', 'ES2016', 'ES2017','ES2018' or 'ESNEXT'. */ + "module": "commonjs", /* Specify module code generation: 'none', 'commonjs', 'amd', 'system', 'umd', 'es2015', or 'ESNext'. */ + // "lib": [], /* Specify library files to be included in the compilation. */ + // "allowJs": true, /* Allow javascript files to be compiled. */ + // "checkJs": true, /* Report errors in .js files. */ + // "jsx": "preserve", /* Specify JSX code generation: 'preserve', 'react-native', or 'react'. */ + // "declaration": true, /* Generates corresponding '.d.ts' file. */ + // "sourceMap": true, /* Generates corresponding '.map' file. */ + // "outFile": "./", /* Concatenate and emit output to single file. */ + // "outDir": "./", /* Redirect output structure to the directory. */ + // "rootDir": "./", /* Specify the root directory of input files. Use to control the output directory structure with --outDir. */ + // "removeComments": true, /* Do not emit comments to output. */ + // "noEmit": true, /* Do not emit outputs. */ + // "importHelpers": true, /* Import emit helpers from 'tslib'. */ + // "downlevelIteration": true, /* Provide full support for iterables in 'for-of', spread, and destructuring when targeting 'ES5' or 'ES3'. */ + // "isolatedModules": true, /* Transpile each file as a separate module (similar to 'ts.transpileModule'). */ + + /* Strict Type-Checking Options */ + "strict": true, /* Enable all strict type-checking options. */ + // "noImplicitAny": true, /* Raise error on expressions and declarations with an implied 'any' type. */ + "strictNullChecks": false, /* Enable strict null checks. */ + // "strictFunctionTypes": true, /* Enable strict checking of function types. */ + // "strictPropertyInitialization": true, /* Enable strict checking of property initialization in classes. */ + // "noImplicitThis": true, /* Raise error on 'this' expressions with an implied 'any' type. */ + // "alwaysStrict": true, /* Parse in strict mode and emit "use strict" for each source file. */ + + /* Additional Checks */ + // "noUnusedLocals": true, /* Report errors on unused locals. */ + // "noUnusedParameters": true, /* Report errors on unused parameters. */ + // "noImplicitReturns": true, /* Report error when not all code paths in function return a value. */ + // "noFallthroughCasesInSwitch": true, /* Report errors for fallthrough cases in switch statement. */ + + /* Module Resolution Options */ + // "moduleResolution": "node", /* Specify module resolution strategy: 'node' (Node.js) or 'classic' (TypeScript pre-1.6). */ + // "baseUrl": "./", /* Base directory to resolve non-absolute module names. */ + // "paths": {}, /* A series of entries which re-map imports to lookup locations relative to the 'baseUrl'. */ + // "rootDirs": [], /* List of root folders whose combined content represents the structure of the project at runtime. */ + // "typeRoots": [], /* List of folders to include type definitions from. */ + // "types": [], /* Type declaration files to be included in compilation. */ + // "allowSyntheticDefaultImports": true, /* Allow default imports from modules with no default export. This does not affect code emit, just typechecking. */ + "esModuleInterop": true /* Enables emit interoperability between CommonJS and ES Modules via creation of namespace objects for all imports. Implies 'allowSyntheticDefaultImports'. */ + // "preserveSymlinks": true, /* Do not resolve the real path of symlinks. */ + + /* Source Map Options */ + // "sourceRoot": "./", /* Specify the location where debugger should locate TypeScript files instead of source locations. */ + // "mapRoot": "./", /* Specify the location where debugger should locate map files instead of generated locations. */ + // "inlineSourceMap": true, /* Emit a single file with source maps instead of having a separate file. */ + // "inlineSources": true, /* Emit the source alongside the sourcemaps within a single file; requires '--inlineSourceMap' or '--sourceMap' to be set. */ + + /* Experimental Options */ + // "experimentalDecorators": true, /* Enables experimental support for ES7 decorators. */ + // "emitDecoratorMetadata": true, /* Enables experimental support for emitting type metadata for decorators. */ + } +} \ No newline at end of file