Игра красное-черное на JQuiery.

Игра красное-черное на JQuiery.

Цель занятия.

Создать браузерную игру, в которой пользователь должен угадать случайный цвет (красный или черный) и выиграть максимум кредитов.

В начале игры у пользователя спрашивается его имя, и после ввода выводится приветствие.

Затем пользователь добавляет на свой счет 100 кредитов и начинает игру.

Игра начинается с установления ставки 1, 2, 5 или 10 кредитов.

Затем при нажатии на кнопку красное или черное программа случайно выбрасывает и отображает цвет.

Если цвет угадан, то выиграш удваевается и пользователю предлагается угадать снова и удвоить выиграш либо забрать кредиты и положить на счет.

Если цвет не угадан, то ставка обнуляется.

Пользователь может удваивать выиграш не более 6 раз.

Количество угадываний отображается в виде пирамиды с постепенно закрашиваемыми слоями.

Технологии.

В программе использовать HTML, CSS, Bootstrap, JQuery.

Получаемые навыки.

  • HTML верстка;

  • работа со случайными числами;

  • получение и работа с элементами DOM на странице;

  • работа с событиями и функциями обратного вызова;

  • работа с циклами и условиями.

Демонстрация приложения

Разработка.

Создаем репозиторий.

npm init

Устанавливаем bootstrap, jquery popper.js .

npm install bootstrap jquery popper.js --save

Установка gulp browser-sync

npm install gulp browser-sync

Глобально

npm install --global gulp-cli
npm link gulp --no-bin-links

Gulp позволяет создавать задачи (какие то долгоиграющие процессы).

Создаем скрипт сервера server.js.

var gulp = require('gulp');
var browserSync = require('browser-sync').create();
var reload = browserSync.reload;

gulp.task('serve', function() {
  browserSync.init({
    server: {
      baseDir: "./"
    }
  });

  gulp.watch(["*.html","*.css", "*.js"]).on("change", reload);
});

В данном случае мы создаем задачу gulp.task(‘serve’…)

В которой запускаем browserSync который синхронизирует браузер, перезапуская его при изменениях скриптов.

ссылка на документацию

Создаем индексный файл index.html.

<!doctype html>
<html lang="en">
  <head>
    <!-- Required meta tags -->
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">

    <!-- Bootstrap CSS -->
    <link rel="stylesheet" href="node_modules/bootstrap/dist/css/bootstrap.min.css">

    <title>Hello, world!</title>
  </head>
  <body>
    <h1>Hello, world!</h1>

    <!-- Optional JavaScript -->
    <!-- jQuery first, then Popper.js, then Bootstrap JS -->
    <script src="node_modules/jquery/dist/jquery.min.js" ></script>
    <script src="node_modules/popper.js/dist/popper.min.js" ></script>
    <script src="node_modules/bootstrap/dist/js/bootstrap.min.js" ></script>
  </body>
</html>

Создаем скрипт приложения app.js.

alert('Start');

Подключаем.

<script src="static/app.js" ></script>

Создаем функцию создания колоды карт.

var faces = ['hearts', 'diams', 'clubs', 'spades'];
var faces_numbers = [0, 1, 2, 3];
var ranks = [1,2,3,4,5,6,7,8,9,10,'J','Q','K','A'];
var deck = [];

function createDeck(){
    for (let i of faces_numbers) {
        for (let j of rancks) {
            let cardname = `${i}_${j}.svg`;
            let card = {"svg": cardname};
            deck.push(card);
            console.dir(deck);
        }

    }
}

createDeck();

Перемешиваем колоду.

Получение случайного элемента из массива.

var item = items[Math.floor(Math.random() * items.length)];

Math.floor() - округляет до целого в меньшую сторону.

Функция перемешивания.

function shuffle(){
    var copy = [], currentIndex = deck.length, randomIndex, tmpValue;
    while (0 !== currentIndex) {

        // Подбираем случайную карту (индекс) из общего кол-ва
        randomIndex = Math.floor(Math.random() * currentIndex);
        currentIndex -= 1;
        // Меняем местами текущий и случайнвый элемент
        tmpValue = deck[currentIndex];
        deck[currentIndex] = deck[randomIndex];
        deck[randomIndex] = tmpValue;
    }
}

Отображение карты.

function showCard(card){
    let card_div = document.createElement('img');
    card_div.src = `static/cards/${card.svg}`;
    document.getElementById('cards').appendChild(card_div);
}

Карты на css.

Разметка карты.

*
{{ card.name }} {{ faceCSS }}

{{ card.name }} - 2-10 | J | Q | K | A

{{ card.faceName }} - hearts| diams | clubs | spades

{{ faceCSS }} - ♥ | ♦ | ♣ | ♠

Карты на спрайте.

<div style="width: 69px; height: 94px; background-image: url(static/cards.png);"></div>

Изменяем логику генерации колоды.

app = {...
        ranks:['A',2,3,4,5,6,7,8,9,10,'J','Q','K'],
        ...
}
app.createDeck = function(){
    for (let face in this.faces) {
        for (let rank in this.ranks) {
            let card = {face: this.faces[face], 
                rank: this.ranks[rank], 
                shift_rank: parseInt(rank)+1,
                shift_face: face
            };
            this.deck.push(card);
        }
    }        
}

Отображение карты.

    card_html = `
    <div style="width: 69px; height: 94px; background-image: url(static/cards.png);
    background-position: -${card.shift_rank*69}px -${card.shift_face*94}px;">
    </div>`

Изменяем формирование колоды.

function createDeck(){
    for (let face of faces) {
        for (let rank of ranks) {
            let card = {face: face, rank: rank};
            deck.push(card);
        }

    }
}

И отображение карты.

function showCard(card){
    card_html = `
    <div class="card_cell playingCards">
        <div class="card-container fade-long-anim" >
            <div class="card-flipper">
                <div class="card back">*</div>
                <div class="card front card rank-${card.rank} ${card.face}">
                <span class="rank">${card.rank}</span>
                <span class="suit">&${card.face};</span>
            </div>
        </div>
    </div>`;
    document.getElementById('cards').innerHTML = document.getElementById('cards').innerHTML + card_html;
}

Кнопка сдачи карты.

Шаблон.

<button id="take-button">Take one</button>

Код.

var button = document.getElementById('take-button');
button.addEventListener('click', function(el){
    showCard(deck.pop());
})

Создаем пространство имен.

$( document ).ready(function() {
    console.log( "document ready!" );
    app = {
            faces:['hearts', 'diams', 'clubs', 'spades'],
            ranks:[1,2,3,4,5,6,7,8,9,10,'J','Q','K','A'],
            deck: []
    }
    app.createDeck = function(){
        for (let face of this.faces) {
            for (let rank of this.ranks) {
                let card = {face: face, rank: rank};
                this.deck.push(card);
            }
        }        
    }

    app.createDeck();
    console.log(app.deck);
});

Работаем в функции обратного вызова, подвязанной к событию завершения загрузки документа.

Внутри ф-ции все приложение заворачиваем в объект app.

К внутренним свойствам объекта получаем доступ при помощи ключевого слова this.

Сделаем функцию init.

app.init = function() {
    self = this;
    this.createDeck();
    this.shuffle();
    $('#take-button').on('click', function(){
        self.showCard(self.deck.pop());
    });
}

Так как при клике в колбеке мы теряем контекст this, мы можем сохранить ее в замыкании функции init при помощи хака self = this.

Либо применить стрелочную функцию, которая возмет контекст из функции выше (init в нашем случае) и так как эта функция находится внутри объекта, он и пойдет в контекст this.

app.init = function() {
    this.createDeck();
    this.shuffle();
    $('#take-button').on('click', () => {
        this.showCard(this.deck.pop());
    });
}

Выдаем количество набранных очков карты.

app.getScore = function(card){
    if (card.rank == 'A') return 11;
    if (card.rank == 'Q' || card.rank == 'J' || card.rank == 'K') return 2;
    if (typeof card.rank === 'number') return card.rank;
}

Добавляем переменную набранных очков и выводим на экран.

Шаблон.

<button id="take-button">Take one</button>
<div id="score"></div>

<div id="cards"></div>

Скрипт.

app = {
        ...
        score: 0
}


app.showScore = function(){
    $('#score').html(this.score);
}

app.init = function() {
    ...
    this.showScore();
    $('#take-button').on('click', () => {
        let card = this.deck.pop();
        this.showCard(card);
        this.score = this.score + this.getScore(card);
        this.showScore();
    });
}

Проверяем на перебор.

app.checkScore = function() {
    if(this.score>21){
        this.score = 0;
        $('#cards').html('');
    }
}

app.init = function() {
    ...
    $('#take-button').on('click', () => {
        ...
        this.checkScore();
    });
}

Делаем кнопку Stop.

Функция набора карт диллером.

app = {
        ...
        stop_game: false
}


app.dillerTaking = function(){
    while(!this.stop_game){
        let card = this.deck.pop();
        this.showCard(card);
        this.diller_score = this.diller_score + this.getScore(card);
        this.showScore();
        if(this.diller_score>17 && this.diller_score<=21){
            if(this.score > this.diller_score){
                alert('You win');
                this.stop_game = true;
            } else {
                alert('You lost');
                this.stop_game = true;
            }
        }
        if(this.diller_score>21){
            alert('You win');
            this.stop_game = true;
        }
        this.dillerTaking();
    }
}


app.init = function() {
    ....

    $('#stop-button').on('click', () => {
        this.dillerTaking();
    });

}