Task: Minesweeper game




Go: package main

import (
    "bufio"
    "fmt"
    "math"
    "math/rand"
    "os"
    "strconv"
    "strings"
    "time"
)

type cell struct {
    isMine  bool
    display byte 
}

const lMargin = 4

var (
    grid        [][]cell
    mineCount   int
    minesMarked int
    isGameOver  bool
)

var scanner = bufio.NewScanner(os.Stdin)

func makeGrid(n, m int) {
    if n <= 0 || m <= 0 {
        panic("Grid dimensions must be positive.")
    }
    grid = make([][]cell, n)
    for i := 0; i < n; i++ {
        grid[i] = make([]cell, m)
        for j := 0; j < m; j++ {
            grid[i][j].display = '.'
        }
    }
    min := int(math.Round(float64(n*m) * 0.1)) 
    max := int(math.Round(float64(n*m) * 0.2)) 
    mineCount = min + rand.Intn(max-min+1)
    rm := mineCount
    for rm > 0 {
        x, y := rand.Intn(n), rand.Intn(m)
        if !grid[x][y].isMine {
            rm--
            grid[x][y].isMine = true
        }
    }
    minesMarked = 0
    isGameOver = false
}

func displayGrid(isEndOfGame bool) {
    if !isEndOfGame {
        fmt.Println("Grid has", mineCount, "mine(s),", minesMarked, "mine(s) marked.")
    }
    margin := strings.Repeat(" ", lMargin)
    fmt.Print(margin, " ")
    for i := 1; i <= len(grid); i++ {
        fmt.Print(i)
    }
    fmt.Println()
    fmt.Println(margin, strings.Repeat("-", len(grid)))
    for y := 0; y < len(grid[0]); y++ {
        fmt.Printf("%*d:", lMargin, y+1)
        for x := 0; x < len(grid); x++ {
            fmt.Printf("%c", grid[x][y].display)
        }
        fmt.Println()
    }
}

func endGame(msg string) {
    isGameOver = true
    fmt.Println(msg)
    ans := ""
    for ans != "y" && ans != "n" {
        fmt.Print("Another game (y/n)? : ")
        scanner.Scan()
        ans = strings.ToLower(scanner.Text())
    }
    if scanner.Err() != nil || ans == "n" {
        return
    }
    makeGrid(6, 4)
    displayGrid(false)
}

func resign() {
    found := 0
    for y := 0; y < len(grid[0]); y++ {
        for x := 0; x < len(grid); x++ {
            if grid[x][y].isMine {
                if grid[x][y].display == '?' {
                    grid[x][y].display = 'Y'
                    found++
                } else if grid[x][y].display != 'x' {
                    grid[x][y].display = 'N'
                }
            }
        }
    }
    displayGrid(true)
    msg := fmt.Sprint("You found ", found, " out of ", mineCount, " mine(s).")
    endGame(msg)
}

func usage() {
    fmt.Println("h or ? - this help,")
    fmt.Println("c x y  - clear cell (x,y),")
    fmt.Println("m x y  - marks (toggles) cell (x,y),")
    fmt.Println("n      - start a new game,")
    fmt.Println("q      - quit/resign the game,")
    fmt.Println("where x is the (horizontal) column number and y is the (vertical) row number.\n")
}

func markCell(x, y int) {
    if grid[x][y].display == '?' {
        minesMarked--
        grid[x][y].display = '.'
    } else if grid[x][y].display == '.' {
        minesMarked++
        grid[x][y].display = '?'
    }
}

func countAdjMines(x, y int) int {
    count := 0
    for j := y - 1; j <= y+1; j++ {
        if j >= 0 && j < len(grid[0]) {
            for i := x - 1; i <= x+1; i++ {
                if i >= 0 && i < len(grid) {
                    if grid[i][j].isMine {
                        count++
                    }
                }
            }
        }
    }
    return count
}

func clearCell(x, y int) bool {
    if x >= 0 && x < len(grid) && y >= 0 && y < len(grid[0]) {
        if grid[x][y].display == '.' {
            if !grid[x][y].isMine {
                count := countAdjMines(x, y)
                if count > 0 {
                    grid[x][y].display = string(48 + count)[0]
                } else {
                    grid[x][y].display = ' '
                    clearCell(x+1, y)
                    clearCell(x+1, y+1)
                    clearCell(x, y+1)
                    clearCell(x-1, y+1)
                    clearCell(x-1, y)
                    clearCell(x-1, y-1)
                    clearCell(x, y-1)
                    clearCell(x+1, y-1)
                }
            } else {
                grid[x][y].display = 'x'
                fmt.Println("Kaboom! You lost!")
                return false
            }
        }
    }
    return true
}

func testForWin() bool {
    isCleared := false
    if minesMarked == mineCount {
        isCleared = true
        for x := 0; x < len(grid); x++ {
            for y := 0; y < len(grid[0]); y++ {
                if grid[x][y].display == '.' {
                    isCleared = false
                }
            }
        }
    }
    if isCleared {
        fmt.Println("You won!")
    }
    return isCleared
}

func splitAction(action string) (int, int, bool) {
    fields := strings.Fields(action)
    if len(fields) != 3 {
        return 0, 0, false
    }
    x, err := strconv.Atoi(fields[1])
    if err != nil || x < 1 || x > len(grid) {
        return 0, 0, false
    }
    y, err := strconv.Atoi(fields[2])
    if err != nil || y < 1 || y > len(grid[0]) {
        return 0, 0, false
    }
    return x, y, true
}

func main() {
    rand.Seed(time.Now().UnixNano())
    usage()
    makeGrid(6, 4)
    displayGrid(false)
    for !isGameOver {
        fmt.Print("\n>")
        scanner.Scan()
        action := strings.ToLower(scanner.Text())
        if scanner.Err() != nil || len(action) == 0 {
            continue
        }
        switch action[0] {
        case 'h', '?':
            usage()
        case 'n':
            makeGrid(6, 4)
            displayGrid(false)
        case 'c':
            x, y, ok := splitAction(action)
            if !ok {
                continue
            }
            if clearCell(x-1, y-1) {
                displayGrid(false)
                if testForWin() {
                    resign()
                }
            } else {
                resign()
            }
        case 'm':
            x, y, ok := splitAction(action)
            if !ok {
                continue
            }
            markCell(x-1, y-1)
            displayGrid(false)
            if testForWin() {
                resign()
            }
        case 'q':
            resign()
        }
    }
}




Python: 


gridsize  = (6, 4)
minerange = (0.2, 0.6)


try:
    raw_input
except:
    raw_input = input
    
import random
from itertools import product
from pprint import pprint as pp


def gridandmines(gridsize=gridsize, minerange=minerange):
    xgrid, ygrid = gridsize
    minmines, maxmines = minerange
    minecount = xgrid * ygrid    
    minecount = random.randint(int(minecount*minmines), int(minecount*maxmines))
    grid = set(product(range(xgrid), range(ygrid)))
    mines = set(random.sample(grid, minecount))
    show = {xy:'.' for xy in grid}
    return grid, mines, show

def printgrid(show, gridsize=gridsize):
    xgrid, ygrid = gridsize
    grid = '\n'.join(''.join(show[(x,y)] for x in range(xgrid))
                     for y in range(ygrid))
    print( grid )

def resign(showgrid, mines, markedmines):
    for m in mines:
        showgrid[m] = 'Y' if m in markedmines else 'N'

def clear(x,y, showgrid, grid, mines, markedmines):
    if showgrid[(x, y)] == '.':
        xychar = str(sum(1
                         for xx in (x-1, x, x+1)
                         for yy in (y-1, y, y+1)
                         if (xx, yy) in mines ))
        if xychar == '0': xychar = '.'
        showgrid[(x,y)] = xychar
        for xx in (x-1, x, x+1):
            for yy in (y-1, y, y+1):
                xxyy = (xx, yy)
                if ( xxyy != (x, y)
                     and xxyy in grid
                     and xxyy not in mines | markedmines ):
                    clear(xx, yy, showgrid, grid, mines, markedmines)

if __name__ == '__main__':
    grid, mines, showgrid = gridandmines()
    markedmines = set([])
    print( __doc__ )
    print( '\nThere are %i true mines of fixed position in the grid\n' % len(mines) )
    printgrid(showgrid)
    while markedmines != mines:
        inp = raw_input('m x y/c x y/p/r: ').strip().split()
        if inp:
            if inp[0] == 'm':
                x, y = [int(i)-1 for i in inp[1:3]]
                if (x,y) in markedmines:
                    markedmines.remove((x,y))
                    showgrid[(x,y)] = '.'
                else:
                    markedmines.add((x,y))
                    showgrid[(x,y)] = '?'
            elif inp[0] == 'p':
                printgrid(showgrid)
            elif inp[0] == 'c':
                x, y = [int(i)-1 for i in inp[1:3]]
                if (x,y) in mines | markedmines:
                    print( '\nKLABOOM!! You hit a mine.\n' )
                    resign(showgrid, mines, markedmines)
                    printgrid(showgrid)
                    break
                clear(x,y, showgrid, grid, mines, markedmines)
                printgrid(showgrid)
            elif inp[0] == 'r':
                print( '\nResigning!\n' )
                resign(showgrid, mines, markedmines)
                printgrid(showgrid)
                break
    
    print( '\nYou got %i and missed %i of the %i mines'
           % (len(mines.intersection(markedmines)),
              len(markedmines.difference(mines)),
              len(mines)) )