├── .gitignore
├── src
├── img
│ └── battlefield-js.jpg
├── js
│ ├── metrika.js
│ ├── battlefield.options.js
│ ├── battlefield.class-field.js
│ ├── battlefield.helper.js
│ ├── battlefield.class-battlefield.js
│ ├── battlefield.class-battle.js
│ └── battlefield.class-gameui.js
└── css
│ ├── battlefield.modal-window.css
│ ├── battlefield.player-name.css
│ ├── battlefield.logger.css
│ ├── battlefield.global.css
│ ├── battlefield.fields.css
│ └── battlefield.helper.css
├── bower.json
├── test
├── index.html
└── spec
│ └── class.battlefield.js
├── package.json
├── README.md
├── examples
├── index.html
└── development.html
├── gulpfile.js
└── dist
├── battlefield.min.js
└── battlefield.min.css
/.gitignore:
--------------------------------------------------------------------------------
1 | .idea
2 | bower_components
3 | node_modules
4 | npm-debug.log
--------------------------------------------------------------------------------
/src/img/battlefield-js.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/alx2das/battlefield-js/HEAD/src/img/battlefield-js.jpg
--------------------------------------------------------------------------------
/bower.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "battlefield-js",
3 | "description": "This is classic game Battlefield for browsers, implemented on language JavaScript.",
4 | "main": "examples/index.html",
5 | "authors": [
6 | "Alexandr Builov"
7 | ],
8 | "license": "ISC",
9 | "keywords": [
10 | "battlefield",
11 | "javascript",
12 | "gulp",
13 | "jasmine"
14 | ],
15 | "homepage": "https://github.com/alx2das/battlefield-js",
16 | "ignore": [
17 | "**/.*",
18 | "node_modules",
19 | "bower_components",
20 | "test",
21 | "tests"
22 | ],
23 | "dependencies": {
24 | "jasmine-core": "jasmine#^2.5.2"
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/src/js/metrika.js:
--------------------------------------------------------------------------------
1 | (function (d, w, c) {
2 | (w[c] = w[c] || []).push(function () {
3 | try {
4 | w.yaCounter42568409 = new Ya.Metrika({
5 | id: 42568409,
6 | clickmap: true,
7 | trackLinks: true,
8 | accurateTrackBounce: true
9 | });
10 | } catch (e) {
11 | }
12 | });
13 |
14 | var n = d.getElementsByTagName("script")[0],
15 | s = d.createElement("script"),
16 | f = function () {
17 | n.parentNode.insertBefore(s, n);
18 | };
19 | s.type = "text/javascript";
20 | s.async = true;
21 | s.src = "https://mc.yandex.ru/metrika/watch.js";
22 |
23 | if (w.opera == "[object Opera]") {
24 | d.addEventListener("DOMContentLoaded", f, false);
25 | } else {
26 | f();
27 | }
28 | })(document, window, "yandex_metrika_callbacks");
--------------------------------------------------------------------------------
/test/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Battlefield JS
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "battlefield-js",
3 | "version": "1.0.1",
4 | "description": "This is classic game Battlefield for browsers, implemented on language JavaScript.",
5 | "main": "examples/index.html",
6 | "directories": {
7 | "example": "examples",
8 | "test": "test"
9 | },
10 | "dependencies": {},
11 | "devDependencies": {
12 | "autoprefixer": "^6.7.2",
13 | "bower": "^1.8.0",
14 | "del": "^2.2.2",
15 | "gulp": "^3.9.1",
16 | "gulp-concat": "^2.6.1",
17 | "gulp-minify-css": "^1.2.4",
18 | "gulp-postcss": "^6.3.0",
19 | "gulp-rename": "^1.2.2",
20 | "gulp-uglify": "^2.0.0",
21 | "run-sequence": "^1.2.2"
22 | },
23 | "scripts": {
24 | "test": "test/index.html"
25 | },
26 | "repository": {
27 | "type": "git",
28 | "url": "git+https://github.com/alx2das/battlefield-js.git"
29 | },
30 | "keywords": [
31 | "battlefield",
32 | "javascript",
33 | "gulp",
34 | "jasmine"
35 | ],
36 | "author": "Alexandr Builov",
37 | "license": "ISC",
38 | "bugs": {
39 | "url": "https://github.com/alx2das/battlefield-js/issues"
40 | },
41 | "homepage": "https://alx2das.github.io/battlefield-js/examples/"
42 | }
43 |
--------------------------------------------------------------------------------
/src/css/battlefield.modal-window.css:
--------------------------------------------------------------------------------
1 | .bf-modal-font {
2 | position: fixed;
3 | z-index: 9;
4 | top: 0;
5 | left: 0;
6 | width: 100%;
7 | height: 100%;
8 | background: rgba(122, 139, 159, 0.8);
9 | }
10 |
11 | .bf-modal-window {
12 | position: fixed;
13 | z-index: 19;
14 | top: 50%;
15 | left: 50%;
16 | width: 600px;
17 | background: #fff;
18 | border-radius: 4px;
19 | }
20 |
21 | .bf-modal-window .content {
22 | padding: 25px 15px 15px 15px;
23 | }
24 |
25 | .bf-modal-window .content span {
26 | float: right;
27 | font-size: 12px;
28 | font-weight: 400;
29 | padding: 2px 0;
30 | color: #7A8BB4;
31 | font-style: italic;
32 | }
33 |
34 | .bf-modal-window .header, .bf-modal-window .cont, .bf-modal-window .footer {
35 | }
36 |
37 | .bf-modal-window .header {
38 | font-weight: 700;
39 | font-size: 16px;
40 | padding-bottom: 16px;
41 | border-bottom: 2px solid rgba(122, 139, 159, .3);
42 | }
43 |
44 | .bf-modal-window .cont {
45 | padding: 30px 0;
46 | }
47 |
48 | .bf-modal-window .footer {
49 | padding-top: 15px;
50 | border-top: 2px solid rgba(122, 139, 159, .3);
51 | }
52 |
53 | .bf-modal-window .header:after, .bf-modal-window .cont:after, .bf-modal-window .footer:after {
54 | content: " ";
55 | clear: both;
56 | display: block;
57 | }
--------------------------------------------------------------------------------
/src/css/battlefield.player-name.css:
--------------------------------------------------------------------------------
1 | .bf-player-name {
2 | text-align: center;
3 | width: 950px;
4 | margin: 0 auto
5 | }
6 |
7 | .bf-player-name span {
8 | display: inline-block;
9 | padding: 0 10px;
10 | font-size: 15px;
11 | height: 24px;
12 | line-height: 24px;
13 | }
14 |
15 | .bf-player-name .name {
16 | width: 120px;
17 | background: #7a8b9f;
18 | color: #fff;
19 | margin: 0 10px 0 6px;
20 | padding: 4px 10px;
21 | border-radius: 3px;
22 | height: auto;
23 | line-height: 1.1;
24 | }
25 |
26 | .bf-player-name .name.act {
27 | background: #f0ad4e;
28 | }
29 |
30 | .bf-player-name .total {
31 | min-width: 30px;
32 | text-align: center;
33 | color: #7a8b9f;
34 | font-weight: 700;
35 | }
36 |
37 | .bf-player-name .opt {
38 | float: left
39 | }
40 |
41 | .bf-player-name .left {
42 | float: left;
43 | margin-top: -5px
44 | }
45 |
46 | .bf-player-name .center {
47 | width: 460px;
48 | margin: 0 auto
49 | }
50 |
51 | .bf-player-name .center:after {
52 | content: " ";
53 | clear: both;
54 | display: block;
55 | }
56 |
57 | .bf-player-name .right {
58 | float: right
59 | }
60 |
61 | .bf-player-name .left a {
62 | color: #7a8b9f;
63 | font-weight: 700;
64 | font-size: 26px;
65 | text-decoration: none;
66 | }
67 |
68 | .bf-player-name .right span {
69 | padding: 0
70 | }
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Battlefield 1.0.1
2 | Игра была разработанна шутки ради, практики для, в свободное от основной работы время и помере желания выседания перед компьютером. Алгоритмы игры стараются максимально соответствовать правилам классической игры "Морской бой". Присутствует подобие искуственного интелекта (не обучается), старается сделать минимальное количество выстрелов для победы.
3 |
4 | > Игра может не запуститься в браузерах Internet Explorer, при чем даже в 11 верии,
5 | > все за за `Object.assign()` и многих других мелочей которые не поддерживаются в IE.
6 |
7 |
8 | ## Примеры
9 | [Основной пример можно мосмотреть GitHub Pages](https://alx2das.github.io/battlefield-js/examples/).
10 |
11 |
12 | ## Сборка
13 | Для сборки у вас уже должен быть установлен [Node.js с NPM](https://nodejs.org/). Все необходимые зависимости приписаны в файле `package.json`.
14 | Я использовал [Gulp](http://gulpjs.com/), поэтому у Вас он должен быть установлен глобально.
15 |
16 | ```sh
17 | npm i gulp -g
18 | ```
19 |
20 | Для запуска используйте команду по умолчанию:
21 |
22 | ```sh
23 | gulp
24 | ```
25 |
26 |
27 | ## Тестирование
28 | Для тестирования я использовал [Jasmine](https://jasmine.github.io/2.0/introduction.html). Пока что реализованно только браузерное тестирование, пожже добавлю серверное при сборке.
29 |
30 | Для запуска тестов должен быть глобально установлен `bower` и все необходимые зависимости которые описаны в файле `bower.json`:
31 |
32 | ```sh
33 | npm i bower -g
34 | bower i
35 | ```
36 |
37 | Максимальную информацию по опциям Вы можите увидеть в [исходном коде](https://github.com/alx2das/battlefield-js/tree/master/src).
38 |
39 |
40 | #### [Лицензия ISC](https://ru.wikipedia.org/wiki/%D0%9B%D0%B8%D1%86%D0%B5%D0%BD%D0%B7%D0%B8%D1%8F_ISC)
--------------------------------------------------------------------------------
/src/css/battlefield.logger.css:
--------------------------------------------------------------------------------
1 | .bf-logger {
2 | max-width: 950px;
3 | margin: 0 auto;
4 | }
5 |
6 | .bf-logger h2 {
7 | padding-bottom: 15px;
8 | }
9 |
10 | .bf-logger ul {
11 | list-style: none;
12 | max-height: 300px;
13 | overflow-y: auto;
14 | margin-bottom: 25px;
15 | }
16 |
17 | .bf-logger ul li {
18 | display: block;
19 | padding: 7px 0;
20 | border-bottom: 1px solid #d6d6d6;
21 | }
22 |
23 | .bf-logger ul li.no-active {
24 | display: none;
25 | }
26 |
27 | .bf-logger ul li:hover {
28 | background-color: #f6f6f6
29 | }
30 |
31 | .game-log ul li:last-child {
32 | border-bottom: none;
33 | }
34 |
35 | .bf-logger ul li .point, .bf-logger ul li .type, .bf-logger ul li .time {
36 | width: 60px;
37 | display: inline-block;
38 | }
39 |
40 | .bf-logger ul li .point, .bf-logger ul li .time {
41 | font-weight: 700
42 | }
43 |
44 | .bf-logger ul li .point {
45 | }
46 |
47 | .bf-logger ul li .type {
48 | margin: 0 10px;
49 | font-size: 12px;
50 | padding: 2px 0;
51 | text-align: center;
52 | border-radius: 2px;
53 | font-weight: 700;
54 | }
55 |
56 | .bf-logger ul li .type.kil {
57 | background-color: #d9534f;
58 | color: #fff;
59 | }
60 |
61 | .bf-logger ul li .type.war {
62 | background-color: #f0ad4e;
63 | color: #fff;
64 | }
65 |
66 | .bf-logger ul li .type.nul {
67 | }
68 |
69 | .bf-logger ul li .name {
70 | font-size: 14px
71 | }
72 |
73 | .bf-logger ul li .time {
74 | float: right;
75 | }
76 |
77 | .bf-logger .bf-filter {
78 | float: right;
79 | font-weight: 400;
80 | font-size: 13px;
81 | }
82 |
83 | .bf-logger .bf-filter.no-active {
84 | display: none;
85 | }
86 |
87 | .bf-logger .bf-filter span.active {
88 | border-bottom: 1px solid;
89 | }
--------------------------------------------------------------------------------
/src/js/battlefield.options.js:
--------------------------------------------------------------------------------
1 | var options = {}, // глобальный объект с опциями игры
2 | // публичные свойства, могут быть изменены через config
3 | _optionsPublic = {
4 | printName: true, // печатать имена игроков
5 | printLog: true, // ведения журнала боя
6 | printHelp: true, // использовать подсказки
7 |
8 | fSize: { // размерность игрового поля
9 | h: 15, v: 15 // h - горизонтально, v - вертикально
10 | },
11 | fBarrier: [ // список кораблей на игровом поле
12 | [5, 2], [4, 3], [3, 4], [2, 5], [1, 6] // по принципу: ["кол-во палуб", "кол-во штук"]
13 | ],
14 | fMarker: { // обозначение ячеек
15 | h: 'number', v: 'char' // могут быть: char или number
16 | }
17 | },
18 | // приватные, не доступны для изменения
19 | _optionsPrivate = {
20 | player: { // коды играков, должны начинаться с буквы
21 | kUser: 'FUser', kBrain: 'FBrain'
22 | },
23 | winner: {
24 | kUser: 0, kBrain: 0
25 | },
26 | tPoint: { // типы точек игрового поля
27 | DEF: 0, BAR: 1, KIL: 2, NUL: 3 // пусто, корабль, ранил, мимо
28 | }
29 | };
--------------------------------------------------------------------------------
/examples/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Battlefield JS
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
29 |
30 |
31 |
32 |
33 |
34 |
42 |
43 |
46 |
47 |
48 |
52 |
53 |
54 |
55 |
56 |
57 |
--------------------------------------------------------------------------------
/examples/development.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Battlefield JS
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
34 |
35 |
36 |
37 |
38 |
39 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
60 |
61 |
62 |
63 |
64 |
65 |
--------------------------------------------------------------------------------
/src/css/battlefield.global.css:
--------------------------------------------------------------------------------
1 | * {
2 | margin: 0;
3 | padding: 0
4 | }
5 |
6 | html, body {
7 | min-height: 100%;
8 | height: 100%;
9 | font-family: Arial, sans-serif;
10 | }
11 |
12 | .wrap {
13 | width: 950px;
14 | margin: 0 auto;
15 | }
16 |
17 | .container {
18 | min-height: 100%;
19 | }
20 |
21 | .container .clear-footer {
22 | height: 46px;
23 | }
24 |
25 | .ctn-header:after, .ctn-footer:after {
26 | content: " ";
27 | clear: both;
28 | display: block;
29 | }
30 |
31 | .ctn-header {
32 | padding: 20px 0;
33 | border-bottom: 1px solid #7a8b9f;
34 | }
35 |
36 | .ctn-header .logotype {
37 | float: left;
38 | color: #7a8b9f;
39 | font-weight: 700;
40 | font-size: 26px;
41 | text-decoration: none;
42 | }
43 |
44 | .ctn-header .logotype small {
45 | font-weight: 400;
46 | font-size: 12px;
47 | color: #b5b5b5;
48 | }
49 |
50 | .ctn-header .soc-btn {
51 | float: right;
52 | padding: 3px 0;
53 | }
54 |
55 | .ctn-footer {
56 | padding: 15px 0;
57 | margin-top: -46px;
58 | border-top: 1px solid #7a8b9f;
59 | font-size: 13px;
60 | color: #b5b5b5;
61 | }
62 |
63 | .ctn-footer .copy {
64 | float: left;
65 | }
66 |
67 | .ctn-footer .file {
68 | float: left;
69 | margin-left: 25px;
70 | }
71 |
72 | .ctn-footer .file a {
73 | color: #7a8b9f;
74 | text-decoration: none;
75 | }
76 |
77 | .ctn-footer .file a:hover {
78 | border-bottom: 1px solid #7a8b9f
79 | }
80 |
81 | .bf-player-name, .bf-fields, .bf-logger, .bf-modal-window, .btn {
82 | font-family: Arial, sans-serif;
83 | color: #7a8b9f;
84 | font-size: 13px;
85 | }
86 |
87 | .bf-player-name, .bf-fields, .bf-logger {
88 | padding: 25px 0;
89 | }
90 |
91 | .bf-player-name:after, .bf-fields:after, .bf-logger:after {
92 | content: " ";
93 | clear: both;
94 | display: block;
95 | }
96 |
97 | .btn {
98 | color: #fff;
99 | float: left;
100 | margin-right: 10px;
101 | outline: 0;
102 | margin-bottom: 0;
103 | font-weight: 400;
104 | text-align: center;
105 | vertical-align: middle;
106 | cursor: pointer;
107 | border: 1px solid transparent;
108 | white-space: nowrap;
109 | padding: 7px 14px;
110 | font-size: 13px;
111 | line-height: 1.2;
112 | border-radius: 3px;
113 | -webkit-user-select: none;
114 | -moz-user-select: none;
115 | -ms-user-select: none;
116 | user-select: none;
117 | }
118 |
119 | .btn {
120 | background-color: #5cb85c;
121 | color: #fff;
122 | }
123 |
124 | .btn:active {
125 | background-color: #449d44;
126 | }
127 |
128 | .btn:hover {
129 | background-color: #449d44;
130 | }
131 |
132 | .btn.btn-warning {
133 | background-color: #f0ad4e;
134 | }
135 |
136 | .btn.btn-warning:active {
137 | background-color: #ec971f;
138 | }
139 |
140 | .btn.btn-warning:hover {
141 | background-color: #ec971f;
142 | }
143 |
144 | .btn.btn-danger {
145 | background-color: #d9534f;
146 | float: right;
147 | margin-right: 0
148 | }
149 |
150 | .btn.btn-danger:active {
151 | background-color: #c9302c;
152 | background-image: none;
153 | }
154 |
155 | .btn.btn-danger:hover {
156 | background-color: #c9302c;
157 | }
158 |
159 | span.js {
160 | margin-left: 15px;
161 | cursor: pointer;
162 | color: #7a8b9f;
163 | border-bottom: 1px dashed #7a8b9f;
164 | }
165 |
166 | span.js:hover {
167 | border-bottom: none
168 | }
--------------------------------------------------------------------------------
/test/spec/class.battlefield.js:
--------------------------------------------------------------------------------
1 | describe('Публичный класс Battlefield()', function() {
2 | var BF;
3 |
4 | beforeEach(function () {
5 | options = {};
6 | _instances = false;
7 | });
8 | afterEach(function () {
9 | BF = undefined;
10 | });
11 |
12 | it("Применение публичных опций", function() {
13 | BF = new Battlefield('htmlSelector', {
14 | fSize: { h: 22, v: 23 },
15 | fBarrier: [
16 | [6, 1], [5, 2], [4, 3], [3, 3], [2, 4], [1, 6]
17 | ]
18 | });
19 |
20 | expect(options.fSize.h).toEqual(22);
21 | expect(options.fSize.v).toEqual(23);
22 | expect(options.fBarrier.length).toEqual(6);
23 | expect(options.fBarrier[0]).toEqual([6, 1]);
24 | });
25 |
26 | it("Игнорирование изменения приватных опций", function() {
27 | BF = new Battlefield('htmlSelector', {
28 | player: {
29 | kUser: 'BlaBlaUser', kBrain: 'BlaBlaBrain'
30 | },
31 | tPoint: {
32 | DEF: '12', BAR: '13', KIL: '14', NUL: '15'
33 | }
34 | });
35 |
36 | expect(options.player.kUser).not.toBe('BlaBlaUser');
37 | expect(options.player.kBrain).not.toBe('BlaBlaBrain');
38 |
39 | expect(options.tPoint.DEF).not.toBe('12');
40 | expect(options.tPoint.DEF).not.toBe('13');
41 | expect(options.tPoint.DEF).not.toBe('14');
42 | expect(options.tPoint.DEF).not.toBe('15');
43 | });
44 |
45 | it('Установка уровня сложности', function () {
46 | BF = new Battlefield('htmlSelector');
47 |
48 | expect(options.fSize.h).not.toBe(10);
49 | expect(options.fSize.v).not.toBe(10);
50 | expect(options.fBarrier.length).not.toBe(4);
51 |
52 | BF.setLevel('easy');
53 |
54 | expect(options.fSize.h).toBe(10);
55 | expect(options.fSize.v).toBe(10);
56 | expect(options.fBarrier.length).toBe(4);
57 |
58 | BF.setLevel('middle');
59 |
60 | expect(options.fSize.h).toBe(15);
61 | expect(options.fSize.v).toBe(15);
62 | expect(options.fBarrier.length).toBe(5);
63 |
64 | BF.setLevel('hard');
65 |
66 | expect(options.fSize.h).toBe(15);
67 | expect(options.fSize.v).toBe(20);
68 | expect(options.fBarrier.length).toBe(6);
69 | });
70 | });
71 |
72 | describe('Приватный класс Field()', function () {
73 | var BF;
74 | var F;
75 |
76 | beforeEach(function () {
77 | options = {};
78 | _instances = false;
79 |
80 | BF = new Battlefield('htmlSelector');
81 | });
82 | afterEach(function () {
83 | BF = undefined;
84 | });
85 |
86 | it('Создание игровых полей', function () {
87 | BF.setLevel('easy');
88 | F = new Field();
89 | expect(F.fields[options.player.kUser].length).toBe(10);
90 | expect(F.fields[options.player.kUser][0].length).toBe(10);
91 |
92 | delete F;
93 |
94 | BF.setLevel('middle');
95 | F = new Field();
96 | expect(F.fields[options.player.kUser].length).toBe(15);
97 | expect(F.fields[options.player.kUser][0].length).toBe(15);
98 |
99 | delete F;
100 |
101 | BF.setLevel('hard');
102 | F = new Field();
103 | expect(F.fields[options.player.kUser].length).toBe(20);
104 | expect(F.fields[options.player.kUser][0].length).toBe(15);
105 | })
106 | });
--------------------------------------------------------------------------------
/gulpfile.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | var pkg = require('./package.json'),
4 | gulp = require('gulp'),
5 | autoprefixer = require('autoprefixer'),
6 | postcss = require('gulp-postcss'),
7 | concat = require('gulp-concat'),
8 | uglify = require('gulp-uglify'),
9 | minifyCSS = require('gulp-minify-css'),
10 | rename = require("gulp-rename"),
11 | del = require('del'),
12 | runSequence = require('run-sequence');
13 |
14 | // очистка директории
15 | gulp.task('clean', function () {
16 | return del('dist');
17 | });
18 |
19 | // обьединение файлов
20 | gulp.task('concat', function (callback) {
21 | runSequence(
22 | ['concat:js', 'concat:css'],
23 | callback
24 | );
25 | });
26 |
27 | // обьединение JS файлов
28 | gulp.task('concat:js', function () {
29 | return gulp
30 | .src([
31 | 'src/js/battlefield.options.js',
32 | 'src/js/battlefield.class-battlefield.js',
33 | 'src/js/battlefield.class-field.js',
34 | 'src/js/battlefield.class-battle.js',
35 | 'src/js/battlefield.class-gameui.js',
36 | 'src/js/battlefield.helper.js'
37 | ])
38 | .on('data', function (file) {
39 | file.contents = new Buffer(file.contents.toString() + '\n');
40 | })
41 | .pipe(concat('battlefield.js'))
42 | .on('data', function (file) {
43 | file.contents = new Buffer(
44 | description() +
45 | '(function(window){' +
46 | ' \n' +
47 | ' "use strict";' +
48 | ' \n\n' +
49 | file.contents.toString() +
50 | ' \n' +
51 | ' window.Battlefield = Battlefield;' +
52 | ' \n' +
53 | '})(window);'
54 | );
55 | })
56 | .pipe(gulp.dest('dist'));
57 | });
58 |
59 | // обьединение CSS файлов
60 | gulp.task('concat:css', function () {
61 | return gulp
62 | .src('src/css/*.css')
63 | .pipe(postcss([autoprefixer()]))
64 | .pipe(concat('battlefield.css'))
65 | .on('data', function (file) {
66 | file.contents = new Buffer(
67 | description() +
68 | file.contents.toString()
69 | )
70 | })
71 | .pipe(gulp.dest('dist'));
72 | });
73 |
74 | // минификация файлов
75 | gulp.task('min', function (callback) {
76 | runSequence(
77 | ['min:js', 'min:css'],
78 | callback
79 | );
80 | });
81 |
82 | // добавляем метрику
83 | gulp.task('metrika', function () {
84 | return gulp
85 | .src([
86 | 'dist/battlefield.js',
87 | 'src/js/metrika.js'
88 | ])
89 | .on('data', function (file) {
90 | file.contents = new Buffer(file.contents.toString() + '\n');
91 | })
92 | .pipe(concat('battlefield.js'))
93 | .pipe(gulp.dest('dist'));
94 | });
95 |
96 | // минификация JS файлов
97 | gulp.task('min:js', function () {
98 | return gulp
99 | .src(['dist/battlefield.js'])
100 | .pipe(rename('battlefield.min.js'))
101 | .pipe(uglify())
102 | .on('data', function (file) {
103 | file.contents = new Buffer(
104 | description() +
105 | file.contents.toString()
106 | );
107 | })
108 | .pipe(gulp.dest('dist'));
109 | });
110 |
111 | // минификация CSS файлов
112 | gulp.task('min:css', function () {
113 | return gulp
114 | .src(['dist/battlefield.css'])
115 | .pipe(rename('battlefield.min.css'))
116 | .pipe(minifyCSS())
117 | .on('data', function (file) {
118 | file.contents = new Buffer(
119 | description() +
120 | file.contents.toString()
121 | )
122 | })
123 | .pipe(gulp.dest('dist'));
124 | });
125 |
126 | // главная задача
127 | gulp.task('default', function (callback) {
128 | runSequence(
129 | 'clean',
130 | 'concat',
131 | 'metrika',
132 | 'min',
133 | callback
134 | );
135 | });
136 |
137 | // описание для файлов
138 | function description() {
139 | return '' +
140 | '/**\n' +
141 | ' * ' + pkg.name + ' v' + pkg.version + '\n' +
142 | ' * ' + pkg.description + '\n' +
143 | ' * \n' +
144 | ' * repository: ' + pkg.repository.url + '\n' +
145 | ' * bugs: ' + pkg.repository.url + '\n' +
146 | ' * homepage: ' + pkg.homepage + '\n' +
147 | ' * \n' +
148 | ' * Copyright 2017, ' + pkg.author + '\n' +
149 | ' * Date: ' + new Date().toDateString() + '\n' +
150 | ' */\n';
151 | }
--------------------------------------------------------------------------------
/src/js/battlefield.class-field.js:
--------------------------------------------------------------------------------
1 | /**
2 | * Класс для создания игрового поля
3 | *
4 | * Требуется:
5 | * options = {} - глобальный объект с опциями игры
6 | * h = {} - глобальный обьект функций помошников
7 | *
8 | * @constructor
9 | */
10 | function Field() {
11 | if (options.fSize.h < 10 || options.fSize.h > 25 || options.fSize.v < 10 || options.fSize.v > 25)
12 | throw new RangeError(h.getMessage('err_size_field'));
13 |
14 | if (!(options.fBarrier instanceof Array) || options.fBarrier.length < 1)
15 | throw new RangeError(h.getMessage('err_barrier'));
16 |
17 | this.fields = [];
18 | this.fName = [options.player.kUser, options.player.kBrain];
19 |
20 | for (var player in options.player) { // создание игровых полей
21 | var fKey = options.player[player];
22 |
23 | var field = new Array(options.fSize.v);
24 | for (var i = 0; i < options.fSize.v; i++) {
25 | field[i] = new Array(options.fSize.h);
26 |
27 | for (var j = 0; j < options.fSize.h; j++)
28 | field[i][j] = options.tPoint.DEF;
29 | }
30 |
31 | this.fields[fKey] = field;
32 | }
33 | }
34 |
35 | /**
36 | * Устанавливает корабли на игровое поле
37 | *
38 | * @returns {Array}
39 | */
40 | Field.prototype.setBarrier = function () {
41 | var self = this,
42 | maxIteration = this.fName.length * 100;
43 |
44 | this.fName.forEach(function (fKey) { // на каждое игровое поле ставим по отдельности
45 | var field = self.fields[fKey];
46 |
47 | options.fBarrier.forEach(function (ship) { // перебираем типы кораблей
48 | var cell = ship[0], // кол-во палуб
49 | ctn = ship[1]; // кол-во штук
50 |
51 | for (var c = 0; c < ctn; c++) // устанавливаем по одному
52 | field = shipInField(cell, field);
53 | });
54 |
55 | self.fields[fKey] = field;
56 | });
57 |
58 | return this.fields; // игровые поля с кораблями
59 |
60 |
61 | // private method....................
62 | // ..................................
63 |
64 | // установит корабль на игровое поле
65 | function shipInField(cell, field) {
66 | if (maxIteration > 0) maxIteration--; // от зацикливания рекурсии
67 | else throw new RangeError(h.getMessage('err_max_iteration'));
68 |
69 | var sPoint = [], // массив точек для размещения корабля
70 | x = h.rand(0, options.fSize.v - 1), // случайная координата начала установки
71 | y = h.rand(0, options.fSize.h - 1);
72 |
73 | var posHorizontal = h.rand(1, 2) % 2; // случайное направление, горизонтально/вертикально
74 |
75 | for (var i = 0; i < cell; i++) { // перебор палуб
76 | var pX = x, pY = y;
77 |
78 | if (posHorizontal) pX = x + i; // направление корабля
79 | else pY = y + i;
80 |
81 | if (checkPoint(pX, pY, field)) // если точка свободна, сохраняем ее
82 | sPoint.push([pX, pY]);
83 | else return shipInField(cell, field); // перезапуск
84 | }
85 |
86 | // сюда дайдет если только все точки доступны для размещения
87 | sPoint.forEach(function (point) { // точки которые можно нанести на карту
88 | var x = point[0],
89 | y = point[1];
90 |
91 | field[x][y] = options.tPoint.BAR;
92 | });
93 |
94 | return field; // вернем карту с размещенным кораблем
95 | }
96 |
97 | // проверяет выбранную точку + ее окружение
98 | function checkPoint(x, y, field) {
99 | var cP = [[-1, 0], [-1, -1], [0, -1], [1, -1], [1, 0], [1, 1], [0, 1], [-1, 1]],
100 | pX = 0, pY = 0;
101 | var sX = options.fSize.v - 1,
102 | sY = options.fSize.h - 1;
103 |
104 | if (x < 0 || x > sX || y < 0 || y > sY) // исходная точка в рамках игрового поля
105 | return false;
106 |
107 | if (field[x][y] !== options.tPoint.DEF) // точка свободна
108 | return false;
109 |
110 | for (var i = 0; i < cP.length; i++) { // перебор соседних точек
111 | pX = x + cP[i][0];
112 | pY = y + cP[i][1];
113 |
114 | if (pX >= 0 && pX <= sX && pY >= 0 && pY <= sY) { // сеседние точки могут быть за гранью поля
115 | if (field[pX][pY] != options.tPoint.DEF) // но не могут быть заняты другим кораблем
116 | return false;
117 | }
118 | }
119 |
120 | return true; // если все условия проверки пройдены, можно ставить
121 | }
122 | };
--------------------------------------------------------------------------------
/src/css/battlefield.fields.css:
--------------------------------------------------------------------------------
1 | .bf-fields {
2 | background-color: #7a8b9f;
3 | }
4 |
5 | .bf-fields:after {
6 | content: " ";
7 | display: block;
8 | clear: both
9 | }
10 |
11 | .bf-fields .board {
12 | width: 50%
13 | }
14 |
15 | .bf-fields .board.lf {
16 | float: left
17 | }
18 |
19 | .bf-fields .board.rg {
20 | float: right
21 | }
22 |
23 | .bf-fields table.field {
24 | border-collapse: collapse;
25 | margin: 25px;
26 | }
27 |
28 | .bf-fields table.field td, .bf-fields table.field td .box {
29 | border: 2px solid #E5EAFF;
30 | }
31 |
32 | .bf-fields table.field td .box, .bf-fields table.field td .ll, .bf-fields table.field td .mm {
33 | width: 28px;
34 | height: 28px;
35 | line-height: 28px;
36 | text-align: center;
37 | }
38 |
39 | .bf-fields table.field td .ll, .bf-fields table.field td .mm {
40 | position: absolute;
41 | z-index: 1;
42 | font-family: Georgia;
43 | color: #afafaf;
44 | font-weight: 700;
45 | font-size: 12px
46 | }
47 |
48 | .bf-fields table.field td .ll {
49 | left: -28px
50 | }
51 |
52 | .bf-fields table.field td .mm {
53 | top: -28px
54 | }
55 |
56 | .bf-fields table.field td {
57 | position: relative;
58 | }
59 |
60 | .bf-fields table.field td .box {
61 | float: left;
62 | margin: -2px
63 | }
64 |
65 | .bf-fields table.field td .box.null, .bf-fields table.field td .box.auto-null, .bf-fields table.field td .box.kill, .bf-fields .list-let .box.kill {
66 | background: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAADgAAAAcCAYAAAA0u3w+AAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAyFpVFh0WE1MOmNvbS5hZG9iZS54bXAAAAAAADw/eHBhY2tldCBiZWdpbj0i77u/IiBpZD0iVzVNME1wQ2VoaUh6cmVTek5UY3prYzlkIj8+IDx4OnhtcG1ldGEgeG1sbnM6eD0iYWRvYmU6bnM6bWV0YS8iIHg6eG1wdGs9IkFkb2JlIFhNUCBDb3JlIDUuNS1jMDIxIDc5LjE1NDkxMSwgMjAxMy8xMC8yOS0xMTo0NzoxNiAgICAgICAgIj4gPHJkZjpSREYgeG1sbnM6cmRmPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5LzAyLzIyLXJkZi1zeW50YXgtbnMjIj4gPHJkZjpEZXNjcmlwdGlvbiByZGY6YWJvdXQ9IiIgeG1sbnM6eG1wPSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvIiB4bWxuczp4bXBNTT0iaHR0cDovL25zLmFkb2JlLmNvbS94YXAvMS4wL21tLyIgeG1sbnM6c3RSZWY9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC9zVHlwZS9SZXNvdXJjZVJlZiMiIHhtcDpDcmVhdG9yVG9vbD0iQWRvYmUgUGhvdG9zaG9wIENDIChXaW5kb3dzKSIgeG1wTU06SW5zdGFuY2VJRD0ieG1wLmlpZDpDRjMwN0VCOEM4NDcxMUU1OTM5M0RBNkE1MDVDQUVEMSIgeG1wTU06RG9jdW1lbnRJRD0ieG1wLmRpZDpDRjMwN0VCOUM4NDcxMUU1OTM5M0RBNkE1MDVDQUVEMSI+IDx4bXBNTTpEZXJpdmVkRnJvbSBzdFJlZjppbnN0YW5jZUlEPSJ4bXAuaWlkOkNGMUMzMzI1Qzg0NzExRTU5MzkzREE2QTUwNUNBRUQxIiBzdFJlZjpkb2N1bWVudElEPSJ4bXAuZGlkOkNGMUMzMzI2Qzg0NzExRTU5MzkzREE2QTUwNUNBRUQxIi8+IDwvcmRmOkRlc2NyaXB0aW9uPiA8L3JkZjpSREY+IDwveDp4bXBtZXRhPiA8P3hwYWNrZXQgZW5kPSJyIj8+aamjFgAAAmdJREFUeNrs2E1IFGEcx/FdldlVWosiyg7WKQo6LNFFykgoL4GKEER16OUQ5kW6RZ3yUKcugVJLJEKIHSSiRKUoO0UvaChSInSIXpBa1y13Y3fW6fvIXxi2nX1zwJ1lHviwLzPzzPyet9lZr2EYnnIuFZ4yL25AN2Cxxeu10oKNWbZn5qAe/Ixh1ObYr8apQ3QKAQkZsNhnK1qdPAcHcVBCbkjrMfU6hJdODjgAdYM+JCG3oBeVsu0bvudTUVUhZz3cdHT17THsxhtMI/7qxTO7wql6w3iNBjRiTi1LuI0WNOVbWVWBJ1cteAPNSOEi7qMPCwXWFcRxLEqYD0hiGRPYbtp3k7x2YCbf4VlMwHbVkSdPtCd9Pl8wkUhMj449Px+ORL7y/cMC65qUBeW0zLk6CabC3sU1i+N6TQvNDmmUGbvmoFrVlgm3XzWOpmlBf031XzlJMUWNgn7sQRfqcRnXoVkccwV/cE8a5aOdi8y4ajld12dXri6VmossRDbLpF9LSUqv7ZUezFZUr92UuTgiQ9q2gEu482R41PPu/cT4o8dPPbF4PMR3v2xYXNScDMk8z1W6ZXXdafcc/IEHi9HoLHS1euKLrHJrLZNy4YN5/BA4g21yr/wpDZ+5qOfBdSE3OpMLWDLUJeXW/9/xFucphYC1GEgLEEU4Q7C3pvddTgh4AJ8whZD04j5UoE+CxHAVOjR04jeSOFLKAf1oRCDDcFV6JOA5+dxh2rYLI5hHfbaA3nX7TybLM5yUW/DjklUNOItTK08WhhEr9UUmXasMyVz71aGt9HrQ/U/GDegGdAOWQ/knwAALfSfZ0tNOqgAAAABJRU5ErkJggg==) 0 0 no-repeat;
67 | }
68 |
69 | .bf-fields table.field td .box.let {
70 | background-color: #E5EAFF
71 | }
72 |
73 | .bf-fields table.field td .box.null {
74 | opacity: 1 !important;
75 | }
76 |
77 | .bf-fields table.field td .box.auto-null {
78 | opacity: .5;
79 | }
80 |
81 | .bf-fields table.field td .box.kill {
82 | background-position: -28px 0;
83 | background-color: #a1b9d6;
84 | }
85 |
86 | .bf-fields table.field td .box.death {
87 | background-color: #deabab
88 | }
89 |
90 | .bf-fields .shot {
91 | position: absolute;
92 | z-index: 1;
93 | width: 28px;
94 | height: 28px;
95 | margin: -2px;
96 | background-color: rgba(255, 249, 0, 0.7);
97 | border: 2px solid #fff900;
98 | }
99 |
100 | .bf-fields .list-let {
101 | margin: 25px 15px 0;
102 | float: left;
103 | }
104 |
105 | .bf-fields .list-let .let {
106 | margin-bottom: 10px
107 | }
108 |
109 | .bf-fields .list-let .let:after {
110 | content: " ";
111 | display: block;
112 | clear: both
113 | }
114 |
115 | .bf-fields .list-let span {
116 | width: 26px;
117 | height: 26px;
118 | line-height: 26px;
119 | margin: 0 10px;
120 | text-align: center;
121 | color: #afafaf;
122 | font-weight: 700;
123 | display: inline-block;
124 | background: 0 0;
125 | border: none;
126 | }
127 |
128 | .bf-fields .list-let span .shot {
129 | width: 24px;
130 | height: 24px;
131 | margin: -27px 0 0 0;
132 | }
133 |
134 | .bf-fields .list-let .box {
135 | float: left;
136 | width: 24px;
137 | height: 24px;
138 | margin-left: -2px;
139 | background-color: rgba(165, 188, 208, .5) !important;
140 | border: 2px solid #E5EAFF;
141 | }
142 |
143 | .bf-fields .list-let .box.kill {
144 | background-position: -28px 0;
145 | }
146 |
147 | .bf-fields .board.rg table.field td .box {
148 | cursor: pointer;
149 | }
150 |
151 | .bf-fields .board.rg table.field td .box:hover {
152 | box-shadow: inset 0 0 5px 2px #ff8d8d;
153 | }
154 |
155 | .bf-fields .board.rg table.field td .box.kill:hover,
156 | .bf-fields .board.rg table.field td .box.let:hover,
157 | .bf-fields .board.rg table.field td .box.null:hover,
158 | .bf-fields .board.rg table.field td .box.auto-null:hover {
159 | box-shadow: none !important;
160 | cursor: default !important;
161 | }
162 |
163 | .bf-fields .board table.field.timeout {
164 | opacity: 0.7;
165 | -webkit-user-select: none;
166 | -moz-user-select: none;
167 | -ms-user-select: none;
168 | user-select: none;
169 | }
170 |
171 | .bf-fields .board table.field.timeout .box {
172 | cursor: wait !important;
173 | }
174 |
175 | .bf-fields .board.lf table.field,
176 | .bf-fields .board.lf .list-let,
177 | .bf-fields .board.lf .list-let .box,
178 | .bf-fields .board.rg .list-let span {
179 | float: right
180 | }
181 |
182 | .bf-fields .board.rg table.field,
183 | .bf-fields .board.rg .list-let,
184 | .bf-fields .board.rg .list-let .box,
185 | .bf-fields .board.lf .list-let span {
186 | float: left
187 | }
--------------------------------------------------------------------------------
/src/js/battlefield.helper.js:
--------------------------------------------------------------------------------
1 | // глобальный класс модуля
2 | var h = {
3 | /**
4 | * имена играков по умолчанию
5 | */
6 | playerName: {
7 | def: {
8 | kUser: 'Игрок', kBrain: 'Компьютер'
9 | }
10 | },
11 |
12 | /**
13 | * Вернет случайное число в интервале
14 | *
15 | * @param min - по умолчанию: 0
16 | * @param max - по умолчанию: 100
17 | * @returns {Number}
18 | */
19 | rand: function (min, max) {
20 | min = min || 0;
21 | max = max || 100;
22 |
23 | return parseInt(Math.random() * (max - min + 1) + min);
24 | },
25 |
26 | /**
27 | * Вернет буквку англ.алфавита по номеру.
28 | * Если номер больше кол-ва букв, к результату будет прибавлена цифра
29 | *
30 | * @param key
31 | * @param operand
32 | * @returns {*}
33 | */
34 | getLetter: function (key, operand) {
35 | var operand = operand || '',
36 | alphabet = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
37 | if (key > alphabet.length)
38 | return this.getLetter(key - alphabet.length, (operand == '' ? 1 : operand + 1));
39 |
40 | return alphabet[key] + operand;
41 | },
42 |
43 | /**
44 | * Перемешает массив случайным образом
45 | *
46 | * @param arr - массив
47 | * @returns {*}
48 | */
49 | shuffle: function (arr) {
50 | var inx, buffer;
51 | for (var i = 0; i < arr.length - 1; i++) {
52 | inx = this.rand(0, arr.length - 1);
53 | buffer = arr[inx];
54 |
55 | arr[inx] = arr[arr.length - 1];
56 | arr[arr.length - 1] = buffer;
57 | }
58 | return arr;
59 | },
60 |
61 | /**
62 | * Интернализация
63 | *
64 | * @param type
65 | * @returns {*}
66 | */
67 | getMessage: function (type) {
68 | var mess = {
69 | start_game: 'Начать игру',
70 | new_game: 'Новая игра',
71 | game_over: 'Игра закончена',
72 | you_lose: 'Ты проиграл',
73 | you_winner: 'Ты выиграл',
74 | options: 'Настройки',
75 | update_options: 'Изменить настройки',
76 | close: 'Закрыть',
77 | update_page: 'Обновить страницу',
78 | set_default_params: 'Настройки по умолчанию',
79 | save: 'Сохранить',
80 | filter: 'Фильтр',
81 | full: 'Все',
82 |
83 | log_kill: 'ранил',
84 | log_death: 'убил',
85 | log_past: 'мимо',
86 |
87 | // error
88 | err_invalid_selector: 'Указанный HTML блок на странице не найден',
89 | err_max_iteration: 'Не получилось установить корабли на игровое поле, измените настройки',
90 | err_invalid_player: 'Неизвестный игрок',
91 | err_invalid_field: 'Некорректное игровое поле',
92 | err_player_name: 'Переданны не корректные ключи играков',
93 | err_size_field: 'Игровое поле не должно быть меньше 10х10 или больше 25х25, измените настройки',
94 | err_barrier: 'Не корректный список кораблей',
95 | err_invalid_level: 'Указан несуществующий уровень сложности',
96 |
97 | // info
98 | info_log_title: 'Состояние игрового поля',
99 | info_title_error: 'Критическая ошибка',
100 | info_title_range_error: 'Некорректные настройки',
101 | info_winner: 'Замечательная победа,
попробуешь еще?',
102 | info_loser: 'В следующий раз повезет больше,
попробуешь еще?'
103 | };
104 |
105 | return typeof mess[type] == 'string' && mess[type].length > 0 ? mess[type] : type;
106 | },
107 |
108 | /**
109 | * Вернет строковое имя игрока
110 | *
111 | * @param fKey - строковый ключ игрока
112 | * @returns {*}
113 | */
114 | getPlayerName: function (fKey) {
115 | var key = fKey == options.player.kUser ? 'kUser' : 'kBrain';
116 | return this.playerName.def[key];
117 | },
118 |
119 | /**
120 | * Ловит сообщение об ошибке
121 | *
122 | * @param err
123 | */
124 | showExceptions: function (err) {
125 | var title = '',
126 | content = '',
127 | button = [];
128 |
129 | switch (err.name) {
130 | case ('Error'):
131 | title = h.getMessage('info_title_error');
132 | content = err.message;
133 | button = [{
134 | elValue: h.getMessage('set_default_params'),
135 | onClick: function (modal) {
136 | modal.close();
137 | var b = new Battlefield(options.htmlSelector, options);
138 | b.setLevel('middle').run();
139 | }
140 | }];
141 | break;
142 | case ('RangeError'):
143 | title = h.getMessage('info_title_range_error');
144 | content = err.message;
145 | button = [{
146 | elValue: h.getMessage('update_options'),
147 | onClick: function (modal) {
148 | modal.close();
149 | var b = new Battlefield(options.htmlSelector, options);
150 | b.updateConfig();
151 | }
152 | },{
153 | elValue: h.getMessage('set_default_params'),
154 | elClass: 'btn-warning',
155 | onClick: function (modal) {
156 | modal.close();
157 | var b = new Battlefield(options.htmlSelector, options);
158 | b.setLevel('middle').run();
159 | }
160 | }];
161 | break;
162 | default:
163 | title = err.name;
164 | content = err.message;
165 | }
166 |
167 | this.modalWindow(title, content, button);
168 | },
169 |
170 | /**
171 | * Выводит модальное окно, автоматически установит по середине страницы
172 | *
173 | * ~~~~
174 | * h.modalWindow(
175 | * 'title modal window',
176 | * 'Content modal',
177 | * [{
178 | * elClass: 'btn-success', // css класс будет добавлен к кнопке
179 | * elValue: 'Button close', // значение кнопки
180 | * onClick: function (modal, event) {} // событие клика по кнопке
181 | * }]
182 | * )
183 | * ~~~~
184 | *
185 | * @param title - заголовок
186 | * @param contentHTML - html содержимое
187 | * @param button - массив обьектов кнопок модального окна
188 | */
189 | modalWindow: function (title, contentHTML, button) {
190 | var modal = {
191 | font: false,
192 | window: false,
193 |
194 | construct: function () {
195 | this.createHTML().autoPosition();
196 |
197 | if (!(button instanceof Array) || button.length == 0) {
198 | this.window.querySelector('.footer').style.display = 'none';
199 | return false;
200 | }
201 |
202 | var footer = this.window.querySelector('.footer'),
203 | on = [];
204 |
205 | for (var i = 0; i < button.length; i++) {
206 | var btn = button[i],
207 | dopClass = typeof button[i].elClass == 'string' ? ' ' + btn.elClass : '';
208 |
209 | on[i] = document.createElement('button');
210 | on[i].setAttribute('class', 'btn' + dopClass);
211 | on[i].setAttribute('id', 'btn_' + i);
212 | on[i].innerHTML = btn.elValue;
213 | on[i].addEventListener('click', eventListener(i, button), false);
214 |
215 | footer.appendChild(on[i]);
216 | }
217 | },
218 | createHTML: function () {
219 | var _font = document.querySelector('.bf-modal-font'),
220 | _window = document.querySelector('.bf-modal-window');
221 | if (_font != null) document.body.removeChild(_font);
222 | if (_window != null) document.body.removeChild(_window);
223 |
224 |
225 | this.font = document.createElement('div');
226 | this.font.setAttribute('class', 'bf-modal-font');
227 |
228 | this.window = document.createElement('div');
229 | this.window.setAttribute('class', 'bf-modal-window');
230 | this.window.innerHTML =
231 | '' +
232 | ' ' +
233 | '
' + contentHTML + '
' +
234 | ' ' +
235 | '
';
236 |
237 | document.body.appendChild(this.font);
238 | document.body.appendChild(this.window);
239 |
240 | return this;
241 | },
242 | autoPosition: function () {
243 | var wid2 = this.window.clientWidth / 2,
244 | hei2 = this.window.clientHeight / 2;
245 |
246 | this.window.style.marginTop = hei2 * (-1) + 'px';
247 | this.window.style.marginLeft = wid2 * (-1) + 'px';
248 | },
249 | close: function () {
250 | document.body.removeChild(this.font);
251 | document.body.removeChild(this.window);
252 | }
253 | };
254 |
255 | modal.construct();
256 |
257 |
258 | // private method....................
259 | // ..................................
260 |
261 | // вешает событие на кнопку в модальном окне
262 | function eventListener(i, obj) {
263 | return function (event) {
264 | if (typeof obj[i].onClick == 'function')
265 | obj[i].onClick(modal, event);
266 | };
267 | }
268 | },
269 |
270 | /**
271 | * Запускает анимацию плавного исчезновения со страницы
272 | *
273 | * @param element - document элемент
274 | * @param time - кол-во сек.через которое элемент исчезнет со страницы
275 | */
276 | animateOpacity: function (element, time) {
277 | element.style.opacity = 1;
278 | var t = setInterval(function () {
279 | element.style.opacity = element.style.opacity - (100 / (time / 0.1));
280 | if (element.style.opacity <= 0) {
281 | clearInterval(t);
282 | try {
283 | element.parentNode.removeChild(element);
284 | } catch (e) { }
285 | }
286 | }, 1);
287 | }
288 | };
--------------------------------------------------------------------------------
/src/js/battlefield.class-battlefield.js:
--------------------------------------------------------------------------------
1 | var _instances = false, // Singleton
2 | _globalLevel = 'middle'; // уровень сложности по умолчанию
3 |
4 | /**
5 | * Инициализирует игру, устанавливает параметры по умолчанию
6 | *
7 | * Требуется:
8 | * options = {} - глобальный объект с опциями игры
9 | * h = {} - глобальный обьект функций помошников
10 | *
11 | * @param htmlSelector - строковый селектор элемента на странице
12 | * @param config - объект настроек по умолчанию, доступные параметры: _optionsPublic
13 | * @returns {Battlefield}
14 | * @constructor
15 | */
16 | function Battlefield(htmlSelector, config) {
17 | // Singleton
18 | if (_instances instanceof Battlefield)
19 | return _instances;
20 | _instances = this;
21 |
22 | // объединяем установленные опции игры с доступными
23 | if (typeof config == 'object') {
24 | for (var key in _optionsPublic)
25 | options[key] = config.hasOwnProperty(key) ? config[key] : _optionsPublic[key];
26 | options = Object.assign(options, _optionsPrivate);
27 | }
28 | else options = Object.assign(_optionsPublic, _optionsPrivate);
29 |
30 | options.htmlSelector = document.querySelector(htmlSelector);
31 | }
32 |
33 | /**
34 | * Запуск игры
35 | */
36 | Battlefield.prototype.run = function () {
37 | try {
38 | var F = new Field();
39 | var fields = F.setBarrier();
40 |
41 | new Battle(fields, this);
42 | } catch (err) {
43 | h.showExceptions(err);
44 | }
45 | };
46 |
47 | /**
48 | * Вернет настройки для указанного уровеня сложности
49 | *
50 | * @param type
51 | * @returns {*}
52 | */
53 | Battlefield.prototype.getLevel = function (type) {
54 | var level = {
55 | easy: {
56 | fSize: {h: 10, v: 10},
57 | fBarrier: [[4, 1], [3, 2], [2, 3], [1, 4]]
58 | },
59 | middle: {
60 | fSize: {h: 15, v: 15},
61 | fBarrier: [[5, 2], [4, 3], [3, 4], [2, 5], [1, 6]]
62 | },
63 | hard: {
64 | fSize: {h: 15, v: 20},
65 | fBarrier: [[6, 1], [5, 2], [4, 3], [3, 4], [2, 5], [1, 6]]
66 | }
67 | };
68 |
69 | if (typeof level[type] == 'object') {
70 | return level[type];
71 | }
72 | else throw new Error(h.getMessage('err_invalid_level'));
73 | };
74 |
75 | /**
76 | * Установит уровень сложности
77 | *
78 | * @param type
79 | * @returns {Battlefield}
80 | */
81 | Battlefield.prototype.setLevel = function (type) {
82 | var nLevel = this.getLevel(type);
83 |
84 | options.fSize = nLevel.fSize;
85 | options.fBarrier = nLevel.fBarrier;
86 |
87 | _globalLevel = type;
88 |
89 | return this;
90 | };
91 |
92 | /**
93 | * Выведет модальное окно для изменения настроек игры
94 | */
95 | Battlefield.prototype.updateConfig = function () {
96 | var self = this;
97 |
98 | var contentHtml =
99 | '';
132 | contentHtml = '';
133 |
134 | var newLevel = _globalLevel;
135 |
136 | h.modalWindow(h.getMessage('options'), contentHtml, [{
137 | elValue: h.getMessage('new_game'),
138 | onClick: function (modal) {
139 | modal.close();
140 |
141 | try {
142 | if (newLevel == 'user') {
143 | var nOpt = getUserOptions();
144 |
145 | options.fSize = nOpt.fSize;
146 | options.fBarrier = nOpt.fBarrier;
147 |
148 | _globalLevel = newLevel;
149 | } else {
150 | if (newLevel.length > 0 && newLevel != _globalLevel)
151 | self.setLevel(newLevel);
152 | }
153 |
154 | self.run();
155 | } catch (err) {
156 | h.showExceptions(err);
157 | }
158 | }
159 | },{
160 | elValue: h.getMessage('set_default_params'),
161 | elClass: 'btn-warning',
162 | onClick: function (modal) {
163 | modal.close();
164 |
165 | self.setLevel('middle');
166 | self.run();
167 | }
168 | },{
169 | elValue: h.getMessage('close'),
170 | elClass: 'btn-danger',
171 | onClick: function (modal) {
172 | modal.close();
173 | }
174 | }
175 | ]);
176 |
177 | var table = document.querySelector('.bf-config');
178 | var btnList = document
179 | .getElementById('config_level')
180 | .querySelectorAll('button');
181 |
182 | activeFormOptions(_globalLevel == 'user');
183 | echoOptions(options);
184 |
185 | // выбор уровня сложности
186 | btnList.forEach(function (btn) {
187 | btn.onclick = function (env) {
188 |
189 | newLevel = env.target.value;
190 |
191 | btnList.forEach(function (b) {
192 | b.classList.remove('active');
193 | });
194 | env.target.classList += ' active';
195 |
196 | if (newLevel == 'user') {
197 | activeFormOptions(true);
198 | } else {
199 | activeFormOptions(false);
200 | echoOptions(self.getLevel(newLevel));
201 | }
202 |
203 | return false;
204 | }
205 | });
206 |
207 | // private method....................
208 | // ..................................
209 |
210 | // активирует форму для ввода пользовательских настроек
211 | function activeFormOptions(active) {
212 | // размер игрового поля
213 | table.querySelector('#opt-fsize').querySelectorAll('label')
214 | .forEach(function (label) {
215 | var input = label.querySelector('input');
216 |
217 | if (active) {
218 | label.classList = '';
219 | input.disabled = false;
220 | } else {
221 | label.classList = 'no-act';
222 | input.disabled = true;
223 | }
224 | });
225 |
226 | // корабли на поле
227 | table.querySelector('#opt-fbarrier').querySelectorAll('label')
228 | .forEach(function (label) {
229 | var input = label.querySelector('input');
230 |
231 | if (active) {
232 | label.classList = '';
233 | input.disabled = false;
234 | } else {
235 | label.classList = 'no-act';
236 | input.disabled = true;
237 | }
238 | });
239 | }
240 |
241 | // вернет настройки пользователя
242 | function getUserOptions() {
243 | var nOptions = {
244 | fSize: {h: 0, v: 0},
245 | fBarrier: []
246 | };
247 |
248 | // размер игрового поля
249 | nOptions.fSize.h = parseInt(table.querySelector('input#type-h').value);
250 | nOptions.fSize.v = parseInt(table.querySelector('input#type-v').value);
251 |
252 | // корабли на игровом поле
253 | table.querySelector('#opt-fbarrier').querySelectorAll('label')
254 | .forEach(function (label) {
255 | var input = label.querySelector('input'),
256 | ship = parseInt(input.getAttribute('bar')),
257 | ctn = parseInt(input.value);
258 |
259 | if (ctn > 0)
260 | nOptions.fBarrier.push([ship, ctn]);
261 | });
262 |
263 | return nOptions;
264 | }
265 |
266 | // напечатает переданные настройки
267 | function echoOptions(nOptions) {
268 | // размер игрового поля
269 | table.querySelector('input#type-h').value = nOptions.fSize.h;
270 | table.querySelector('input#type-v').value = nOptions.fSize.v;
271 |
272 | // корабли на игровом поле
273 | table.querySelector('#opt-fbarrier').querySelectorAll('input').forEach(function (input) {
274 | input.value = 0;
275 | });
276 |
277 | nOptions.fBarrier.forEach(function (barrier) {
278 | var ship = barrier[0], // кол-во палуб корабля
279 | ctn = barrier[1]; // кол-во кораблей
280 |
281 | table.querySelector('#opt-fbarrier').querySelector('input#bar_' + ship).value = ctn;
282 | });
283 | }
284 | };
--------------------------------------------------------------------------------
/src/js/battlefield.class-battle.js:
--------------------------------------------------------------------------------
1 | /**
2 | * Запускает алгоритмы обстрела игроками поля боя
3 | *
4 | * Требуется:
5 | * options = {} - глобальный объект с опциями игры
6 | * h = {} - глобальный обьект функций помошников
7 | *
8 | * @param fields - обьект массивов игровых поле
9 | * @param battlefield - экземпляр Battlefield
10 | * @constructor
11 | */
12 | function Battle(fields, battlefield) {
13 | if (!(battlefield instanceof Battlefield))
14 | throw new Error('Invalid Battlefield object in the construct Battle');
15 |
16 | GameUI.apply(this, arguments);
17 |
18 | this.fields = fields;
19 | this.battlefield = battlefield;
20 |
21 | this._lsKill = []; // последнее попадание компьютером
22 | this._lsShot = []; // список точек доступных для выстрела
23 | this._ctnCell = []; // остаток кораблей у игрока
24 |
25 | for (var p in options.player) { // заполнение данных
26 | var v = options.player[p];
27 |
28 | this._lsKill[v] = [];
29 | this._lsShot[v] = getListPoint();
30 | this._ctnCell[v] = getCountCell();
31 | }
32 | this.userKey = options.player.kUser; // ключ игрока
33 | this.enemyKey = options.player.kBrain; // ключ компьютера
34 |
35 | // первый ход
36 | this.player = h.rand(1, 2) % 2 ? this.userKey : this.enemyKey;
37 | this.game(this.player);
38 |
39 |
40 | // private method....................
41 | // ..................................
42 |
43 | function getListPoint() {
44 | var __fullPoint = [];
45 | for (var i = 0; i < options.fSize.h; i++) {
46 | for (var j = 0; j < options.fSize.v; j++)
47 | __fullPoint.push([j, i]);
48 | }
49 | return __fullPoint;
50 | }
51 |
52 | function getCountCell() {
53 | var __countCell = 0;
54 | options.fBarrier.forEach(function (ship) {
55 | __countCell += ship[0] * ship[1];
56 | });
57 | return __countCell;
58 | }
59 | }
60 |
61 | Battle.prototype = Object.create(GameUI.prototype); // наследование
62 |
63 | /**
64 | * Осуществляет переход хода
65 | *
66 | * @param fKey - строковый ключ игрока
67 | */
68 | Battle.prototype.game = function (fKey) {
69 | try {
70 | this.showProgress(fKey);
71 | this.player = fKey;
72 |
73 | switch (fKey) {
74 | case (this.userKey):
75 | this.shotUser();
76 | break;
77 | case (this.enemyKey):
78 | this.shotAI(this.userKey);
79 | break;
80 | default:
81 | throw new Error(h.getMessage('err_invalid_player'));
82 | }
83 | } catch (err) {
84 | h.showExceptions(err);
85 | }
86 | };
87 |
88 | /**
89 | * Ход игрока,
90 | * ожидает событие клика по игровому полю
91 | */
92 | Battle.prototype.shotUser = function () {
93 | var self = this;
94 |
95 | this.clickToField(this.enemyKey, function (event) {
96 | if (self.player !== self.userKey)
97 | return false;
98 |
99 | try {
100 | var Y = event.target.parentNode.cellIndex,
101 | X = event.target.parentNode.parentNode.rowIndex;
102 |
103 | self.shot([X, Y], self.enemyKey);
104 | } catch (err) {
105 | self.game(self.userKey);
106 | }
107 | });
108 | };
109 |
110 | /**
111 | * Ход компьютера,
112 | * в зависимости от попадания по кораблю противника будет
113 | * добивать корабль или стрелять по случайной клетке
114 | *
115 | * @param fKey - строковый ключ игрока
116 | */
117 | Battle.prototype.shotAI = function (fKey) {
118 | var self = this,
119 | field = this.fields[fKey],
120 | fSize = options.fSize,
121 | tPoint = options.tPoint,
122 | point = getPointShot();
123 |
124 | setTimeout(function () {
125 | self.shot(point, fKey);
126 | }, 600);
127 |
128 |
129 | // private method....................
130 | // ..................................
131 |
132 | // вернет случайную точку для выстрела
133 | function getPointShot() {
134 | var point = [];
135 |
136 | if (self._lsKill[fKey].length > 0) { // если ранее попадали по кораблю
137 | point = getPointFinishing();
138 | } else { // случайный выстрел
139 | var rInx = h.rand(0, self._lsShot[fKey].length - 1);
140 | point = self._lsShot[fKey][rInx]; // получаем случайную точку
141 | self._lsShot[fKey].splice(rInx, 1); // удаляем точку из доступных для выстрела
142 | }
143 |
144 | // проверка полученной точки...
145 | if (point instanceof Array && point[0] !== 'undefined' && point[1] !== 'undefined') {
146 | var X = point[0], Y = point[1];
147 | if (X >= 0 && X < options.fSize.v && Y >= 0 && Y < options.fSize.h) {
148 | if (field[X][Y] == tPoint.NUL || field[X][Y] == tPoint.KIL) {
149 | // уже стреляли в эту точку
150 | }
151 | else return point;
152 | }
153 | }
154 |
155 | return getPointShot();
156 | }
157 |
158 | // вернет точку для добивания
159 | function getPointFinishing() {
160 | var cP = [[-1, 0], [0, -1], [1, 0], [0, 1]], // возможные направления для добивания
161 | lsP = self._lsKill[fKey],
162 | point = [];
163 |
164 | var i = 0, n = 0;
165 |
166 | if (lsP.length == 1) { // первый выстрел при добивание
167 | var X = lsP[0][0], Y = lsP[0][1];
168 |
169 | cP = h.shuffle(cP); // перемешает массив
170 | for (i = 0; i < cP.length; i++) { // выбираем случайное направление для выстрела
171 | var pX = X + cP[i][0],
172 | pY = Y + cP[i][1];
173 |
174 | // точка в рамках поля и туда еще не стреляли
175 | if (pX >= 0 && pX < fSize.v && pY >= 0 && pY < fSize.h) {
176 | if (field[pX][pY] !== tPoint.NUL)
177 | return [pX, pY];
178 | }
179 | }
180 | } else { // второй и т.д выстрел при добивании
181 | var posHorizontal = lsP[0][0] == lsP[1][0], // определяем направление корабля
182 | min = fSize.h + fSize.v, max = 0; // крайние точки
183 |
184 | for (i = 0; i < lsP.length; i++) { // поиск крайних точек корабля
185 | n = posHorizontal ? lsP[i][1] : lsP[i][0];
186 |
187 | min = min > n ? n : min;
188 | max = max < n ? n : max;
189 | }
190 |
191 | // случайным образом определяем с какого края стрелять по караблю
192 | var nP = h.rand(1, 2) % 2 ? min - 1 : max + 1;
193 | point = posHorizontal ? [lsP[0][0], nP] : [nP, lsP[0][1]];
194 | }
195 |
196 | return point;
197 | }
198 | };
199 |
200 | /**
201 | * Осуществляет выстрел по игровому полю
202 | *
203 | * @param point - массив 2 элементов с точкой на игровом поле
204 | * @param fKey - строковый ключ игрока
205 | */
206 | Battle.prototype.shot = function (point, fKey) {
207 | var self = this,
208 | ctnCellShip = 0,
209 | _fKey = fKey == this.userKey ? this.enemyKey : this.userKey;
210 | var X = point[0], Y = point[1];
211 |
212 | var check = checkPoint(point, fKey); // проверка выстрела
213 | if (typeof check == 'boolean') { // во что то попал
214 | if (check) { // попал на по кораблю -> РАНИЛ
215 | this._ctnCell[fKey]--; // минус 1 точка для выстрела
216 |
217 | this.fields[fKey][X][Y] = options.tPoint.KIL;
218 | var isKill = isKillShip(point, fKey);
219 | if (typeof isKill == 'boolean') { // корабль просто ранен
220 | this._lsKill[fKey].push(point); // сохраняем последнее попадание
221 |
222 | this.setMarker(point, fKey, options.tPoint.KIL);
223 | this.setHelpMarker(point, fKey, function (_point) {// при ранении установим точки подсказки
224 | var _X = _point[0],
225 | _Y = _point[1];
226 | self.fields[fKey][_X][_Y] = options.tPoint.NUL;
227 | });
228 | }
229 | else { // корабль убит
230 | this._lsKill[fKey] = []; // очищаем список последнего попадания
231 |
232 | isKill.forEach(function (_point) {
233 | var _X = _point[0],
234 | _Y = _point[1];
235 |
236 | // ставим метки на игровое поле, если разрешены подсказки
237 | if (options.printHelp) {
238 | self.setMarker(_point, fKey, options.tPoint.NUL, true);
239 | self.fields[fKey][_X][_Y] = options.tPoint.NUL;
240 | }
241 | if (_fKey == options.player.kBrain)
242 | self.fields[fKey][_X][_Y] = options.tPoint.NUL;
243 | });
244 |
245 | this.setMarker(point, fKey, options.tPoint.KIL + '_death');
246 | this.shipInfoMap(ctnCellShip, fKey);
247 | }
248 |
249 | if (this._ctnCell[fKey] === 0) { // конец игры
250 | this.player = false;
251 | this.gameOver(_fKey);
252 | } else this.game(_fKey); // повтор хода
253 | }
254 | else { // попадание по пустой клетке -> МИМО
255 | this.fields[fKey][X][Y] = options.tPoint.NUL;
256 | this.setMarker(point, fKey, options.tPoint.NUL);
257 | this.game(fKey); // переход кода
258 | }
259 | }
260 | else this.game(_fKey); // уже стрелял в эту точку -> повтор хода
261 |
262 |
263 | // private method....................
264 | // ..................................
265 |
266 | // проверяет точку выстрела по полю
267 | function checkPoint(point, fKey) {
268 | var X = point[0], Y = point[1];
269 |
270 | switch (self.fields[fKey][X][Y]) {
271 | case (options.tPoint.DEF): // мимо
272 | return false;
273 | case (options.tPoint.BAR): // ранил
274 | return true;
275 | default: // что то другое
276 | return null;
277 | }
278 | }
279 |
280 | // проверка уничтожения корабля
281 | function isKillShip(point, fKey) {
282 | var cP = [[-1, 0], [-1, -1], [0, -1], [1, -1], [1, 0], [1, 1], [0, 1], [-1, 1]],
283 | field = self.fields[fKey],
284 | sPoints = [],
285 | lsCellShip = [];
286 |
287 | if (_checkPointToKill(point)) {
288 | lsCellShip.push(point);
289 | ctnCellShip = lsCellShip;
290 |
291 | return sPoints;
292 | }
293 | else return false;
294 |
295 |
296 | // private method....................
297 | // ..................................
298 |
299 | // убит или нет корабль, если да то заполнет массив соседних точек
300 | function _checkPointToKill(point, noCheck) {
301 | var X = point[0], Y = point[1], // исходная проверяемая точка
302 | nX = false, nY = false; // не проверяемая точка при повторе
303 | var dopCheck = []; // дополнительные точки проверки
304 |
305 | if (typeof noCheck == "object") { // не проверяемая точка, при рекурсии
306 | nX = noCheck[0];
307 | nY = noCheck[1];
308 | }
309 |
310 | for (var i = 0; i < cP.length; i++) { // перебор точек по кругу
311 | var pX = X + cP[i][0],
312 | pY = Y + cP[i][1];
313 |
314 | if (pX === nX && pY === nY) { // эту точку уже проверили
315 | // точка проверенна при предыдущей итерации
316 | } else {
317 | // только если точка в рамках игрового поля
318 | if (pX >= 0 && pX < options.fSize.v && pY >= 0 && pY < options.fSize.h) {
319 | var val = field[pX][pY];
320 |
321 | if (val == options.tPoint.BAR)
322 | return false; // целая часть корабля -> не убит
323 | else if (val == options.tPoint.KIL) { // раненая часть корабля, запомним для рекурсии
324 | lsCellShip.push([pX, pY]); // подсчет палуб
325 | dopCheck.push([[pX, pY], [X, Y]]); // доп.точка првоерки
326 | }
327 | else sPoints.push([pX, pY]); // подбитая часть корабля,
328 | }
329 | }
330 | }
331 |
332 | // доп.точки проверки, если еще есть то запуск рекурсии
333 | if (dopCheck.length === 0)
334 | return true; // точек более нет -> убит
335 | else {
336 | var sRes = 0;
337 | for (var k = 0; k < dopCheck.length; k++) {
338 | if (!_checkPointToKill(dopCheck[k][0], dopCheck[k][1]))
339 | return false;
340 | else sRes++;
341 | }
342 | return sRes == dopCheck.length; // проверенно == доп.точек
343 | }
344 | }
345 | }
346 | };
--------------------------------------------------------------------------------
/src/js/battlefield.class-gameui.js:
--------------------------------------------------------------------------------
1 | /**
2 | * Класс управления пользовательским интерфейсом
3 | *
4 | * Требуется:
5 | * options = {} - глобальный объект с опциями игры
6 | * h = {} - глобальный обьект функций помошников
7 | *
8 | * @param htmlSelector - document.querySelector
9 | * @constructor
10 | */
11 | function GameUI(fields, battlefield) {
12 | if (options.htmlSelector == null)
13 | throw new Error(h.getMessage('err_invalid_selector'));
14 |
15 | this.fields = fields;
16 | this.battlefield = battlefield;
17 |
18 | var self = this;
19 | var playerName =
20 | '' +
21 | ' ' + h.getMessage('new_game') + '' +
22 | ' ' + h.getMessage('options') + '' +
23 | '
';
24 |
25 | // очистка блока
26 | options.htmlSelector.innerHTML = '';
27 |
28 | // имена игроков
29 | if (options.printName) {
30 | var echoTotal = options.winner.kUser + options.winner.kBrain != 0;
31 | playerName +=
32 | '' +
33 | '' + h.getPlayerName(options.player.kUser) + '' +
34 | (echoTotal ? '' + options.winner.kUser + '' : '') +
35 | '&' +
36 | (echoTotal ? '' + options.winner.kBrain + '' : '') +
37 | ' ' + h.getPlayerName(options.player.kBrain) + '' +
38 | '
';
39 | }
40 |
41 | this.nameHtml = document.createElement('div');
42 | this.nameHtml.setAttribute('class', 'bf-player-name');
43 | this.nameHtml.innerHTML = playerName;
44 | options.htmlSelector.appendChild(this.nameHtml);
45 |
46 | // игровые поля
47 | this.fieldHtml = document.createElement('div');
48 | this.fieldHtml.setAttribute('class', 'bf-fields');
49 | this.fieldHtml.innerHTML = this.getFieldHTML(options.player);
50 | options.htmlSelector.appendChild(this.fieldHtml);
51 |
52 | // логирование боя
53 | if (options.printLog) {
54 | var filter =
55 | '' +
56 | ' ' + h.getMessage('filter') + ':' +
57 | ' ' + h.getPlayerName(options.player.kUser) + '' +
58 | ' ' + h.getPlayerName(options.player.kBrain) + '' +
59 | ' ' + h.getMessage('full') + '' +
60 | '
';
61 |
62 | this.logFilter = null;
63 | this.actFilter = '';
64 |
65 | this.logHtml = document.createElement('div');
66 | this.logHtml.setAttribute('class', 'bf-logger');
67 | this.logHtml.innerHTML = '' + h.getMessage('info_log_title') + filter + '
';
68 | options.htmlSelector.appendChild(this.logHtml);
69 | }
70 |
71 |
72 | document.getElementById('new_game').onclick = function () {
73 | self.battlefield.run();
74 | };
75 | document.getElementById('config').onclick = function () {
76 | self.battlefield.updateConfig();
77 | };
78 |
79 | }
80 |
81 | /**
82 | * Вернет HTML разметку игрового поля
83 | *
84 | * @param player - строковый ключ игрока
85 | * @returns {string}
86 | */
87 | GameUI.prototype.getFieldHTML = function (player) {
88 | var fields = this.fields,
89 | html = '';
90 |
91 | for (var k in player) {
92 | var fKey = player[k],
93 | dopAttr = fKey == options.player.kUser ? 'lf' : 'rg',
94 | printShip = dopAttr == 'lf';
95 |
96 | html += '';
97 | html += getFieldTable(fKey, printShip);
98 | html += getBarrierInfo(fKey);
99 | html += '
';
100 | }
101 |
102 | return html;
103 |
104 |
105 | // private method....................
106 | // ..................................
107 |
108 | // вернет HTML игрового поля
109 | function getFieldTable(fKey, printShip) {
110 | printShip = printShip || false;
111 | var table = '';
112 |
113 | table += '';
114 | for (var x = 0; x < options.fSize.v; x++) {
115 | table += '';
116 | for (var y = 0; y < options.fSize.h; y++) {
117 | var mm = '', ll = '';
118 |
119 | // установка маркеров
120 | if (options.fMarker !== false && typeof options.fMarker == 'object') {
121 | var txtMM = typeof options.fMarker.h != 'undefined' ? (options.fMarker.h == 'char' ? h.getLetter(y) : (y + 1)) : (y + 1),
122 | txtLL = typeof options.fMarker.v != 'undefined' ? (options.fMarker.v == 'char' ? h.getLetter(x) : (x + 1)) : (x + 1);
123 |
124 | mm = x === 0 ? '' + txtMM + '
' : '';
125 | ll = y === 0 ? '' + txtLL + '
' : '';
126 | }
127 |
128 | var ship = '';
129 | if (printShip)
130 | ship = fields[fKey][x][y] == options.tPoint.BAR ? ' let' : '';
131 | table += '' + mm + ll + ' | ';
132 | }
133 | table += '
';
134 | }
135 | table += '
';
136 |
137 | return table;
138 | }
139 |
140 | // вернет HTML списка кораблей
141 | function getBarrierInfo(fKey) {
142 | var html = '';
143 |
144 | options.fBarrier.forEach(function (ship) {
145 | var box = '';
146 | for (var c = 0; c < ship[0]; c++)
147 | box += '';
148 | html +=
149 | '' +
150 | ' x' + ship[1] + '' +
151 | ' ' + box +
152 | '
';
153 | });
154 |
155 | return '' + html + '
';
156 | }
157 | };
158 |
159 | /**
160 | * Оповещает пользователя о переходе хода,
161 | * блокирует игровое поле ожидающего
162 | *
163 | * @param fKey строковый ключ игрока
164 | * @returns {*}
165 | */
166 | GameUI.prototype.showProgress = function (fKey) {
167 | // в конце игры, блокируем игровые поля и убираем метку активности с имени
168 | if (!fKey) {
169 | this.fieldHtml.querySelectorAll('table.field').forEach(function (table) {
170 | table.classList.add('timeout');
171 | });
172 |
173 | if (options.printName) {
174 | this.nameHtml.querySelectorAll('.name').forEach(function (span) {
175 | span.classList.remove('act');
176 | });
177 | }
178 | return false;
179 | }
180 |
181 | // делаем игровое поле неактивным
182 | this.fieldHtml.querySelectorAll('table.field.timeout').forEach(function (table) {
183 | table.classList.remove('timeout');
184 | });
185 | this.fieldHtml.querySelector('table.field#' + fKey).classList.add('timeout');
186 |
187 | if (!options.printName)
188 | return null;
189 |
190 | // ставим метку к кому перешел ход
191 | this.nameHtml.querySelectorAll('.name').forEach(function (span) {
192 | span.classList.remove('act');
193 | });
194 | this.nameHtml.querySelector('.name#' + fKey).classList.add('act');
195 | };
196 |
197 | /**
198 | * Вешает событие ожидания клика по игровому полю
199 | *
200 | * @param fKey - строковый ключ игрока
201 | * @param callback - фукция
202 | */
203 | GameUI.prototype.clickToField = function (fKey, callback) {
204 | this.fieldHtml.querySelector('table.field#' + fKey).onclick = callback;
205 | };
206 |
207 | /**
208 | * Печатает маркер на игровом поле
209 | *
210 | * @param point - точка в формате [x, y]
211 | * @param fKey - строковый ключ игрока
212 | * @param tPoint - тип точки
213 | * @param auto - автоматическая точка
214 | * @returns {null}
215 | */
216 | GameUI.prototype.setMarker = function (point, fKey, tPoint, auto) {
217 | var X = point[0],
218 | Y = point[1],
219 | elClass = '';
220 | auto = auto || false;
221 |
222 | switch (tPoint) {
223 | case (options.tPoint.NUL): // мимо
224 | elClass = auto ? 'auto-null' : 'null';
225 | break;
226 | case (options.tPoint.KIL): // ранил
227 | elClass = 'kill';
228 | break;
229 | case (options.tPoint.KIL + '_death'): // убил
230 | elClass = 'kill';
231 | break;
232 | default:
233 | return null;
234 | }
235 |
236 | if (!auto) this.printLog(point, fKey, tPoint);
237 |
238 | var coll = this.fieldHtml.querySelector('table.field#' + fKey)
239 | .rows[X].cells[Y];
240 | coll.querySelector('.box').className += ' ' + elClass;
241 |
242 | if (!auto) {
243 | var shotBox = document.createElement('div');
244 | shotBox.setAttribute('class', 'shot');
245 | coll.appendChild(shotBox);
246 |
247 | h.animateOpacity(shotBox, 2000);
248 | }
249 | };
250 |
251 | /**
252 | * Ставит точки подсказки по углам от подбитого корабля
253 | *
254 | * @param point - точка в формате [x, y]
255 | * @param fKey - строковый ключ игрока
256 | * @param callback - фукция запускается после установки точки
257 | * @returns {boolean}
258 | */
259 | GameUI.prototype.setHelpMarker = function (point, fKey, callback) {
260 | if (!options.printHelp)
261 | return false;
262 |
263 | var sP = [[-1, -1], [1, -1], [1, 1], [-1, 1]],
264 | X = point[0], Y = point[1];
265 |
266 | for (var i = 0; i < sP.length; i++) {
267 | var nX = X + sP[i][0],
268 | nY = Y + sP[i][1];
269 |
270 | if (nX >= 0 && nX < options.fSize.v && nY >= 0 && nY < options.fSize.h) {
271 | this.setMarker([nX, nY], fKey, options.tPoint.NUL, true);
272 | if (typeof callback == 'function')
273 | callback([nX, nY], fKey);
274 | }
275 | }
276 | };
277 |
278 | /**
279 | * Информирует пользователя об оставшихся кораблях на игровом поле
280 | *
281 | * @param ctnCell - массив точек убитого корабля
282 | * @param fKey - строковый ключ игрока
283 | */
284 | GameUI.prototype.shipInfoMap = function (ctnCell, fKey) {
285 | var count = ctnCell.length;
286 |
287 | var letBox = this.fieldHtml
288 | .querySelector('.list-let#' + fKey)
289 | .querySelector('#cell_' + count);
290 |
291 | var span = letBox.querySelector('span'),
292 | dCtn = parseInt(span.getAttribute('data-ctn')) - 1;
293 |
294 | span.setAttribute('data-ctn', dCtn);
295 | span.innerHTML = 'x' + dCtn;
296 |
297 | var shot = document.createElement('div');
298 | shot.setAttribute('class', 'shot');
299 | span.appendChild(shot);
300 |
301 | h.animateOpacity(shot, 3000);
302 |
303 | // если кораблей такова типа больше нет
304 | if (dCtn == 0) {
305 | letBox.querySelectorAll('div').forEach(function (box) {
306 | box.className += ' kill'; // ставим метку убит
307 | });
308 | }
309 |
310 | // если корабль убит, делаем его крассным
311 | var table = this.fieldHtml.querySelector('.field#' + fKey);
312 | ctnCell.forEach(function (ship) {
313 | var X = ship[0],
314 | Y = ship[1];
315 |
316 | table.rows[X].cells[Y]
317 | .querySelector('.box')
318 | .className += ' death';
319 | });
320 | };
321 |
322 | /**
323 | * Ведет журнал боя,
324 | * так же запускает фильтр журнала и подсветку точек на игром поле при наведении на запись
325 | *
326 | * @param point - точка выстрела в формате [x, y]
327 | * @param fKey - строковый ключ игрока
328 | * @param tPoint - тип попадания
329 | * @returns {boolean}
330 | */
331 | GameUI.prototype.printLog = function (point, fKey, tPoint) {
332 | if (!options.printLog)
333 | return false;
334 |
335 | var self = this;
336 |
337 | var html = '',
338 | X = point[0], Y = point[1];
339 |
340 | var tPoint_class = '',
341 | tPoint_name = '';
342 |
343 | var player = fKey == options.player.kUser
344 | ? h.getPlayerName(options.player.kBrain) : h.getPlayerName(options.player.kUser),
345 | __date = new Date(),
346 | time = __date.toLocaleTimeString(),
347 | marker = '';
348 |
349 | switch (tPoint) {
350 | case (options.tPoint.KIL):
351 | tPoint_class = 'war';
352 | tPoint_name = 'log_kill';
353 | break;
354 | case (options.tPoint.KIL + '_death'):
355 | tPoint_class = 'kil';
356 | tPoint_name = 'log_death';
357 | break;
358 | case (options.tPoint.NUL):
359 | tPoint_class = 'nul';
360 | tPoint_name = 'log_past';
361 | break;
362 | }
363 |
364 | marker += options.fMarker.v == 'char' ? h.getLetter(X) : (X + 1);
365 | marker += "x";
366 | marker += options.fMarker.h == 'char' ? h.getLetter(Y) : (Y + 1);
367 |
368 | html +=
369 | '' + marker + '' +
370 | '' + h.getMessage(tPoint_name) + '' +
371 | '' + player + '' +
372 | '' + time + '';
373 |
374 | var li = document.createElement('li');
375 | li.setAttribute('id', fKey);
376 | li.setAttribute('data-x', X);
377 | li.setAttribute('data-y', Y);
378 |
379 | if (this.actFilter == fKey)
380 | li.setAttribute('class', 'no-active');
381 |
382 | li.innerHTML = html;
383 |
384 | this.logHtml.querySelector('ul').insertBefore(li, this.logHtml.querySelector('ul').firstChild);
385 |
386 | // при наведении на лог, подсветка точки игрового поля
387 | li.onmouseover = function (event) {
388 | if (event.target.nodeName != 'LI')
389 | return false;
390 |
391 | var fKey = event.target.getAttribute('id'), // event.target.dataset.fkey,
392 | X = event.target.getAttribute('data-x'), // event.target.dataset.x,
393 | Y = event.target.getAttribute('data-y'); // event.target.dataset.y;
394 |
395 | var td = self.fieldHtml.querySelector('.field#' + fKey).rows[X].cells[Y],
396 | shot = document.createElement('div');
397 |
398 | shot.setAttribute('class', 'shot');
399 | td.appendChild(shot);
400 |
401 | li.onmouseout = function () {
402 | h.animateOpacity(shot, 1000);
403 | };
404 | };
405 |
406 | // фильт журнала
407 | if (this.logFilter == null) {
408 | this.logFilter = this.logHtml.querySelector('.bf-filter');
409 | this.logFilter.classList = 'bf-filter';
410 |
411 | var activeFilter = this.logFilter.querySelector('#full');
412 | this.logFilter.querySelectorAll('span').forEach(function (span) {
413 | span.onclick = function (event) {
414 | if (activeFilter == event.target)
415 | return false;
416 |
417 | if (activeFilter)
418 | activeFilter.classList.remove('active');
419 |
420 | self.actFilter = event.target.getAttribute('id');
421 |
422 | activeFilter = event.target;
423 | activeFilter.classList.add('active');
424 |
425 | self.logHtml.querySelectorAll('li').forEach(function (li) {
426 | li.classList = self.actFilter == li.getAttribute('id') ? 'no-active' : '';
427 | });
428 | }
429 | })
430 | }
431 | };
432 |
433 | /**
434 | * Показывает корабли на игровом поле
435 | *
436 | * @param fKey - строковый ключ игрока
437 | */
438 | GameUI.prototype.showShip = function (fKey) {
439 | var field = this.fields[fKey],
440 | table = this.fieldHtml.querySelector('table#' + fKey);
441 |
442 | for (var X = 0; X < field.length; X++) {
443 | for (var Y = 0; Y < field[X].length; Y++)
444 | if (field[X][Y] == options.tPoint.BAR) {
445 | table
446 | .rows[X].cells[Y]
447 | .querySelector('.box')
448 | .className += ' let';
449 | }
450 | }
451 | };
452 |
453 | /**
454 | * Оповещает пользователя об окончании игры,
455 | * выводит модальное окно
456 | *
457 | * @param winner - строковый ключ игрока, победителя
458 | */
459 | GameUI.prototype.gameOver = function (winner) {
460 | var self = this,
461 | kWinner = options.player.kUser == winner ? 'kUser' : 'kBrain';
462 | var title = '',
463 | elClass = '',
464 | message = '';
465 |
466 | // счетчик побед...
467 | options.winner[kWinner]++;
468 |
469 | if (options.player.kUser == winner) {
470 | elClass = 'winner';
471 | title = h.getMessage('you_winner');
472 | message = h.getMessage('info_winner');
473 | } else {
474 | this.showShip(winner);
475 |
476 | elClass = 'lose';
477 | title = h.getMessage('you_lose');
478 | message = h.getMessage('info_loser');
479 | }
480 |
481 | var contentHtml =
482 | '' +
483 | '' +
484 | '
' + title + '
' +
485 | ' ' + message + '
' +
486 | '';
487 |
488 | // выводит модальное окно с опциями
489 | h.modalWindow(h.getMessage('game_over'), contentHtml, [{
490 | elValue: h.getMessage('new_game'),
491 | onClick: function (modal) {
492 | modal.close();
493 | self.battlefield.run();
494 | }
495 | }, {
496 | elValue: h.getMessage('update_options'),
497 | elClass: 'btn-warning',
498 | onClick: function (modal) {
499 | modal.close();
500 | self.showProgress(false);
501 | self.battlefield.updateConfig();
502 | }
503 | }, {
504 | elValue: h.getMessage('close'),
505 | elClass: 'btn-danger',
506 | onClick: function (modal) {
507 | modal.close();
508 | self.showProgress(false);
509 | }
510 | }]);
511 | };
--------------------------------------------------------------------------------
/dist/battlefield.min.js:
--------------------------------------------------------------------------------
1 | /**
2 | * battlefield-js v1.0.1
3 | * This is classic game Battlefield for browsers, implemented on language JavaScript.
4 | *
5 | * repository: git+https://github.com/alx2das/battlefield-js.git
6 | * bugs: git+https://github.com/alx2das/battlefield-js.git
7 | * homepage: https://alx2das.github.io/battlefield-js/examples/
8 | *
9 | * Copyright 2017, Alexandr Builov
10 | * Date: Sun Feb 05 2017
11 | */
12 | !function(e){"use strict";function t(e,r){if(o instanceof t)return o;if(o=this,"object"==typeof r){for(var i in l)n[i]=r.hasOwnProperty(i)?r[i]:l[i];n=Object.assign(n,s)}else n=Object.assign(l,s);n.htmlSelector=document.querySelector(e)}function r(){if(n.fSize.h<10||n.fSize.h>25||n.fSize.v<10||n.fSize.v>25)throw new RangeError(f.getMessage("err_size_field"));if(!(n.fBarrier instanceof Array)||n.fBarrier.length<1)throw new RangeError(f.getMessage("err_barrier"));this.fields=[],this.fName=[n.player.kUser,n.player.kBrain];for(var e in n.player){for(var t=n.player[e],r=new Array(n.fSize.v),i=0;i '+f.getMessage("new_game")+' '+f.getMessage("options")+"";if(n.htmlSelector.innerHTML="",n.printName){var a=n.winner.kUser+n.winner.kBrain!=0;i+=''+f.getPlayerName(n.player.kUser)+""+(a?''+n.winner.kUser+"":"")+"&"+(a?''+n.winner.kBrain+"":"")+' '+f.getPlayerName(n.player.kBrain)+"
"}if(this.nameHtml=document.createElement("div"),this.nameHtml.setAttribute("class","bf-player-name"),this.nameHtml.innerHTML=i,n.htmlSelector.appendChild(this.nameHtml),this.fieldHtml=document.createElement("div"),this.fieldHtml.setAttribute("class","bf-fields"),this.fieldHtml.innerHTML=this.getFieldHTML(n.player),n.htmlSelector.appendChild(this.fieldHtml),n.printLog){var l=' '+f.getMessage("filter")+': '+f.getPlayerName(n.player.kUser)+' '+f.getPlayerName(n.player.kBrain)+' '+f.getMessage("full")+"
";this.logFilter=null,this.actFilter="",this.logHtml=document.createElement("div"),this.logHtml.setAttribute("class","bf-logger"),this.logHtml.innerHTML=""+f.getMessage("info_log_title")+l+"
",n.htmlSelector.appendChild(this.logHtml)}document.getElementById("new_game").onclick=function(){r.battlefield.run()},document.getElementById("config").onclick=function(){r.battlefield.updateConfig()}}var n={},l={printName:!0,printLog:!0,printHelp:!0,fSize:{h:15,v:15},fBarrier:[[5,2],[4,3],[3,4],[2,5],[1,6]],fMarker:{h:"number",v:"char"}},s={player:{kUser:"FUser",kBrain:"FBrain"},winner:{kUser:0,kBrain:0},tPoint:{DEF:0,BAR:1,KIL:2,NUL:3}},o=!1,c="middle";t.prototype.run=function(){try{var e=new r,t=e.setBarrier();new i(t,this)}catch(e){f.showExceptions(e)}},t.prototype.getLevel=function(e){var t={easy:{fSize:{h:10,v:10},fBarrier:[[4,1],[3,2],[2,3],[1,4]]},middle:{fSize:{h:15,v:15},fBarrier:[[5,2],[4,3],[3,4],[2,5],[1,6]]},hard:{fSize:{h:15,v:20},fBarrier:[[6,1],[5,2],[4,3],[3,4],[2,5],[1,6]]}};if("object"==typeof t[e])return t[e];throw new Error(f.getMessage("err_invalid_level"))},t.prototype.setLevel=function(e){var t=this.getLevel(e);return n.fSize=t.fSize,n.fBarrier=t.fBarrier,c=e,this},t.prototype.updateConfig=function(){function e(e){s.querySelector("#opt-fsize").querySelectorAll("label").forEach(function(t){var r=t.querySelector("input");e?(t.classList="",r.disabled=!1):(t.classList="no-act",r.disabled=!0)}),s.querySelector("#opt-fbarrier").querySelectorAll("label").forEach(function(t){var r=t.querySelector("input");e?(t.classList="",r.disabled=!1):(t.classList="no-act",r.disabled=!0)})}function t(){var e={fSize:{h:0,v:0},fBarrier:[]};return e.fSize.h=parseInt(s.querySelector("input#type-h").value),e.fSize.v=parseInt(s.querySelector("input#type-v").value),s.querySelector("#opt-fbarrier").querySelectorAll("label").forEach(function(t){var r=t.querySelector("input"),i=parseInt(r.getAttribute("bar")),a=parseInt(r.value);a>0&&e.fBarrier.push([i,a])}),e}function r(e){s.querySelector("input#type-h").value=e.fSize.h,s.querySelector("input#type-v").value=e.fSize.v,s.querySelector("#opt-fbarrier").querySelectorAll("input").forEach(function(e){e.value=0}),e.fBarrier.forEach(function(e){var t=e[0],r=e[1];s.querySelector("#opt-fbarrier").querySelector("input#bar_"+t).value=r})}var i=this,a='';a="";var l=c;f.modalWindow(f.getMessage("options"),a,[{elValue:f.getMessage("new_game"),onClick:function(e){e.close();try{if("user"==l){var r=t();n.fSize=r.fSize,n.fBarrier=r.fBarrier,c=l}else l.length>0&&l!=c&&i.setLevel(l);i.run()}catch(e){f.showExceptions(e)}}},{elValue:f.getMessage("set_default_params"),elClass:"btn-warning",onClick:function(e){e.close(),i.setLevel("middle"),i.run()}},{elValue:f.getMessage("close"),elClass:"btn-danger",onClick:function(e){e.close()}}]);var s=document.querySelector(".bf-config"),o=document.getElementById("config_level").querySelectorAll("button");e("user"==c),r(n),o.forEach(function(t){t.onclick=function(t){return l=t.target.value,o.forEach(function(e){e.classList.remove("active")}),t.target.classList+=" active","user"==l?e(!0):(e(!1),r(i.getLevel(l))),!1}})},r.prototype.setBarrier=function(){function e(r,a){if(!(i>0))throw new RangeError(f.getMessage("err_max_iteration"));i--;for(var l=[],s=f.rand(0,n.fSize.v-1),o=f.rand(0,n.fSize.h-1),c=f.rand(1,2)%2,u=0;us||t<0||t>o)return!1;if(r[e][t]!==n.tPoint.DEF)return!1;for(var c=0;c=0&&a<=s&&l>=0&&l<=o&&r[a][l]!=n.tPoint.DEF)return!1;return!0}var r=this,i=100*this.fName.length;return this.fName.forEach(function(t){var i=r.fields[t];n.fBarrier.forEach(function(t){for(var r=t[0],a=t[1],n=0;n0)l=r();else{var o=f.rand(0,i._lsShot[e].length-1);l=i._lsShot[e][o],i._lsShot[e].splice(o,1)}if(l instanceof Array&&"undefined"!==l[0]&&"undefined"!==l[1]){var c=l[0],u=l[1];if(c>=0&&c=0&&u=0&&h=0&&pc?c:m,y=y=0&&p=0&&v';for(var a=0;a";for(var l=0;l'+c+"":"",o=0===l?''+u+"
":""}var d="";t&&(d=i[e][a][l]==n.tPoint.BAR?" let":""),r+=""+s+o+' | '}r+=""}return r+=""}function r(e){var t="";return n.fBarrier.forEach(function(e){for(var r="",i=0;i';t+=' x'+e[1]+" "+r+"
"}),''+t+"
"}var i=this.fields,a="";for(var l in e){var s=e[l],o=s==n.player.kUser?"lf":"rg",c="lf"==o;a+='',a+=t(s,c),a+=r(s),a+="
"}return a},a.prototype.showProgress=function(e){return e?(this.fieldHtml.querySelectorAll("table.field.timeout").forEach(function(e){e.classList.remove("timeout")}),this.fieldHtml.querySelector("table.field#"+e).classList.add("timeout"),n.printName?(this.nameHtml.querySelectorAll(".name").forEach(function(e){e.classList.remove("act")}),void this.nameHtml.querySelector(".name#"+e).classList.add("act")):null):(this.fieldHtml.querySelectorAll("table.field").forEach(function(e){e.classList.add("timeout")}),n.printName&&this.nameHtml.querySelectorAll(".name").forEach(function(e){e.classList.remove("act")}),!1)},a.prototype.clickToField=function(e,t){this.fieldHtml.querySelector("table.field#"+e).onclick=t},a.prototype.setMarker=function(e,t,r,i){var a=e[0],l=e[1],s="";switch(i=i||!1,r){case n.tPoint.NUL:s=i?"auto-null":"null";break;case n.tPoint.KIL:s="kill";break;case n.tPoint.KIL+"_death":s="kill";break;default:return null}i||this.printLog(e,t,r);var o=this.fieldHtml.querySelector("table.field#"+t).rows[a].cells[l];if(o.querySelector(".box").className+=" "+s,!i){var c=document.createElement("div");c.setAttribute("class","shot"),o.appendChild(c),f.animateOpacity(c,2e3)}},a.prototype.setHelpMarker=function(e,t,r){if(!n.printHelp)return!1;for(var i=[[-1,-1],[1,-1],[1,1],[-1,1]],a=e[0],l=e[1],s=0;s=0&&o=0&&c'+p+''+f.getMessage(c)+''+u+''+h+"";var v=document.createElement("li");if(v.setAttribute("id",t),v.setAttribute("data-x",l),v.setAttribute("data-y",s),this.actFilter==t&&v.setAttribute("class","no-active"),v.innerHTML=a,this.logHtml.querySelector("ul").insertBefore(v,this.logHtml.querySelector("ul").firstChild),v.onmouseover=function(e){if("LI"!=e.target.nodeName)return!1;var t=e.target.getAttribute("id"),r=e.target.getAttribute("data-x"),a=e.target.getAttribute("data-y"),n=i.fieldHtml.querySelector(".field#"+t).rows[r].cells[a],l=document.createElement("div");l.setAttribute("class","shot"),n.appendChild(l),v.onmouseout=function(){f.animateOpacity(l,1e3)}},null==this.logFilter){this.logFilter=this.logHtml.querySelector(".bf-filter"),this.logFilter.classList="bf-filter";var m=this.logFilter.querySelector("#full");this.logFilter.querySelectorAll("span").forEach(function(e){e.onclick=function(e){return m!=e.target&&(m&&m.classList.remove("active"),i.actFilter=e.target.getAttribute("id"),m=e.target,m.classList.add("active"),void i.logHtml.querySelectorAll("li").forEach(function(e){e.classList=i.actFilter==e.getAttribute("id")?"no-active":""}))}})}},a.prototype.showShip=function(e){for(var t=this.fields[e],r=this.fieldHtml.querySelector("table#"+e),i=0;i
'+i+"
"+l+"
";f.modalWindow(f.getMessage("game_over"),s,[{elValue:f.getMessage("new_game"),onClick:function(e){e.close(),t.battlefield.run()}},{elValue:f.getMessage("update_options"),elClass:"btn-warning",onClick:function(e){e.close(),t.showProgress(!1),t.battlefield.updateConfig()}},{elValue:f.getMessage("close"),elClass:"btn-danger",onClick:function(e){e.close(),t.showProgress(!1)}}])};var f={playerName:{def:{kUser:"Игрок",kBrain:"Компьютер"}},rand:function(e,t){return e=e||0,t=t||100,parseInt(Math.random()*(t-e+1)+e)},getLetter:function(e,t){var t=t||"",r="ABCDEFGHIJKLMNOPQRSTUVWXYZ";return e>r.length?this.getLetter(e-r.length,""==t?1:t+1):r[e]+t},shuffle:function(e){for(var t,r,i=0;iпопробуешь еще?",info_loser:"В следующий раз повезет больше,
попробуешь еще?"};return"string"==typeof t[e]&&t[e].length>0?t[e]:e},getPlayerName:function(e){var t=e==n.player.kUser?"kUser":"kBrain";return this.playerName.def[t]},showExceptions:function(e){var r="",i="",a=[];switch(e.name){case"Error":r=f.getMessage("info_title_error"),i=e.message,a=[{elValue:f.getMessage("set_default_params"),onClick:function(e){e.close();var r=new t(n.htmlSelector,n);r.setLevel("middle").run()}}];break;case"RangeError":r=f.getMessage("info_title_range_error"),i=e.message,a=[{elValue:f.getMessage("update_options"),onClick:function(e){e.close();var r=new t(n.htmlSelector,n);r.updateConfig()}},{elValue:f.getMessage("set_default_params"),elClass:"btn-warning",onClick:function(e){e.close();var r=new t(n.htmlSelector,n);r.setLevel("middle").run()}}];break;default:r=e.name,i=e.message}this.modalWindow(r,i,a)},modalWindow:function(e,t,r){function i(e,t){return function(r){"function"==typeof t[e].onClick&&t[e].onClick(a,r)}}var a={font:!1,window:!1,construct:function(){if(this.createHTML().autoPosition(),!(r instanceof Array)||0==r.length)return this.window.querySelector(".footer").style.display="none",!1;for(var e=this.window.querySelector(".footer"),t=[],a=0;a '+t+'
',document.body.appendChild(this.font),document.body.appendChild(this.window),this},autoPosition:function(){var e=this.window.clientWidth/2,t=this.window.clientHeight/2;this.window.style.marginTop=t*-1+"px",this.window.style.marginLeft=e*-1+"px"},close:function(){document.body.removeChild(this.font),document.body.removeChild(this.window)}};a.construct()},animateOpacity:function(e,t){e.style.opacity=1;var r=setInterval(function(){if(e.style.opacity=e.style.opacity-100/(t/.1),e.style.opacity<=0){clearInterval(r);try{e.parentNode.removeChild(e)}catch(e){}}},1)}};e.Battlefield=t}(window),function(e,t,r){(t[r]=t[r]||[]).push(function(){try{t.yaCounter42568409=new Ya.Metrika({id:42568409,clickmap:!0,trackLinks:!0,accurateTrackBounce:!0})}catch(e){}});var i=e.getElementsByTagName("script")[0],a=e.createElement("script"),n=function(){i.parentNode.insertBefore(a,i)};a.type="text/javascript",a.async=!0,a.src="https://mc.yandex.ru/metrika/watch.js","[object Opera]"==t.opera?e.addEventListener("DOMContentLoaded",n,!1):n()}(document,window,"yandex_metrika_callbacks");
--------------------------------------------------------------------------------
/src/css/battlefield.helper.css:
--------------------------------------------------------------------------------
1 | .bf-go-smile {
2 | float: left;
3 | width: 100px;
4 | height: 100px;
5 | margin-left: 90px;
6 | }
7 |
8 | .bf-go-smile.winner {
9 | background-image: url(data:image/png;base64,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);
10 | }
11 |
12 | .bf-go-smile.lose {
13 | background-image: url(data:image/png;base64,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);
14 | }
15 |
16 | .bf-go-text {
17 | float: left;
18 | margin: 0 0 0 35px;
19 | padding: 15px 0;
20 | }
21 |
22 | .bf-go-text h2 {
23 | margin-bottom: 10px
24 | }
25 |
26 | table.bf-config {
27 | width: 100%;
28 | border-collapse: collapse;
29 | }
30 |
31 | table.bf-config td {
32 | padding: 10px 0
33 | }
34 |
35 | table.bf-config td.name {
36 | width: 28%;
37 | font-size: 13px;
38 | font-weight: 700;
39 | vertical-align: top
40 | }
41 |
42 | table.bf-config td.name.top {
43 | padding: 15px 0
44 | }
45 |
46 | table.bf-config td.options {
47 | width: 73%
48 | }
49 |
50 | table.bf-config td .border {
51 | border-top: 1px solid rgba(34, 36, 38, .15)
52 | }
53 |
54 | table.bf-config td.options .btn {
55 | padding: 4px 14px;
56 | border-radius: 20px;
57 | background: #fff;
58 | border: 1px solid rgba(34, 36, 38, .15);
59 | color: rgba(0, 0, 0, .8);
60 | }
61 |
62 | table.bf-config td.options .btn:hover {
63 | background-color: #F9FAFB;
64 | }
65 |
66 | table.bf-config td.options .btn.active {
67 | background-color: #e7ff7f !important;
68 | }
69 |
70 | table.bf-config td.options .btn.rg {
71 | float: right;
72 | margin: 0;
73 | color: #794B02;
74 | background-color: #ffeacc;
75 | }
76 |
77 | table.bf-config td.options label {
78 | display: inline-block;
79 | margin: 2px 25px 2px 0;
80 | cursor: pointer
81 | }
82 |
83 | table.bf-config td.options label input[type=number] {
84 | color: rgba(0, 0, 0, .8);
85 | width: 45px;
86 | font-size: 13px;
87 | border: 1px solid rgba(34, 36, 38, .15);
88 | margin: -3px 0 0 0;
89 | padding: 3px 4px;
90 | border-radius: 3px;
91 | background-color: rgba(255, 249, 0, 0.25);
92 | }
93 |
94 | table.bf-config td.options label.no-act input[type=number] {
95 | border-color: #fff;
96 | background: none
97 | }
98 |
99 | table.bf-config td.options input[type=checkbox], table.bf-config td.options input[type=radio] {
100 | float: left;
101 | margin-top: 2px;
102 | width: auto;
103 | margin-right: 5px;
104 | }
105 |
106 | table.bf-config td.options.no-label label {
107 | cursor: default !important;
108 | }
109 |
110 | table.bf-config td.options div {
111 | padding-bottom: 4px
112 | }
113 |
114 | table.bf-config td.options div.top {
115 | padding-top: 10px
116 | }
--------------------------------------------------------------------------------
/dist/battlefield.min.css:
--------------------------------------------------------------------------------
1 | /**
2 | * battlefield-js v1.0.1
3 | * This is classic game Battlefield for browsers, implemented on language JavaScript.
4 | *
5 | * repository: git+https://github.com/alx2das/battlefield-js.git
6 | * bugs: git+https://github.com/alx2das/battlefield-js.git
7 | * homepage: https://alx2das.github.io/battlefield-js/examples/
8 | *
9 | * Copyright 2017, Alexandr Builov
10 | * Date: Sun Feb 05 2017
11 | */
12 | .container,body,html{min-height:100%}.bf-fields{background-color:#7a8b9f}.bf-fields .board{width:50%}.bf-fields .board.lf{float:left}.bf-fields .board.rg{float:right}.bf-fields table.field{border-collapse:collapse;margin:25px}.bf-fields table.field td,.bf-fields table.field td .box{border:2px solid #E5EAFF}.bf-fields table.field td .box,.bf-fields table.field td .ll,.bf-fields table.field td .mm{width:28px;height:28px;line-height:28px;text-align:center}.bf-fields table.field td .ll,.bf-fields table.field td .mm{position:absolute;z-index:1;font-family:Georgia;color:#afafaf;font-weight:700;font-size:12px}.bf-fields table.field td .ll{left:-28px}.bf-fields table.field td .mm{top:-28px}.bf-fields table.field td{position:relative}.bf-fields table.field td .box{float:left;margin:-2px}.bf-fields .list-let .box.kill,.bf-fields table.field td .box.auto-null,.bf-fields table.field td .box.kill,.bf-fields table.field td .box.null{background:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAADgAAAAcCAYAAAA0u3w+AAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAyFpVFh0WE1MOmNvbS5hZG9iZS54bXAAAAAAADw/eHBhY2tldCBiZWdpbj0i77u/IiBpZD0iVzVNME1wQ2VoaUh6cmVTek5UY3prYzlkIj8+IDx4OnhtcG1ldGEgeG1sbnM6eD0iYWRvYmU6bnM6bWV0YS8iIHg6eG1wdGs9IkFkb2JlIFhNUCBDb3JlIDUuNS1jMDIxIDc5LjE1NDkxMSwgMjAxMy8xMC8yOS0xMTo0NzoxNiAgICAgICAgIj4gPHJkZjpSREYgeG1sbnM6cmRmPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5LzAyLzIyLXJkZi1zeW50YXgtbnMjIj4gPHJkZjpEZXNjcmlwdGlvbiByZGY6YWJvdXQ9IiIgeG1sbnM6eG1wPSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvIiB4bWxuczp4bXBNTT0iaHR0cDovL25zLmFkb2JlLmNvbS94YXAvMS4wL21tLyIgeG1sbnM6c3RSZWY9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC9zVHlwZS9SZXNvdXJjZVJlZiMiIHhtcDpDcmVhdG9yVG9vbD0iQWRvYmUgUGhvdG9zaG9wIENDIChXaW5kb3dzKSIgeG1wTU06SW5zdGFuY2VJRD0ieG1wLmlpZDpDRjMwN0VCOEM4NDcxMUU1OTM5M0RBNkE1MDVDQUVEMSIgeG1wTU06RG9jdW1lbnRJRD0ieG1wLmRpZDpDRjMwN0VCOUM4NDcxMUU1OTM5M0RBNkE1MDVDQUVEMSI+IDx4bXBNTTpEZXJpdmVkRnJvbSBzdFJlZjppbnN0YW5jZUlEPSJ4bXAuaWlkOkNGMUMzMzI1Qzg0NzExRTU5MzkzREE2QTUwNUNBRUQxIiBzdFJlZjpkb2N1bWVudElEPSJ4bXAuZGlkOkNGMUMzMzI2Qzg0NzExRTU5MzkzREE2QTUwNUNBRUQxIi8+IDwvcmRmOkRlc2NyaXB0aW9uPiA8L3JkZjpSREY+IDwveDp4bXBtZXRhPiA8P3hwYWNrZXQgZW5kPSJyIj8+aamjFgAAAmdJREFUeNrs2E1IFGEcx/FdldlVWosiyg7WKQo6LNFFykgoL4GKEER16OUQ5kW6RZ3yUKcugVJLJEKIHSSiRKUoO0UvaChSInSIXpBa1y13Y3fW6fvIXxi2nX1zwJ1lHviwLzPzzPyet9lZr2EYnnIuFZ4yL25AN2Cxxeu10oKNWbZn5qAe/Ixh1ObYr8apQ3QKAQkZsNhnK1qdPAcHcVBCbkjrMfU6hJdODjgAdYM+JCG3oBeVsu0bvudTUVUhZz3cdHT17THsxhtMI/7qxTO7wql6w3iNBjRiTi1LuI0WNOVbWVWBJ1cteAPNSOEi7qMPCwXWFcRxLEqYD0hiGRPYbtp3k7x2YCbf4VlMwHbVkSdPtCd9Pl8wkUhMj449Px+ORL7y/cMC65qUBeW0zLk6CabC3sU1i+N6TQvNDmmUGbvmoFrVlgm3XzWOpmlBf031XzlJMUWNgn7sQRfqcRnXoVkccwV/cE8a5aOdi8y4ajld12dXri6VmossRDbLpF9LSUqv7ZUezFZUr92UuTgiQ9q2gEu482R41PPu/cT4o8dPPbF4PMR3v2xYXNScDMk8z1W6ZXXdafcc/IEHi9HoLHS1euKLrHJrLZNy4YN5/BA4g21yr/wpDZ+5qOfBdSE3OpMLWDLUJeXW/9/xFucphYC1GEgLEEU4Q7C3pvddTgh4AJ8whZD04j5UoE+CxHAVOjR04jeSOFLKAf1oRCDDcFV6JOA5+dxh2rYLI5hHfbaA3nX7TybLM5yUW/DjklUNOItTK08WhhEr9UUmXasMyVz71aGt9HrQ/U/GDegGdAOWQ/knwAALfSfZ0tNOqgAAAABJRU5ErkJggg==) no-repeat}.bf-fields table.field td .box.let{background-color:#E5EAFF}.bf-fields table.field td .box.null{opacity:1!important}.bf-fields table.field td .box.auto-null{opacity:.5}.bf-fields table.field td .box.kill{background-position:-28px 0;background-color:#a1b9d6}.bf-fields table.field td .box.death{background-color:#deabab}.bf-fields .shot{position:absolute;z-index:1;width:28px;height:28px;margin:-2px;background-color:rgba(255,249,0,.7);border:2px solid #fff900}.bf-fields .list-let{margin:25px 15px 0;float:left}.bf-fields .list-let .let{margin-bottom:10px}.bf-fields .list-let .let:after{content:" ";display:block;clear:both}.bf-fields .list-let span{width:26px;height:26px;line-height:26px;margin:0 10px;text-align:center;color:#afafaf;font-weight:700;display:inline-block;background:0 0;border:none}.bf-fields:after,.bf-logger:after,.bf-player-name:after,.ctn-footer:after,.ctn-header:after{display:block;content:" ";clear:both}.bf-fields .list-let span .shot{width:24px;height:24px;margin:-27px 0 0}.bf-fields .list-let .box{float:left;width:24px;height:24px;margin-left:-2px;background-color:rgba(165,188,208,.5)!important;border:2px solid #E5EAFF}.ctn-footer .file a:hover,.ctn-header{border-bottom:1px solid #7a8b9f}.bf-fields .list-let .box.kill{background-position:-28px 0}.bf-fields .board.rg table.field td .box{cursor:pointer}.bf-fields .board.rg table.field td .box:hover{box-shadow:inset 0 0 5px 2px #ff8d8d}.bf-fields .board.rg table.field td .box.auto-null:hover,.bf-fields .board.rg table.field td .box.kill:hover,.bf-fields .board.rg table.field td .box.let:hover,.bf-fields .board.rg table.field td .box.null:hover{box-shadow:none!important;cursor:default!important}.bf-fields .board table.field.timeout{opacity:.7;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none}.bf-fields .board table.field.timeout .box{cursor:wait!important}.bf-fields .board.lf .list-let,.bf-fields .board.lf .list-let .box,.bf-fields .board.lf table.field,.bf-fields .board.rg .list-let span{float:right}.bf-fields .board.lf .list-let span,.bf-fields .board.rg .list-let,.bf-fields .board.rg .list-let .box,.bf-fields .board.rg table.field{float:left}*{margin:0;padding:0}body,html{height:100%;font-family:Arial,sans-serif}.wrap{width:950px;margin:0 auto}.container .clear-footer{height:46px}.ctn-header{padding:20px 0}.ctn-header .logotype{float:left;color:#7a8b9f;font-weight:700;font-size:26px;text-decoration:none}.ctn-header .logotype small{font-weight:400;font-size:12px;color:#b5b5b5}.ctn-header .soc-btn{float:right;padding:3px 0}.btn,.ctn-footer .copy{float:left}.ctn-footer{padding:15px 0;margin-top:-46px;border-top:1px solid #7a8b9f;font-size:13px;color:#b5b5b5}.ctn-footer .file{float:left;margin-left:25px}.ctn-footer .file a{color:#7a8b9f;text-decoration:none}.bf-fields,.bf-logger,.bf-modal-window,.bf-player-name,.btn{font-family:Arial,sans-serif;color:#7a8b9f;font-size:13px}.bf-fields,.bf-logger,.bf-player-name{padding:25px 0}.btn{margin-right:10px;outline:0;margin-bottom:0;font-weight:400;text-align:center;vertical-align:middle;cursor:pointer;border:1px solid transparent;white-space:nowrap;padding:7px 14px;font-size:13px;line-height:1.2;border-radius:3px;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;background-color:#5cb85c;color:#fff}.btn:active,.btn:hover{background-color:#449d44}.btn.btn-warning{background-color:#f0ad4e}.btn.btn-warning:active,.btn.btn-warning:hover{background-color:#ec971f}.btn.btn-danger{background-color:#d9534f;float:right;margin-right:0}.btn.btn-danger:active,.btn.btn-danger:hover{background-color:#c9302c}.btn.btn-danger:active{background-image:none}span.js{margin-left:15px;cursor:pointer;color:#7a8b9f;border-bottom:1px dashed #7a8b9f}span.js:hover{border-bottom:none}.bf-go-smile{float:left;width:100px;height:100px;margin-left:90px}.bf-go-smile.winner{background-image:url(data:image/png;base64,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)}.bf-go-smile.lose{background-image:url(data:image/png;base64,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)}.bf-go-text{float:left;margin:0 0 0 35px;padding:15px 0}.bf-go-text h2{margin-bottom:10px}table.bf-config{width:100%;border-collapse:collapse}table.bf-config td{padding:10px 0}table.bf-config td.name{width:28%;font-size:13px;font-weight:700;vertical-align:top}table.bf-config td.name.top{padding:15px 0}table.bf-config td.options{width:73%}table.bf-config td .border{border-top:1px solid rgba(34,36,38,.15)}table.bf-config td.options .btn{padding:4px 14px;border-radius:20px;background:#fff;border:1px solid rgba(34,36,38,.15);color:rgba(0,0,0,.8)}table.bf-config td.options .btn:hover{background-color:#F9FAFB}table.bf-config td.options .btn.active{background-color:#e7ff7f!important}table.bf-config td.options .btn.rg{float:right;margin:0;color:#794B02;background-color:#ffeacc}table.bf-config td.options label{display:inline-block;margin:2px 25px 2px 0;cursor:pointer}table.bf-config td.options label input[type=number]{color:rgba(0,0,0,.8);width:45px;font-size:13px;border:1px solid rgba(34,36,38,.15);margin:-3px 0 0;padding:3px 4px;border-radius:3px;background-color:rgba(255,249,0,.25)}table.bf-config td.options label.no-act input[type=number]{border-color:#fff;background:0 0}table.bf-config td.options input[type=checkbox],table.bf-config td.options input[type=radio]{float:left;margin-top:2px;width:auto;margin-right:5px}table.bf-config td.options.no-label label{cursor:default!important}table.bf-config td.options div{padding-bottom:4px}table.bf-config td.options div.top{padding-top:10px}.bf-logger{max-width:950px;margin:0 auto}.bf-logger h2{padding-bottom:15px}.bf-logger ul{list-style:none;max-height:300px;overflow-y:auto;margin-bottom:25px}.bf-logger ul li{display:block;padding:7px 0;border-bottom:1px solid #d6d6d6}.bf-logger ul li.no-active{display:none}.bf-logger ul li:hover{background-color:#f6f6f6}.game-log ul li:last-child{border-bottom:none}.bf-logger ul li .point,.bf-logger ul li .time,.bf-logger ul li .type{width:60px;display:inline-block}.bf-logger ul li .point,.bf-logger ul li .time{font-weight:700}.bf-logger ul li .type{margin:0 10px;font-size:12px;padding:2px 0;text-align:center;border-radius:2px;font-weight:700}.bf-logger ul li .type.kil{background-color:#d9534f;color:#fff}.bf-logger ul li .type.war{background-color:#f0ad4e;color:#fff}.bf-logger ul li .name{font-size:14px}.bf-logger ul li .time{float:right}.bf-logger .bf-filter{float:right;font-weight:400;font-size:13px}.bf-logger .bf-filter.no-active{display:none}.bf-logger .bf-filter span.active{border-bottom:1px solid}.bf-modal-font{position:fixed;z-index:9;top:0;left:0;width:100%;height:100%;background:rgba(122,139,159,.8)}.bf-modal-window{position:fixed;z-index:19;top:50%;left:50%;width:600px;background:#fff;border-radius:4px}.bf-modal-window .content{padding:25px 15px 15px}.bf-modal-window .content span{float:right;font-size:12px;font-weight:400;padding:2px 0;color:#7A8BB4;font-style:italic}.bf-modal-window .header{font-weight:700;font-size:16px;padding-bottom:16px;border-bottom:2px solid rgba(122,139,159,.3)}.bf-modal-window .cont{padding:30px 0}.bf-modal-window .footer{padding-top:15px;border-top:2px solid rgba(122,139,159,.3)}.bf-modal-window .cont:after,.bf-modal-window .footer:after,.bf-modal-window .header:after{content:" ";clear:both;display:block}.bf-player-name{text-align:center;width:950px;margin:0 auto}.bf-player-name span{display:inline-block;padding:0 10px;font-size:15px;height:24px;line-height:24px}.bf-player-name .name{width:120px;background:#7a8b9f;color:#fff;margin:0 10px 0 6px;padding:4px 10px;border-radius:3px;height:auto;line-height:1.1}.bf-player-name .name.act{background:#f0ad4e}.bf-player-name .total{min-width:30px;text-align:center;color:#7a8b9f;font-weight:700}.bf-player-name .opt{float:left}.bf-player-name .left{float:left;margin-top:-5px}.bf-player-name .center{width:460px;margin:0 auto}.bf-player-name .center:after{content:" ";clear:both;display:block}.bf-player-name .right{float:right}.bf-player-name .left a{color:#7a8b9f;font-weight:700;font-size:26px;text-decoration:none}.bf-player-name .right span{padding:0}
--------------------------------------------------------------------------------