Advertisement
Guest User

Mine Sweeper

a guest
Feb 21st, 2018
68
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  1. !function($){
  2.    
  3.     var defaults = {
  4.         cols: 8,
  5.         rows: 8,
  6.         bombs: 10
  7.     };
  8.    
  9.     var Cell = function Cell(x,y,isBomb) {
  10.         this.x = x;
  11.         this.y = y;
  12.         this.isBomb = isBomb;
  13.        
  14.         this.activeNeighbours = 0;
  15.         this.neighbours = [];
  16.         this.revealed = false;
  17.         this._mark = "";
  18.         this.id = y + "-" + x;
  19.     };
  20.     Cell.prototype.setValue = function(value){
  21.         var el = $("#minesweeper").find("td[data-index='"+this.id+"']");
  22.         el.removeClass('mark').html(value);
  23.         switch(value) {
  24.             case "!":
  25.             case "?":
  26.                 el.addClass('mark');
  27.                 break;
  28.             case "X":
  29.                 el.addClass('bomb');
  30.                 break;
  31.         }
  32.         return this;
  33.     };
  34.     Cell.prototype.addNeighbour = function(neighbour){
  35.         this.neighbours.push(neighbour);
  36.         this.activeNeighbours += (neighbour.isBomb ? 1 : 0);
  37.         return this;
  38.     };
  39.     Cell.prototype.getNeighbours = function(neighbour){
  40.         return this.neighbours;
  41.     };
  42.     Cell.prototype.isRevealed = function(neighbour){
  43.         return this.revealed || this.isBomb;
  44.     };
  45.     Cell.prototype.reveal = function(fn, context){
  46.         if(this.isBomb) {
  47.             return ;
  48.         }
  49.         this.revealed = true;
  50.         this.setValue(this.activeNeighbours);
  51.         if(this.activeNeighbours === 0) {
  52.             $.each(this.getNeighbours(), function(i, neighbour){
  53.                 if(!neighbour.isRevealed()) {
  54.                     neighbour.reveal(fn, context);
  55.                 }
  56.             });
  57.         };
  58.         fn.call(context);
  59.     };
  60.     Cell.prototype.mark = function() {
  61.         if(this.revealed) {
  62.             return ;
  63.         }
  64.         switch(this._mark) {
  65.             case "":
  66.                 this._mark = "?";
  67.                 break;
  68.             case "?":
  69.                 this._mark = "!";
  70.                 break;
  71.             case "!":
  72.                 this._mark = "";
  73.                 break;
  74.         }
  75.         this.setValue(this._mark || " ");
  76.         return this;
  77.     };
  78.    
  79.     var Board = {
  80.         board: [],
  81.         bombStack: {},
  82.         reset: function(rows, colls, numBombs) {
  83.             var x, y, row, self = this;
  84.            
  85.             this.colls = colls;
  86.             this.rows = rows;
  87.            
  88.             this.board = []; // reset the board
  89.             this.bombStack = {}; // reset our current bomb stack
  90.            
  91.             this.generateBombs(numBombs);
  92.            
  93.             // build the data structure
  94.             for(y=0; y<this.rows; y++) {
  95.                 row = [];
  96.                 this.board.push(row);
  97.                 for(x=0; x<this.colls; x++) {
  98.                     var isBomb = this.bombStack[y] && this.bombStack[y][x];
  99.                     row.push(new Cell(x,y,isBomb));
  100.                 }
  101.             }
  102.            
  103.             // assign neightbour reference for each cell
  104.             this.traversCells(function(cell) {
  105.                 var neighbours = self.calcNeighbours(cell);
  106.                 $.each(neighbours, function(key, value){
  107.                     cell.addNeighbour(value);
  108.                 });
  109.             });
  110.            
  111.             return this;
  112.         },
  113.         // run a callback on each cell in the board
  114.         traversCells: function(fn) {
  115.             var x, y;
  116.             for(y=0; y<this.rows; y++){
  117.                 for(x=0; x<this.colls; x++){
  118.                     fn(this.getCell(x, y));
  119.                 }
  120.             }
  121.         },
  122.         draw: function(){
  123.             var x, y, tr, td, tbody = $('<tbody>');
  124.             for(y=0; y<this.rows; y++) {
  125.                 tr = $('<tr>');
  126.                 for(x=0; x<this.colls; x++) {
  127.                     td = $('<td data-index="'+y+'-'+x+'">').html("&nbsp;");
  128.                     tr.append(td);
  129.                 }
  130.                 tbody.append(tr);
  131.             }
  132.             Game.over = false;
  133.             $("#minesweeper").empty().html(tbody);
  134.             return this;
  135.         },
  136.         validate: function(){
  137.             var numActive = 0;
  138.             this.traversCells(function(cell) {
  139.                 numActive += cell.isRevealed() ? 0 : 1;
  140.             });
  141.             if(!numActive) {
  142.                 this.checkBombs();
  143.                 Game.complete(true);
  144.             }
  145.         },
  146.         reveal: function(cell, passive){
  147.             cell.reveal(this.validate, this);
  148.             if(cell.isBomb) {
  149.                 this.checkBombs();
  150.                 Game.complete();
  151.             }
  152.         },
  153.         getCell: function(x,y) {
  154.             return this.board[y][x];
  155.         },
  156.         generateBombs: function(numBombs) {
  157.             var i;
  158.             for(i=0; i<numBombs; i++) {
  159.                 this.generateBomb();
  160.             }
  161.         },
  162.         generateBomb: function() {
  163.             var x = Math.floor(Math.random() * this.colls);
  164.             var y = Math.floor(Math.random() * this.rows);
  165.             if(this.bombStack[y] && this.bombStack[y][x]) { // do not allow duplicates
  166.                 return this.generateBomb();
  167.             }
  168.             this.bombStack[y] = this.bombStack[y] || {};
  169.             this.bombStack[y][x] = true;
  170.         },
  171.         checkBombs: function(){
  172.             this.traversCells(function(cell) {
  173.                 if(cell.isBomb) {
  174.                     cell.setValue("X");
  175.                 }
  176.             });
  177.         },
  178.         getCellByEvent: function(e) {
  179.             var cords = $(e.target).attr('data-index').split('-');
  180.             var y = +cords[0], x=+cords[1];
  181.             return this.getCell(x, y);
  182.         },
  183.         calcNeighbours: function(cell) {
  184.             var i, j, data = [], x = cell.x, y = cell.y;
  185.             for( i=y-1; i<=y+1; i++ ) {
  186.                 if(i<0 || i>=this.rows)  continue;
  187.                 for(j=x-1; j<=x+1; j++) {
  188.                     if(j<0 || j>=this.colls) continue;
  189.                     if(x===j && y===i) continue;
  190.                     data.push(this.getCell(j,i));
  191.                 }
  192.             }
  193.             return data;
  194.         }
  195.     };
  196.    
  197.     var Game = {
  198.         over: false,
  199.         complete: function(win) {
  200.             $('#status').html("Game Over, You " + (win ? "Won" : "Lost") + "!");
  201.             if(win) {
  202.                 $('#status').addClass("alert-success").removeClass("alert-info").removeClass("alert-error");
  203.             }
  204.             else {
  205.                 $('#status').removeClass("alert-success").removeClass("alert-info").addClass("alert-error");
  206.             }
  207.             var el = $("#minesweeper");
  208.             el.removeClass('active');
  209.             if(!win) {
  210.                 el.addClass('lost');
  211.             }
  212.             this.over = true;
  213.         },
  214.         setDefaults: function(){
  215.             $("#rows").val(defaults.cols);
  216.             $("#cols").val(defaults.rows);
  217.             $("#bombs").val(defaults.bombs);
  218.         },
  219.         start: function(options){
  220.             options = options || {};
  221.             var pat = /\D/;
  222.             var numBombs = $("#bombs").val(), colls = $("#cols").val(), rows = $("#rows").val();
  223.             // add some input valoidation
  224.             if(pat.test(colls) || pat.test(rows) || pat.test(numBombs)) {
  225.                 throw new Error('Use numbers only');
  226.             }
  227.             if (numBombs > colls * rows) {
  228.                 throw new Error('Too many bombs');
  229.             }
  230.            
  231.             if(options.skipConfirm || confirm("Are you sure?")) {
  232.                 Board.reset(rows, colls, numBombs).draw();
  233.                 $('#status').html("Playing").addClass("alert-info").removeClass("alert-success").removeClass("alert-error");
  234.                 $("#minesweeper").addClass('active').removeClass('lost');
  235.             }
  236.         }
  237.     };
  238.    
  239.     $(function(){
  240.        
  241.         $("#minesweeper").delegate("td", "click", function(e){
  242.             if(!Game.over) {
  243.                 Board.reveal(Board.getCellByEvent(e));
  244.             }
  245.         });
  246.        
  247.         $("#minesweeper").delegate("td", "contextmenu", function(e){
  248.             e.preventDefault();
  249.             if(!Game.over) {
  250.                 Board.getCellByEvent(e).mark();
  251.             }
  252.         });
  253.  
  254.         $("#new-game").on('click', function(e){
  255.             e.preventDefault();
  256.             $("form").submit();
  257.         });
  258.        
  259.         $("form").on('submit', function(e){
  260.             e.preventDefault();
  261.             try {
  262.                 Game.start();
  263.             }
  264.             catch(ex){
  265.                 alert(ex.message);
  266.                 Game.setDefaults();
  267.             }
  268.         });
  269.        
  270.         $("#cheat").on('click', function(){
  271.             Board.checkBombs();
  272.             return false;
  273.         });
  274.        
  275.         Game.setDefaults();
  276.         Game.start({skipConfirm: true});
  277.     });
  278.    
  279. }(jQuery);
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement