<html>
<head>
<meta charset="utf-8">
<title>JS Bin</title>
</head>
<body>
<script src="http://cdnjs.cloudflare.com/ajax/libs/lodash.js/0.9.2/lodash.js"></script>
<script type="text/template" id="template-for-lose">
<div id="cover"></div>
<div id="window-lose">
<p>Вы проиграли!</p>
<button id="btn">Новая игра</button>
</div>
</script>
<script type="text/template" id="template-for-win">
<div id="cover"></div>
<div id="window-win">
<p>Вы победили!</p>
<button id="btn">Новая игра</button>
</div>
</script>
</body>
</html>
body {
text-align: center;
}
td {
width: 28px;
height: 28px;
background: #08a3db;
border: 1px solid #2352ce;
cursor: pointer;
text-align: center;
border-radius: 1px;
color: black;
font-family: 'Arial', sans-serif;
font-weight: bold;
}
table {
border-collapse: collapse;
margin: 0 auto;
}
#cover {
position: fixed;
width: 100%;
height: 100%;
background: gray;
opacity: 0.3;
z-index: 9000;
}
#window-lose {
display: inline-block;
position: absolute;
width: 60%;
height: 100px;
vertical-align: middle;
text-align: center;
background: #FF3300;
border: 2px solid #FF1100;
z-index: 9999;
}
#window-win {
display: inline-block;
position: absolute;
width: 60%;
height: 100px;
vertical-align: middle;
text-align: center;
background: grey;
border: 2px soid white;
border-radius: 5px;
z-index: 9999;
}
.open-cell {
background: #CCFFFF;
}
.close-cell {
background: #08a3db;
}
#btn {
display: inline-block;
width: 120px;
padding: 5px;
margin: 0 auto;;
text-align: center;
vertical-align: bottom;
border: 2px solid green;
background: white;
border-radius: 3px;
cursor: pointer;
}
"// noprotect";
function Util() {
}
Util.trim = function(str) {
return str.replace(/^\s+|\s+$/g,"");
};
Util.hasClass = function(node, klass) {
var classes = ' ' + node.className.replace(/\s/, ' ') + ' ';
if ( classes.indexOf(' ' + klass + ' ') >= 0 ) {
return true;
}
return false;
};
Util.addClass = function(node, klass) {
if ( !Util.hasClass(node, klass) ) {
if ( node.className.length !== 0 ) {
node.className += ' ' + klass;
} else {
node.className = klass;
}
}
return node;
};
Util.removeClass = function(node, klass) {
if ( Util.hasClass(node, klass) ) {
var classes = ' ' + node.className + ' ',
regexp = new RegExp(" " + klass + "(?= )", 'g');
node.className = Util.trim( classes.replace(regexp, ' ') );
}
return node;
};
Util.toggleClass = function(node, klass) {
if ( !Util.hasClass(node, klass) ) {
return Util.addClass(node, klass);
} else {
return Util.removeClass(node, klass);
}
};
Util.clearClass = function(node) {
node.className = '';
};
Util.hasContentOfTag = function(node, content) {
var contentStr = node.innerHTML;
if ( contentStr == content) {
return true;
}
return false;
};
Util.addContentOfTag = function(node, content) {
node.innerHTML = content;
};
Util.removeContentOfTag = function(node, content) {
node.innerHTML = '';
};
Util.toggleContentOfTag = function(node, content) {
if ( !Util.hasContentOfTag(node, content) ) {
Util.addContentOfTag(node, content);
} else {
Util.removeContentOfTag(node, content);
}
};
Util.getRandom = function(size) {
return Math.floor(Math.random()*size);
};
Util.showWindow = function(self, id, clickOnBtn) {
var tpl = document.getElementById(id).innerHTML,
result = _.template(tpl, 1);
document.body.insertAdjacentHTML('afterBegin', result);
var button = document.getElementById('btn');
button.addEventListener('click', function(event) {
event.preventDefault();
clickOnBtn(self);
});
/*var button = document.getElementById('btn');
button.addEventListener('click', function(event) {
event.preventDefault();
Util.clickBtn(self);
});*/
};
Util.showLoseWindow = function(self) {
Util.showWindow(self, 'template-for-lose');
};
Util.showWinWindow = function(self) {
Util.showWindow(self, 'template-for-win');
};
Util.removeWindow = function() {
var body = document.body,
window = document.getElementById('window-lose') || document.getElementById('window-win'),
cover = document.getElementById('cover');
body.removeChild(window);
body.removeChild(cover);
};
Util.clickBtn = function(self) {
self.makeNewGame();
};
function Field(width, height, mines) {
this.width = width;
this.height = height;
this.mines = mines;
this.amountCells = this.width * this.height;
}
Field.prototype.generateField = function() {
var body = document.body,
table = document.createElement('table'),
tr,
td;
body.insertBefore(table, body.firstChild);
this.table = table;
this.cells = [];
this.generateCells();
/*for (var x = 0; x < this.width; x++) {
tr = table.insertRow();
this.cells[x] = [];
for (var y = 0; y < this.height; y++) {
td = tr.insertCell();
this.cells[x][y] = new Cell(td, x, y);
}
}*/
};
Field.prototype.generateCells = function() {
var tr, td;
for (var x = 0; x < this.width; x++) {
tr = this.table.insertRow();
this.cells[x] = [];
for (var y = 0; y < this.height; y++) {
td = tr.insertCell();
this.cells[x][y] = new Cell(td, x, y);
}
}
};
Field.prototype.generateMines = function() {
var x, y;
var i = 0;
while (i < this.mines) {
x = Util.getRandom(this.width);
y = Util.getRandom(this.height);
if ( !this.getCellAt(x, y).checkHasMine() ) {
this.getCellAt(x, y).miningCell();
console.log(x + ' ' + y);
i++;
}
}
};
Field.prototype.getCellAt = function(x, y) {
return this.cells[x][y];
};
Field.prototype.getCell = function(td) {
for (var x = 0; this.width > x; x++) {
for (var y = 0; this.height > y; y++) {
if (this.getCellAt(x, y).getTd() == td) {
return this.cells[x][y];
}
}
}
};
Field.prototype.calcMinesAround = function(cell) {
var mines = 0,
cells = this.getNeighboars(cell);
for (var i = 0; i < cells.length; i++) {
if (cells[i].checkHasMine() === true) {
mines++;
}
}
return mines;
};
Field.prototype.getNeighboars = function(cell) {
var cells = [];
var posX = cell.getCoorByCell().x,
posY = cell.getCoorByCell().y;
for (var x = posX - 1; x <= posX + 1; x++) {
for (var y = posY - 1; y <= posY + 1; y++) {
if ( this.cellExists(x, y) ) {
if ( x != posX || y != posY ) {
cells.push(this.getCellAt(x, y));
}
}
}
}
return cells;
};
Field.prototype.cellExists = function(x, y) {
if ( this.cells[x] !== undefined && this.cells[x][y] !== undefined) {
return true;
}
return false;
};
Field.prototype.openNullCells = function(cell) {
var neighbCells = this.getNeighboars(cell);
cell.showOpenCell();
for (var i = 0; i < neighbCells.length; i++) {
this.openCell(neighbCells[i]);
}
};
Field.prototype.openCell = function(cell) {
var td = cell.getTd(),
status = cell.getStatus();
if (status === false) {
if (cell.checkHasMine() === true) {
var self = this;
cell.showMine(td);
Util.showWindow(self, 'template-for-lose', function(self) {
self.makeNewGame();
});
}
if (cell.checkHasMine() === false) {
var mines = this.calcMinesAround(cell);
if (mines !== 0) {
cell.showAmountMines(mines, td);
}
if (mines === 0) {
this.openNullCells(cell);
}
}
}
};
Field.prototype.checkWin = function() {
var amount = 0,
cell;
for (var x = 0; this.width > x; x++) {
for (var y = 0; this.height > y; y++) {
cell = this.getCellAt(x, y);
if ( cell.getStatus() === true && cell.checkHasMine() === false) {
amount++;
}
}
}
if (amount == this.amountCells - this.mines) {
var self = this;
Util.showWindow(self, 'template-for-win', function(self) {
self.makeNewGame();
});
}
};
Field.prototype.makeNewGame = function() {
this.clearField();
this.generateCells();
this.generateMines();
this.closeCells();
Util.removeWindow();
};
Field.prototype.closeCells = function() {
for (var x = 0; this.width > x; x++) {
for (var y = 0; this.height > y; y++) {
var td = this.cells[x][y].getTd();
Util.clearClass(td);
Util.addClass(td, 'close-cell');
}
}
};
Field.prototype.clearField = function() {
this.table.innerHTML = '';
};
function Cell(td, x, y) {
this.td = td;
this.hasMine = false;
this.x = x;
this.y = y;
this.isOpened = false;
this.isFlag = false;
}
Cell.prototype.miningCell = function() {
this.hasMine = true;
};
Cell.prototype.checkHasMine = function() {
if (this.hasMine) {
return true;
}
return false;
};
Cell.prototype.getTd = function() {
return this.td;
};
Cell.prototype.getCoorByCell = function() {
return {'x': this.x, 'y': this.y};
};
Cell.prototype.getStatus = function() {
return this.isOpened;
};
Cell.prototype.changeStatus = function() {
this.isOpened = true;
};
Cell.prototype.closeCell = function() {
this.isOpened = false;
};
Cell.prototype.showOpenCell = function() {
this.changeStatus();
Util.clearClass(this.getTd());
Util.addClass(this.getTd(), 'open-cell');
};
Cell.prototype.showMine = function(td) {
this.showOpenCell();
td.innerHTML = '<span>☢</span>';
};
Cell.prototype.showAmountMines = function(mines, td) {
this.showOpenCell();
td.innerHTML = '<span>' + mines +'</span>';
};
Cell.prototype.hasFlag = function() {
return this.isFlag;
};
Cell.prototype.changeHasFlag = function() {
this.isFlag = !this.isFlag;
};
Cell.prototype.toggleFlag = function() {
Util.toggleContentOfTag(this.getTd(), '<span>⚑</span>');
};
var field1 = new Field(10, 10, 10);
field1.generateField();
field1.generateMines();
field1.table.addEventListener('mousedown', function(event) {
event.preventDefault();
var target = event.target;
while (target.tagName != 'TD') {
target = target.parentNode;
}
var cell = field1.getCell(target),
status = cell.getStatus(),
flag = cell.hasFlag();
if (target.tagName == 'TD') {
target.setAttribute('oncontextmenu', '; return false');
if (event.which == 1 && flag === false) {
field1.openCell(cell);
field1.checkWin();
} else if ( event.which == 3 && status === false ) {
cell.changeHasFlag();
cell.toggleFlag();
}
}
});
Output
You can jump to the latest bin by adding /latest
to your URL
Keyboard Shortcuts
Shortcut | Action |
---|---|
ctrl + [num] | Toggle nth panel |
ctrl + 0 | Close focused panel |
ctrl + enter | Re-render output. If console visible: run JS in console |
Ctrl + l | Clear the console |
ctrl + / | Toggle comment on selected lines |
ctrl + ] | Indents selected lines |
ctrl + [ | Unindents selected lines |
tab | Code complete & Emmet expand |
ctrl + shift + L | Beautify code in active panel |
ctrl + s | Save & lock current Bin from further changes |
ctrl + shift + s | Open the share options |
ctrl + y | Archive Bin |
Complete list of JS Bin shortcuts |
JS Bin URLs
URL | Action |
---|---|
/ | Show the full rendered output. This content will update in real time as it's updated from the /edit url. |
/edit | Edit the current bin |
/watch | Follow a Code Casting session |
/embed | Create an embeddable version of the bin |
/latest | Load the very latest bin (/latest goes in place of the revision) |
/[username]/last | View the last edited bin for this user |
/[username]/last/edit | Edit the last edited bin for this user |
/[username]/last/watch | Follow the Code Casting session for the latest bin for this user |
/quiet | Remove analytics and edit button from rendered output |
.js | Load only the JavaScript for a bin |
.css | Load only the CSS for a bin |
Except for username prefixed urls, the url may start with http://jsbin.com/abc and the url fragments can be added to the url to view it differently. |