Minesweeper

View Build

HTML

            
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Minesweeper</title>
    <link rel="stylesheet" href="style.css">
    <script src="script.js" defer></script>
</head>
<body>
    <canvas width=400 height=400></canvas>
</body>
</html>
            
        

CSS

            
body{
    background: black;
    color: white;
    height: 100vh;
    margin: 0;
    display: flex;
    justify-content: center;
    align-items: center;
}

canvas{
    border: 1px solid white;
}
            
        

JS

            
let canvas = document.querySelector("canvas")
let c = canvas.getContext('2d')

let dim = 8

let blankPlate = [...Array(dim).keys().map(i => [...Array(dim).keys().map(j=>0)])]
let map = structuredClone(blankPlate)
let mask = structuredClone(blankPlate)

function drawCell(row,col){
    if(!mask[row][col]){
        c.beginPath()
        c.rect(canvas.width/dim*col,canvas.height/dim*row,canvas.width/dim,canvas.height/dim)
        c.fillStyle = "gold"
        c.fill()
        c.beginPath()//left side
        c.moveTo(canvas.width/dim*col,canvas.height/dim*row)
        c.lineTo(canvas.width/dim*(col+.2),canvas.height/dim*(row+.2))
        c.lineTo(canvas.width/dim*(col+.2),canvas.height/dim*(row+.8))
        c.lineTo(canvas.width/dim*col,canvas.height/dim*(row+1))
        c.fillStyle = "sandybrown"
        c.fill()
        c.beginPath()//right side
        c.moveTo(canvas.width/dim*(col+1),canvas.height/dim*row)
        c.lineTo(canvas.width/dim*(col+.8),canvas.height/dim*(row+.2))
        c.lineTo(canvas.width/dim*(col+.8),canvas.height/dim*(row+.8))
        c.lineTo(canvas.width/dim*(col+1),canvas.height/dim*(row+1))
        c.fillStyle = "lemonchiffon"
        c.fill()
        c.beginPath()//top side
        c.moveTo(canvas.width/dim*col,canvas.height/dim*row)
        c.lineTo(canvas.width/dim*(col+.2),canvas.height/dim*(row+.2))
        c.lineTo(canvas.width/dim*(col+.8),canvas.height/dim*(row+.2))
        c.lineTo(canvas.width/dim*(col+1),canvas.height/dim*row)
        c.fillStyle = "khaki"
        c.fill()
        c.beginPath()//bottom side
        c.moveTo(canvas.width/dim*col,canvas.height/dim*(row+1))
        c.lineTo(canvas.width/dim*(col+.2),canvas.height/dim*(row+.8))
        c.lineTo(canvas.width/dim*(col+.8),canvas.height/dim*(row+.8))
        c.lineTo(canvas.width/dim*(col+1),canvas.height/dim*(row+1))
        c.fillStyle = "chocolate"
        c.fill()
    }
    else{
        c.beginPath()
        c.fillStyle = map[row][col]=="B" ? "coral" : "sandybrown"
        c.fillRect(canvas.width/dim*col,canvas.height/dim*row,canvas.width/dim, canvas.height/dim)
        c.beginPath()
        c.fillStyle = "#444"
        c.font = (200/dim)+"pt Arial"
        c.textAlign = "center"
        c.fillText(map[row][col],canvas.width/dim*(col+.5),canvas.height/dim*(row+.75))
    }
}

function drawGrid(){
    for(let x = canvas.width/dim; x < canvas.width; x+= canvas.width/dim){
        c.beginPath()
        c.moveTo(x,0)
        c.lineTo(x,canvas.height)
        c.strokeStyle = "gray"
        c.stroke()
    }
    for(let y = canvas.height/dim; y < canvas.height; y+= canvas.height/dim){
        c.beginPath()
        c.moveTo(0,y)
        c.lineTo(canvas.width,y)
        c.strokeStyle = "gray"
        c.stroke()
    }
}

function populateMap(row,col){
    mask[row][col] = 1
    let count = 0
    while(count < Math.floor(dim*dim/5)){
        let randRow = Math.floor(Math.random()*dim)
        let randCol = Math.floor(Math.random()*dim)
        if(Math.abs(row - randRow) > 1 || Math.abs(col - randCol) > 1){
            map[randRow][randCol] = "B"
            count ++
        }
    }
    map.forEach((row,r)=>{
        row.forEach((col,c)=>{
            let tally = 0
            if(r>0){
                if(map[r-1][c] == "B") tally ++
                if(c>0){
                    if(map[r-1][c-1] == "B") tally ++
                }
                if(c0){
                if(map[r][c-1] == "B") tally ++
            }
            if(c0){
                    if(map[r+1][c-1] == "B") tally ++
                }
                if(c 0){
        console.log(check1.length)
        let [cellrow,cellcol] = check1.shift()
        mask[cellrow][cellcol] = 1
        if(map[cellrow][cellcol] == 0){
            //clear surrrounding squares
            //row above
            if(cellrow > 0){
                if(cellcol > 0){
                    if(!check2.some(item=>item[0] == cellrow-1 && item[1] == cellcol-1)){
                        check1.push([cellrow-1,cellcol-1])
                        check2.push([cellrow-1,cellcol-1])
                    }
                }
                if(!check2.some(item=>item[0] == cellrow-1 && item[1] == cellcol)){
                    check1.push([cellrow-1,cellcol])
                    check2.push([cellrow-1,cellcol])
                }
                if(col < dim-1){
                    if(!check2.some(item=>item[0] == cellrow-1 && item[1] == cellcol+1)){
                        check1.push([cellrow-1,cellcol+1])
                        check2.push([cellrow-1,cellcol+1])
                    }
                }
            }
            //same row
            if(cellcol > 0){
                if(!check2.some(item=>item[0] == cellrow && item[1] == cellcol-1)){
                    check1.push([cellrow,cellcol-1])
                    check2.push([cellrow,cellcol-1])
                }
            }
            if(col < dim-1){
                if(!check2.some(item => item[0] == cellrow && item[1] == cellcol+1)){
                    check1.push([cellrow,cellcol+1])
                    check2.push([cellrow,cellcol+1])
                }
            }
            //row below
            if(cellrow < dim-1){
                if(cellcol > 0){
                    if(!check2.some(item => item[0] == cellrow+1 && item[1] == cellcol-1)){
                        check1.push([cellrow+1,cellcol-1])
                        check2.push([cellrow+1,cellcol-1])
                    }
                }
                if(!check2.some(item => item[0] == cellrow+1 && item[1] == cellcol)){
                    check1.push([cellrow+1,cellcol])
                    check2.push([cellrow+1,cellcol])
                }
                if(col < dim-1){
                    if(!check2.some(item => item[0] == cellrow+1 && item[1] == cellcol+1)){
                        check1.push([cellrow+1,cellcol+1])
                        check2.push([cellrow+1,cellcol+1])
                    }
                }
            }
        }
        else if(map[cellrow][cellcol] == "B"){
            canvas.onclick = null
            setTimeout(function(){
                for(let row = 0; row < dim; row ++){
                    for(let col = 0; col < dim; col ++){
                        mask[row][col] = 1
                    }
                }
                drawMap()
                drawGrid()
                setTimeout(function(){begin("You have lost the game.")},1000)
            },1000)
        }
        else{

        }
    }
    drawMap()
    drawGrid()
}


let clickHandler = (e) => {
    let mx = e.clientX - canvas.getBoundingClientRect().left
    let my = e.clientY - canvas.getBoundingClientRect().top
    let mcol = Math.floor(mx/canvas.width*dim)
    let mrow = Math.floor(my/canvas.height*dim)
    if(populated){
        clearSquare(mrow,mcol)
    }
    else{
        populateMap(mrow,mcol)
        clearSquare(mrow,mcol)
        populated = true
    }
}

let populated = false
canvas.onclick = null

function begin(msg){
    let message = ""
    let defaultMessage = "For an n x n grid, choose an n between 4-20."
    if(msg) message += msg + " " + defaultMessage
    dim = 0
    let tries = 0
    while (tries < 3 && Math.abs(12-dim) > 8){
        dim = parseInt(prompt(message))
        tries++
    }
    if(Math.abs(12 - dim) > 8) dim = 10
    
    blankPlate = [...Array(dim).keys().map(i => [...Array(dim).keys().map(j=>0)])]
    map = structuredClone(blankPlate)
    mask = structuredClone(blankPlate)
    populated = false
    canvas.onclick = clickHandler
    drawMap()
    drawGrid()
}

begin()