Implement classic minesweeper game with pure javascript
- 2020-06-01 08:15:53
- OfStack
A long time ago wrote when all did not write notes just added (nima, a lot of their own do not know... )
The deficiency is the original want to write a game ranking statistics, and so on the free plus (seems to say so every time and then wait for a long time...)
Also not implemented: clicking on the first cell cannot be a ray function
<style>
ul{padding:0;list-style:none;}
#mine{overflow:hidden;width:30px;height:30px;border:1px solid #966;}
#mine li{float:left;width:30px;height:30px;line-height:30px;text-align:center;font-size:14px;color:#222;}
#mine .mine_01{background:url(mine.gif) no-repeat;}
#mine .mine_02{background:url(mine.gif) -30px 0 no-repeat;}
#mine .mine_03{background:url(mine.gif) -60px 0 no-repeat;}
#mine .mine_04{background:url(mine.gif) -90px 0 no-repeat;}
#mine .mine_05{background:url(mine.gif) -120px 0 no-repeat;}
#mine .mine_06{background:url(mine.gif) -150px 0 no-repeat;}
#mine .mine_07{background:url(mine.gif) -180px 0 no-repeat;}
#count{font-size:12px;}
#time{color:#900;font-weight:bold;}
</style>
<select id="wh">
<option value="8*10">8*10</option>
<option value="10*10">10*10</option>
<option value="12*12">12*12</option>
</select>
<button id='ready'> Start all over again </button>
<div id="count">
timing : <span id="time">0</span>
</div>
<ul id="mine">
</ul>
ie6+ ff oprea Google
opera An earlier version Not supported by default document.oncontextmenu The event No good alternative has been found
<script>
var $ = function(id){return document.getElementById(id)};
window.onload=function ready(){
var V=$('wh').value.split('*')
setMineField(Number(V[0]),Number(V[1]));
$('wh').onchange=$('ready').onclick=function(){
V=$('wh').value.split('*')
setMineField(Number(V[0]),Number(V[1]))
}
}
//--------------------------------------------------- minefields
var mineField={
_mineW:30, // every 1 The width of a mine Must be synchronized with the style
_mineH:30,
_mineFieldBlock:$('mine'),
_mineFieldEle:$('mine').getElementsByTagName('li'),
_time:$('time'),
status:0, // State of mine 0 Haven't started 1 began The clock is ticking 2 Game over
mineNum:0, // Ray number
clearPlace:0, // Statistical sweep of the grid ;
x:0, // column
y:0, // line
density:0.2, // The density of ray The density of minefields should not exceed 0.5 Under some size minefields Too high a setting Unable to generate mineMap An array of
mineMap:[], // The minefield 2 D figure ,0 : Not the thunder -1 : ray
time:-1, // timing s
debug:false // Debug mode
}//mineField object end
function timedCount(){
if(mineField.status!=1){return false}
mineField.time++;
mineField._time.innerHTML=mineField.time;
setTimeout("timedCount()",1000);
}
//-------------------------------------- Set ray's state
function setThisMine(str,index){
var allMine=mineField._mineFieldEle;
// Set ray whether to plant the flag
if(str=='setOn'){
var thisMine=allMine[index];
thisMine.on=thisMine.on<2?thisMine.on+1:0;
if(thisMine.on==1){thisMine.className='mine_03';}// flag
else if(thisMine.on==2){thisMine.className='mine_04'}// Cancel the flag
else if(thisMine.on==0){thisMine.className='mine_01'}// Cancel the flag
return false;
}
// Display pane
if(str=='show'){
if(Object.prototype.toString.call(index) === '[object Array]'){// According to 1 large
mineField.clearPlace=mineField.clearPlace+index.length;
for(var i=0;i<index.length;i++){
var thisMine=allMine[index[i]];
thisMine.innerHTML=mineField.mineMap[thisMine.index];
thisMine.className='mine_02';
thisMine.on=3;
}
}
else{// Displays a single non-mine area
mineField.clearPlace++;
allMine[index].on=3;
allMine[index].innerHTML=mineField.mineMap[index];
allMine[index].className='mine_02';
}
if(mineField.clearPlace==mineField.x*mineField.y-mineField.mineNum){// Congratulations on your
alert(' Congratulations on your ');
for(var i=0;i<allMine.length;i++){
if(mineField.mineMap[allMine[i].index]==-1){
allMine[i].className='mine_07';
}
}
mineField.status=2;
return false;
}
}
// Show all mines
if(str=='peng'){
for(var i=0;i<allMine.length;i++){
if(mineField.mineMap[allMine[i].index]==-1){
allMine[i].className=i==index?'mine_06':'mine_05';
}
}
mineField.status=2;
}
}
//----------------------------------------------- Set the number of rows and The number of columns
function setMineField(a,b){
var thisMineFiele=mineField._mineFieldBlock;
DivBox=document.createElement("div"),
num=a*b,k=0;
thisMineFiele.innerHTML='';
// Adjustment of minefield parameters
mineField.x=a;// There are several columns
mineField.y=b;// There are a few lines
mineField.mineNum=Math.floor(a*b*mineField.density);
mineField.status=0;
mineField.time=-1;
mineField.clearPlace=0;
mineField.mineMap.length=0;
mineField._time.innerHTML=0;
// Generate a minefield map
setMineMap();
// Generate a minefield ( create li)
while(k<num){
var newLi=document.createElement("li");
if(mineField.debug) newLi.innerHTML=mineField.mineMap[k];// cheating
newLi.className='mine_01';
DivBox.appendChild(newLi);
k++;
}
thisMineFiele.style.height=mineField._mineW*b+'px';
thisMineFiele.style.width=mineField._mineH*a+'px';
thisMineFiele.innerHTML=DivBox.innerHTML;
DivBox=null;
setEvent();// The event
}
//----------------------------------- Generate a minefield map
function setMineMap(){
var num=mineField.x*mineField.y,
mineNum=mineField.mineNum,
Interval=Math.floor(num/mineNum);
for(var i=0;i<num;i++){
if(i%Interval==0&&i<mineNum*Interval){mineField.mineMap[i]=-1;}else{mineField.mineMap[i]=0;}// Ray equidistant distribution with array
}
mineField.mineMap.sort(function(){ return 0.5 - Math.random()})// Disrupted array
// Check if there is thunder all around the grid If so You want to regenerate the minefield To avoid a minefield
var br=0,// Where the line
x=mineField.x,
L_T,T,R_T,L,R,L_B,B,R_B;
for(var i=0;i<num;i++){
br=Math.ceil((i+1)/x);
L_T = i-x-1;
T = i-x;
R_T = i-x+1;
L = i-1;
R = i+1;
L_B = i+x-1;
B = i+x;
R_B = i+x+1;
// Sit on the corner If you're in a minefield And it's on top 1 line And he's not ray Under it 1 Grid testing
if(L_T>=0&&Math.ceil((L_T+1)/x)==br-1&&mineField.mineMap[L_T]==0){continue}
if(T >=0&&Math.ceil((T +1)/x)==br-1&&mineField.mineMap[T ]==0){continue}
if(R_T>=0&&Math.ceil((R_T+1)/x)==br-1&&mineField.mineMap[R_T]==0){continue}
if(L>=0 &&Math.ceil((L+1)/x)==br&&mineField.mineMap[L]==0){continue}
if(R<num&&Math.ceil((R+1)/x)==br&&mineField.mineMap[R]==0){continue}
if(L_B<num&&Math.ceil((L_B+1)/x)==br+1&&mineField.mineMap[L_B]==0){continue}
if(B <num&&Math.ceil((B +1)/x)==br+1&&mineField.mineMap[B ]==0){continue}
if(R_B<num&&Math.ceil((R_B+1)/x)==br+1&&mineField.mineMap[R_B]==0){continue}
setMineMap();
return false
}
// Count the number of mines around the non-lightning grid
for(i=0;i<num;i++){
if(mineField.mineMap[i]==-1){continue}
var thisMineNum=0
br=Math.ceil((i+1)/x);
L_T = i-x-1;
T = i-x;
R_T = i-x+1;
L = i-1;
R = i+1;
L_B = i+x-1;
B = i+x;
R_B = i+x+1;
if(L_T>=0&&Math.ceil((L_T+1)/x)==br-1&&mineField.mineMap[L_T]==-1){thisMineNum++;}
if(T >=0&&Math.ceil((T +1)/x)==br-1&&mineField.mineMap[T ]==-1){thisMineNum++;}
if(R_T>=0&&Math.ceil((R_T+1)/x)==br-1&&mineField.mineMap[R_T]==-1){thisMineNum++;}
if(L>=0 &&Math.ceil((L+1)/x)==br&&mineField.mineMap[L]==-1){thisMineNum++;}
if(R<num&&Math.ceil((R+1)/x)==br&&mineField.mineMap[R]==-1){thisMineNum++;}
if(L_B<num&&Math.ceil((L_B+1)/x)==br+1&&mineField.mineMap[L_B]==-1){thisMineNum++;}
if(B <num&&Math.ceil((B +1)/x)==br+1&&mineField.mineMap[B ]==-1){thisMineNum++;}
if(R_B<num&&Math.ceil((R_B+1)/x)==br+1&&mineField.mineMap[R_B]==-1){thisMineNum++;}
mineField.mineMap[i]=thisMineNum;
}
}
//---------------------------------- Minefields event
function setEvent(){
var thisMineFiele=mineField._mineFieldBlock,
allMine=mineField._mineFieldEle,
iMax=mineField.x*mineField.y;
for(var i=0;i<iMax;i++){
allMine[i].index=i;
allMine[i].on=0;//0 As the default 1 For the flag 2 For the question mark 3 To show the
}
thisMineFiele.onmouseup=function(e){
if(mineField.status==2){return false;}
if(mineField.status==0){mineField.status=1;timedCount();}
var e=e||window.event,
thisObj=e.target||e.srcElement;
if(thisObj.nodeName=='UL'||thisObj.on==3){return false;}
var Btn=getButton(e);
if(Btn== 0){// left-click
if(thisObj.on==1){return false;}// The setting flags I can't
if(mineField.mineMap[thisObj.index]==-1){// Point of the ray
setThisMine('peng',thisObj.index);
}else if(mineField.mineMap[thisObj.index]==0){// Point to the clearing Open the 1 large
//alert(' You're in luck ')
var allShowMine=minesShow(thisObj.index);
setThisMine('show',allShowMine)
}else{// According to 1 A grid
setThisMine('show',thisObj.index)
}
}
if(Btn== 2){// Right click
setThisMine('setOn',thisObj.index);
}
}
}
//-------------------------------- When you press the space According to 1 large
function minesShow(I){
var allMine=mineField._mineFieldEle,
allShowMine=[I];// Save the subscript of the ray to display
allMine[I].on=3;
see(I);// The query index is I The surrounding square
function see(allI){
var _allI=[];
if(Object.prototype.toString.call(allI) === '[object Array]'){
for(var i=0;i<allI.length;i++){f(allI[i])}
}
else{f(allI)}
function f(thisI){
var text,
x=mineField.x,
br,
num=x*mineField.y,
L_T,T,R_T,L,R,L_B,B,R_B;
text='_'+allShowMine.join('_')+'_';// To determine whether the subscript has been written to the array
br=Math.ceil((thisI+1)/x);
L_T = thisI-x-1;
T = thisI-x;
R_T = thisI-x+1;
L = thisI-1;
R = thisI+1;
L_B = thisI+x-1;
B = thisI+x;
R_B = thisI+x+1;
// The top left square If you're in a minefield And in the 1 line Open lattice again And the blank space So let's write as _allI An array of To carry out the 1 Time to retrieve
if(L_T>=0&&Math.ceil((L_T+1)/x)==br-1&&allMine[L_T].on==0&&mineField.mineMap[L_T] == 0){_allI.push(L_T);}
if(T >=0&&Math.ceil((T +1)/x)==br-1&&allMine[T ].on==0&&mineField.mineMap[T ] == 0){_allI.push(T);}
if(R_T>=0&&Math.ceil((R_T+1)/x)==br-1&&allMine[R_T].on==0&&mineField.mineMap[R_T] == 0){_allI.push(R_T);}
if(L>=0&&Math.ceil((L+1)/x)==br&&allMine[L].on==0&&mineField.mineMap[L] == 0){_allI.push(L);}
if(R<num&&Math.ceil((R+1)/x)==br&&allMine[R].on==0&&mineField.mineMap[R] == 0){_allI.push(R);}
if(L_B<num&&Math.ceil((L_B+1)/x)==br+1&&allMine[L_B].on==0&&mineField.mineMap[L_B] == 0){_allI.push(L_B);}
if(B <num&&Math.ceil((B +1)/x)==br+1&&allMine[B ].on==0&&mineField.mineMap[B ] == 0){_allI.push(B);}
if(R_B<num&&Math.ceil((R_B+1)/x)==br+1&&allMine[R_B].on==0&&mineField.mineMap[R_B] == 0){_allI.push(R_B);}
//------------------------------------------------
// The top left corner of the grid If you're in a minefield And in the 1 line Open lattice again Again not written allShowMine An array of So let's do that And mark in advance as turned over the grid
if(L_T>=0&&Math.ceil((L_T+1)/x)==br-1&&allMine[L_T].on==0&&text.indexOf('_'+L_T+'_') == -1){allShowMine.push(L_T);allMine[L_T].on=3}
if(T >=0&&Math.ceil((T +1)/x)==br-1&&allMine[T ].on==0&&text.indexOf('_'+T+'_') == -1){allShowMine.push(T);allMine[T].on=3}
if(R_T>=0&&Math.ceil((R_T+1)/x)==br-1&&allMine[R_T].on==0&&text.indexOf('_'+R_T+'_') == -1){allShowMine.push(R_T);allMine[R_T].on=3}
if(L>=0&&Math.ceil((L+1)/x)==br&&allMine[L].on==0&&text.indexOf('_'+L+'_') == -1){allShowMine.push(L);allMine[L].on=3}
if(R<num&&Math.ceil((R+1)/x)==br&&allMine[R].on==0&&text.indexOf('_'+R+'_') == -1){allShowMine.push(R);allMine[R].on=3}
if(L_B<num&&Math.ceil((L_B+1)/x)==br+1&&allMine[L_B].on==0&&text.indexOf('_'+L_B+'_') == -1){allShowMine.push(L_B);allMine[L_B].on=3}
if(B <num&&Math.ceil((B +1)/x)==br+1&&allMine[B ].on==0&&text.indexOf('_'+B+'_') == -1){allShowMine.push(B );allMine[B ].on=3}
if(R_B<num&&Math.ceil((R_B+1)/x)==br+1&&allMine[R_B].on==0&&text.indexOf('_'+R_B+'_') == -1){allShowMine.push(R_B);allMine[R_B].on=3}
if(_allI.length!=0){see(_allI)}
}
}
return allShowMine
}
//--------------------------------------
document.oncontextmenu=function(){return false;}// Disable right-click menu
function getButton(e){
var Btn;
if(document.implementation.hasFeature('MouseEvents','2.0')){Btn=e.button;}
else{ switch(e.button){
case 0:
case 1:
case 3:
case 5:
case 7:
Btn=0;
break;
case 2:
case 6:
Btn=2;
break;
case 4:
Btn=9;
break;
}
}
return Btn;
}
</script>
That's all for this article, I hope you enjoy it.