<?php
define('MINEGRID_WIDTH',  6);
define('MINEGRID_HEIGHT', 4);

define('MINESWEEPER_NOT_EXPLORED', -1);
define('MINESWEEPER_MINE',         -2);
define('MINESWEEPER_FLAGGED',      -3);
define('MINESWEEPER_FLAGGED_MINE', -4);
define('ACTIVATED_MINE',           -5);

function check_field($field) {
    if ($field === MINESWEEPER_MINE || $field === MINESWEEPER_FLAGGED_MINE) {
        return true;
    }
    else {
        return false;
    }
}

function explore_field($field) {
    if (!isset($_SESSION['minesweeper'][$field])
     || !in_array($_SESSION['minesweeper'][$field],
                  array(MINESWEEPER_NOT_EXPLORED, MINESWEEPER_FLAGGED))) {
        return;
    }

    $mines = 0;

    // Make reference to that long name
    $fields  = &$_SESSION['minesweeper'];

    // @ operator helps avoiding isset()... (it removes E_NOTICEs)

    // left side options
    if ($field % MINEGRID_WIDTH !== 1) {
        $mines += check_field(@$fields[$field - MINEGRID_WIDTH - 1]);
        $mines += check_field(@$fields[$field - 1]);
        $mines += check_field(@$fields[$field + MINEGRID_WIDTH - 1]);
    }

    // bottom and top
    $mines += check_field(@$fields[$field - MINEGRID_WIDTH]);
    $mines += check_field(@$fields[$field + MINEGRID_WIDTH]);

    // right side options
    if ($field % MINEGRID_WIDTH !== 0) {
        $mines += check_field(@$fields[$field - MINEGRID_WIDTH + 1]);
        $mines += check_field(@$fields[$field + 1]);
        $mines += check_field(@$fields[$field + MINEGRID_WIDTH + 1]);
    }

    $fields[$field] = $mines;

    if ($mines === 0) {
        if ($field % MINEGRID_WIDTH !== 1) {
            explore_field($field - MINEGRID_WIDTH - 1);
            explore_field($field - 1);
            explore_field($field + MINEGRID_WIDTH - 1);
        }

        explore_field($field - MINEGRID_WIDTH);
        explore_field($field + MINEGRID_WIDTH);

        if ($field % MINEGRID_WIDTH !== 0) {
            explore_field($field - MINEGRID_WIDTH + 1);
            explore_field($field + 1);
            explore_field($field + MINEGRID_WIDTH + 1);
        }
    }
}

session_start(); // will start session storage

if (!isset($_SESSION['minesweeper'])) {
    // Fill grid with not explored tiles
    $_SESSION['minesweeper'] = array_fill(1,
                                         MINEGRID_WIDTH * MINEGRID_HEIGHT,
                                         MINESWEEPER_NOT_EXPLORED);

    // Generate random number of mines between 0.1 and 0.2
    $number_of_mines = (int) mt_rand(0.1 * MINEGRID_WIDTH * MINEGRID_HEIGHT,
                                     0.2 * MINEGRID_WIDTH * MINEGRID_HEIGHT);

    // generate mines randomly
    $random_keys = array_rand($_SESSION['minesweeper'], $number_of_mines);

    foreach ($random_keys as $key) {
        $_SESSION['minesweeper'][$key] = MINESWEEPER_MINE;
    }

    // to make calculations shorter use SESSION variable to store the result
    $_SESSION['numberofmines'] = $number_of_mines;
}

if (isset($_GET['explore'])) {
    if(isset($_SESSION['minesweeper'][$_GET['explore']])) {
        switch ($_SESSION['minesweeper'][$_GET['explore']]) {
            case MINESWEEPER_NOT_EXPLORED:
                explore_field($_GET['explore']);
                break;
            case MINESWEEPER_MINE:
                $lost = 1;
                $_SESSION['minesweeper'][$_GET['explore']] = ACTIVATED_MINE;
                break;
            default:
                // The tile was discovered already. Ignore it.
                break;
        }
    }
    else {
        die('Tile doesn\'t exist.');
    }
}
elseif (isset($_GET['flag'])) {
    if(isset($_SESSION['minesweeper'][$_GET['flag']])) {
        $tile = &$_SESSION['minesweeper'][$_GET['flag']];
        switch ($tile) {
            case MINESWEEPER_NOT_EXPLORED:
                $tile = MINESWEEPER_FLAGGED;
                break;
            case MINESWEEPER_MINE:
                $tile = MINESWEEPER_FLAGGED_MINE;
                break;
            case MINESWEEPER_FLAGGED:
                $tile = MINESWEEPER_NOT_EXPLORED;
                break;
            case MINESWEEPER_FLAGGED_MINE:
                $tile = MINESWEEPER_MINE;
                break;
            default:
                // This tile shouldn't be flagged. Ignore it.
                break;
        }
    }
    else {
        die('Tile doesn\'t exist.');
    }
}

// Check if the player won...
if (!in_array(MINESWEEPER_NOT_EXPLORED, $_SESSION['minesweeper'])
 && !in_array(MINESWEEPER_FLAGGED,      $_SESSION['minesweeper'])) {
    $won = true;
}
?>
<!DOCTYPE html>
<title>Minesweeper</title>

<?php
    echo "
This field contains $_SESSION[numberofmines] mines.";
?>

<?php
// array_shift() affects array, so we need a copy
$mine_copy = $_SESSION['minesweeper'];

for ($x = 1; $x <= MINEGRID_HEIGHT; $x++) {
    echo '
';
    for ($y = 1; $y <= MINEGRID_WIDTH; $y++) {
        echo '';

        $number = array_shift($mine_copy);
        switch ($number) {
            case MINESWEEPER_FLAGGED:
            case MINESWEEPER_FLAGGED_MINE:
                if (!empty($lost) || !empty($won)) {
                    if ($number === MINESWEEPER_FLAGGED_MINE) {
                        echo '*';
                    }
                    else {
                        echo '.';
                    }
                }
                else {
                    echo '?';
                }
                break;
            case ACTIVATED_MINE:
                echo ':(';
                break;
            case MINESWEEPER_MINE:
            case MINESWEEPER_NOT_EXPLORED:
                // oncontextmenu causes the menu to disappear in
                // Firefox, IE and Chrome

                // In case of Opera, modifying location causes menu
                // to not appear.

                if (!empty($lost)) {
                    if ($number === MINESWEEPER_MINE) {
                        echo '*';
                    }
                    else {
                        echo '.';
                    }
                }
                elseif (!empty($won)) {
                    echo '*';
                }
                else {
                    echo '.';
                }
                break;
            case 0:
                echo '';
                break;
            default:
                echo '', $number, '';
                break;
        }
    }
}
?>

<?php
if (!empty($lost)) {
    unset($_SESSION['minesweeper']);
    echo '
You lost :(. Reboot?';
}
elseif (!empty($won)) {
    unset($_SESSION['minesweeper']);
    echo '
Congratulations. You won :).';
}


# NIL    Hidden: Empty field
# T      Hidden: Mine
# 0-8    Marked: Empty field
# ?      Marked: Mine

(de minesweeper (DX DY Density)
   (default Density 20)
   (setq *Field (make (do DY (link (need DX)))))
   (use (X Y)
      (do (prinl "Number of mines: " (*/ DX DY Density 100))
         (while
            (get *Field
               (setq Y (rand 1 DY))
               (setq X (rand 1 DX)) ) )
         (set (nth *Field Y X) T) ) )
   (showMines) )

(de showMines ()
   (for L *Field
      (for F L
         (prin (if (flg? F) "." F)) )
      (prinl) ) )

(de *NeighborX -1  0 +1 -1  +1 -1  0 +1)
(de *NeighborY -1 -1 -1  0   0 +1 +1 +1)

(de c (X Y)
   (if (=T (get *Field Y X))
      "KLABOOM!! You hit a mine."
      (let Visit NIL
         (recur (X Y)
            (when
               (=0
                  (set (nth *Field Y X)
                     (cnt
                        '((DX DY)
                           (=T (get *Field (+ Y DY) (+ X DX))) )
                        *NeighborX
                        *NeighborY ) ) )
               (mapc
                  '((DX DY)
                     (and
                        (get *Field (inc 'DY Y))
                        (nth @ (inc 'DX X))
                        (not (member (cons DX DY) Visit))
                        (push 'Visit (cons DX DY))
                        (recurse DX DY) ) )
                  *NeighborX
                  *NeighborY ) ) ) )
      (showMines) ) )

(de m (X Y)
   (set (nth *Field Y X) '?)
   (showMines)
   (unless (fish =T *Field)
      "Congratulations! You won!!" ) )


:- use_module(library(clpfd)).

% Play - run the minesweeper game with a specified width and height
play(W,H) :-
	format('
Welcome to prolog minesweeper!
: o X Y  exposes a cell of the grid
: m X Y  marks bombs

Any else to quit.
'),

	make_grid(W, H, Grid),
	!,
	play(Grid),
	!.

play(Grid) :- % win condition is true
	map_grid(won, Grid),
	map_grid(print_cell, Grid),
	writeln('you won!').

play(Grid) :- % lose condition is true
	\+ map_grid(still_playing, Grid),
	map_grid(print_cell, Grid),
	writeln('you hit a bomb!').

play(Grid) :- % stil playing
	map_grid(print_cell, Grid),
	parse_input(Op, X, Y),
	do_op(Op, p(X,Y), Grid, Grid2),
	!,
	play(Grid2).

/* Create a new Grid
 *
 * The grid is created initially as a flat list, and after everything
 * has been populated is converted into a 2 dimensional array.
 */
make_grid(W, H, grid(W,H,MappedCells)) :-
	% create a flat list
	Len is W * H,
	length(Cells, Len),

	% create a list of bombs that is 20% of the grid list
	NBombs is W * H / 5,
	floor(NBombs, NBint),
	format('There are ~w bombs on the grid~n', NBint),
	length(AllBombs, NBint),
	maplist(=('?'), AllBombs),
	% add the bombs to the start of the grid list
	map_bombs_to_cells(Cells, AllBombs, NewC),

	% randomise and convert to a 2D array
	random_permutation(NewC, RCells),
	convert_col(RCells, W, H, CreatedCells),

	% populate the hidden part of the grid with number of bombs next to each cell
	map_grid(adj_bomb(grid(W,H,CreatedCells)), grid(W,H,CreatedCells), grid(W,H,MappedCells)).

% puts the bombs at the start of the flat list before shuffling.
map_bombs_to_cells(C, [], C).
map_bombs_to_cells([_|Ct], [B|Bt], [B|R]) :- map_bombs_to_cells(Ct, Bt, R).

convert_row(T, 0, [], T).
convert_row([H|T], W, [H|R], Rem) :-
	dif(W, 0), succ(W1, W),
	convert_row(T, W1, R, Rem).

convert_col([], _, 0, []).
convert_col(C, W, H, [Row|MoreCells]) :- dif(H, 0), succ(H1, H),
	convert_row(C, W, Row, Rem),
	convert_col(Rem, W, H1, MoreCells).

% determine the number of bombs next to a cell (use mapgrid)
adj_bomb(_, _, _, C, cell('.',C)) :- C =@= '?'.
adj_bomb(Grid, p(X,Y), D, Cell, cell('.',NBombs)) :-
	dif(Cell, '?'),
	findall(p(Ax,Ay), (
		adj(p(X,Y), D, p(Ax,Ay)),
		indomain(Ax), indomain(Ay),
		grid_val_xy(Grid, p(Ax,Ay), Val),
		Val =@= '?'
	), Bombs),
	length(Bombs, NBombs).

% Print the grid (use mapgrid)
print_cell(p(X,_), dim(X,_), cell(C,A), cell(C,A)) :- format("~w~n", C).
print_cell(p(X,_), dim(W,_), cell(C,A), cell(C,A)) :- dif(X,W), format("~w ", C).

% determine if we have lost yet or not (use mapgrid).
still_playing(_,_,cell(A,_),_) :- A \= '*'.

% determine if we have won yet or not (use mapgrid).
won(_,_,cell(N,N),_) :- integer(N).
won(_,_,cell('?','?'),_).

% Operate on all cells in a grid, this is a meta predicate that is
% applied several times throughout the code
map_grid(Goal, G) :- map_grid(Goal, G, G).

map_grid(Goal, grid(W,H,Cells), grid(W,H,OutCells)) :-
	map_grid_col(Cells, 1, dim(W,H), Goal, OutCells).

map_grid_col([], _, _, _, []).
map_grid_col([H|T], Y, D, Goal, [NRow|NCol]) :-
	map_grid_row(H, p(1, Y), D, Goal, NRow),
	succ(Y, Y1),
	map_grid_col(T, Y1, D, Goal, NCol).

map_grid_row([], _, _, _, []).
map_grid_row([H|T], p(X, Y), D, Goal, [Cell|R]) :-
	call(Goal, p(X, Y), D, H, Cell),
	succ(X, X1),
	map_grid_row(T, p(X1, Y), D, Goal, R).

% Get a value from the grid by X Y
grid_val_xy(grid(_,_,Cells), p(X,Y), Val) :-
	nth1(Y, Cells, Row),
	nth1(X, Row, Val).

% Set a value on the grid by X Y
grid_set_xy(grid(W,H,Cells), p(X,Y), Val, grid(W,H,NewCells)) :- grid_set_col(Cells, X, Y, Val, NewCells).
grid_set_col([H|T], X, 1, Val, [Row|T]) :- grid_set_row(H, X, Val, Row).
grid_set_col([H|T], X, Y, Val, [H|New]) :- dif(Y, 0), succ(Y1, Y), grid_set_col(T, X, Y1, Val, New).
grid_set_row([_|T], 1, Val, [Val|T]).
grid_set_row([H|T], X, Val, [H|New]) :- dif(X, 0), succ(X1, X), grid_set_row(T, X1, Val, New).

% All coordinates adjacent to an x,y position
adj(p(X,Y), dim(W,H), p(Ax,Ay)) :-

	dif(p(X,Y),p(Ax,Ay)),

	% adjacent X
	Ax in 1..W,
	Xmin #= X-1, Xmax #= X+1,
	Ax in Xmin..Xmax,

	% adjacent Y
	Ay in 1..H,
	Ymin #= Y-1, Ymax #= Y+1,
	Ay in Ymin..Ymax.

% get user operation from input
parse_input(Op, X, Y) :-
	read_line_to_codes(user_input, In),
	maplist(char_code, InChars, In),
	phrase(mine_op(Op, X, Y), InChars, []).

mine_op(mark, X, Y) --> [m], [' '], coords(X, Y).
mine_op(open, X, Y) --> [o], [' '], coords(X, Y).
coords(Xi, Yi) --> number_(X), { number_chars(Xi, X) }, [' '], number_(Y), { number_chars(Yi, Y) }.

number_([D|T]) --> digit(D), number_(T).
number_([D]) --> digit(D).
digit(D) --> [D], { char_type(D, digit) }.

% Do mark operation
do_op(mark, P, G, Ng) :-
	grid_val_xy(G, P, cell(_,A)),
	grid_set_xy(G, P, cell('?',A), Ng).

% Do open operation, opening a bomb
do_op(open, P, G, Ng) :-
	grid_val_xy(G, P, cell(_,'?')),
	grid_set_xy(G, P, cell('*','?'), Ng).

% Do open operation, not a bomb
do_op(open, P, G, Ng) :-
	grid_val_xy(G, P, cell(_,A)),
	dif(A, '?'),
	grid_set_xy(G, P, cell(A,A), Ng1),
	expose_grid(P, Ng1, Ng).

% expose the grid by checking all the adjacent cells and operating
% appropriately
expose_grid(p(X,Y), grid(W,H,Cells), Ng2) :-
	findall(p(Ax,Ay), (
		    adj(p(X,Y), dim(W,H), p(Ax,Ay)),
		    indomain(Ax), indomain(Ay)
		), Coords),
	expose_grid_(Coords, grid(W,H,Cells), Ng2).

expose_grid_([], G, G).

expose_grid_([H|T], G, Ng) :-  % this cell has already been exposed, continue
	grid_val_xy(G, H, cell(A,B)),
	member(A, [B,'?']),
	expose_grid_(T, G, Ng).

expose_grid_([H|T], G, Ng) :- % ignore bombs
	grid_val_xy(G, H, cell(_,'?')),
	expose_grid_(T, G, Ng).

expose_grid_([H|T], G, Ng) :- % is an integer, expose and continue
	grid_val_xy(G, H, cell(_,N)),
	integer(N),
	N #> 0,
	grid_set_xy(G, H, cell(N,N), Ng1),
	expose_grid_(T, Ng1, Ng).

expose_grid_([H|T], G, Ng) :- % is a space, recurse
	grid_val_xy(G, H, cell('.',0)),
	grid_set_xy(G, H, cell(0,0), Ng1),
	expose_grid(H, Ng1, Ng2),
	expose_grid_(T, Ng2, Ng).


Structure cell
  isMine.i
  display.c ;character to displays for cell, one of these {'.', '?', ' ', #)
EndStructure

Global Dim grid.cell(0,0)
Global mineCount, minesMarked, isGameOver

Procedure makeGrid(n, m)
  Protected rm, x, y
  Dim grid.cell(n - 1, m - 1)
  mineCount = n * m * (Random(4) + 2) / 10
  If mineCount < 0: mineCount = 1: EndIf

  For x = 0 To n - 1
    For y = 0 To m - 1
      grid(x, y)\display = '.'
    Next
  Next

  rm = mineCount
  While rm
    x = Random(n - 1)
    y = Random(m - 1)
    If Not grid(x, y)\isMine
      rm - 1: grid(x, y)\isMine = #True
    EndIf
  Wend
  minesMarked = 0
  isGameOver = #False
EndProcedure

Procedure displayGrid(isEndOfGame = #False)
  #lMargin = 4
  Protected x, y, display.s
  If Not isEndOfGame
    PrintN("Grid has " + Str(mineCount) + " mines, " + Str(minesMarked) + " mines marked.")
  EndIf
  PrintN(Space(#lMargin + 1) + ReplaceString(Space(ArraySize(grid(), 1) + 1), " ", "-"))
  For y = 0 To ArraySize(grid(), 2)
    Print(RSet(Str(y + 1), #lMargin, " ") + ":")
    For x = 0 To ArraySize(grid(), 1)
      Print(Chr(grid(x,y)\display))
    Next
    PrintN("")
  Next
EndProcedure

Procedure endGame(msg.s)
  Protected ans.s
  isGameOver = #True
  PrintN(msg): Print("Another game (y/n)?"): ans = Input()
  If LCase(Left(Trim(ans),1)) = "y"
    makeGrid(6, 4)
  EndIf
EndProcedure

Procedure resign()
  Protected x, y, found
  For y = 0 To ArraySize(grid(), 2)
    For x = 0 To ArraySize(grid(), 1)
      With grid(x,y)
        If \isMine
          If \display = '?'
            \display = 'Y'
            found + 1
          ElseIf \display <> 'x'
            \display = 'N'
          EndIf
        EndIf
      EndWith
    Next
  Next
  displayGrid(#True)
  endGame("You found " + Str(found) + " out of " + Str(mineCount) + " mines.")
EndProcedure

Procedure usage()
  PrintN("h or ? - this help,")
  PrintN("c x y  - clear cell (x,y),")
  PrintN("m x y  - marks (toggles) cell (x,y),")
  PrintN("n      - start a new game,")
  PrintN("q      - quit/resign the game,")
  PrintN("where x is the (horizontal) column number and y is the (vertical) row number." + #CRLF$)
EndProcedure

Procedure markCell(x, y)
  If grid(x, y)\display = '?'
    minesMarked - 1: grid(x, y)\display = '.'
  ElseIf grid(x, y)\display = '.'
    minesMarked + 1: grid(x, y)\display = '?'
  EndIf
EndProcedure

Procedure countAdjMines(x, y)
  Protected count, i, j
  For j = y - 1 To y + 1
    If j >= 0 And j <= ArraySize(grid(), 2)
      For i = x - 1 To x + 1
        If i >= 0 And i <= ArraySize(grid(), 1)
          If grid(i, j)\isMine
            count + 1
          EndIf
        EndIf
      Next
    EndIf
  Next

  ProcedureReturn count
EndProcedure

Procedure clearCell(x, y)
  Protected count
  If x >= 0 And x <= ArraySize(grid(), 1) And y >= 0 And y <= ArraySize(grid(), 2)
    If grid(x, y)\display = '.'
      If Not grid(x,y)\isMine
        count = countAdjMines(x, y)
        If count
          grid(x, y)\display = Asc(Str(count))
        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)
        EndIf
      Else
        grid(x, y)\display = 'x'
        PrintN("Kaboom!  You lost!")
        resign()
      EndIf
    EndIf
  EndIf
EndProcedure

Procedure testforwin()
  Protected x, y, isCleared
  If minesMarked = mineCount
    isCleared = #True
    For x = 0 To ArraySize(grid(), 1)
      For y = 0 To ArraySize(grid(), 2)
        If grid(x, y)\display = '.': isCleared = #False: EndIf
      Next
    Next
  EndIf
  If isCleared: endGame("You won!"): EndIf
EndProcedure

If OpenConsole()
  Define action.s
  usage()
  makeGrid(6, 4): displayGrid()
  Repeat
    PrintN(""): Print(">"):  action = Input()
    Select Asc(LCase(Left(action, 1)))
      Case 'h', '?'
        usage()
      Case 'n'
        makeGrid(6, 4): displayGrid()
      Case 'c'
        clearCell(Val(StringField(action, 2, " ")) - 1, Val(StringField(action, 3, " ")) - 1)
        If Not isGameOver: displayGrid(): Else: testforwin(): EndIf
      Case 'm'
        markCell(Val(StringField(action, 2, " ")) - 1, Val(StringField(action, 3, " ")) - 1)
        displayGrid()
        testforwin()
      Case 'q'
        resign()
    EndSelect
  Until isGameOver

  Print(#CRLF$ + #CRLF$ + "Press ENTER to exit"): Input()
  CloseConsole()
EndIf


'''
Minesweeper game.

    There is an n by m grid that has a random number of between 20% to 60%
    of randomly hidden mines that need to be found.

    Positions in the grid are modified by entering their coordinates
    where the first coordinate is horizontal in the grid and the second
    vertical. The top left of the grid is position 1,1; the bottom right is
    at n,m.

    * The total number of mines to be found is shown at the beginning of the
    game.
    * Each mine occupies a single grid point, and its position is initially
    unknown to the player
    * The grid is shown as a rectangle of characters between moves.
    * You are initially shown all grids as obscured, by a single dot '.'
    * You may mark what you think is the position of a mine which will show
    as a '?'
    * You can mark what you think is free space by entering its coordinates.
    :*  If the point is free space then it is cleared, as are any adjacent
    points that are also free space- this is repeated recursively for
    subsequent adjacent free points unless that point is marked as a mine
    or is a mine.
    ::*   Points marked as a mine show as a '?'.
    ::*   Other free points show as an integer count of the number of adjacent
    true mines in its immediate neighbourhood, or as a single space ' ' if the
    free point is not adjacent to any true mines.
    * Of course you loose if you try to clear space that starts on a mine.
    * You win when you have correctly identified all mines.

    When prompted you may:
        Toggle where you think a mine is at position x, y:
          m <x> <y>
        Clear the grid starting at position x, y (and print the result):
          c <x> <y>
        Print the grid so far:
          p
        Resign
          r
    Resigning will first show the grid with an 'N' for unfound true mines, a
    'Y' for found true mines and a '?' for where you marked clear space as a
    mine

'''

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)) )


#lang racket
(require math/array)
;board uses arrays directly, but maintaining an abstraction is nice
(define (board-ref b row col) (array-ref b (vector row col)))
(define (board-rows b) (vector-ref (array-shape b) 0))
(define (board-cols b) (vector-ref (array-shape b) 1))
(define (on-board? b row col)
  (and (<= 0 row (sub1 (board-rows b)))
       (<= 0 col (sub1 (board-cols b)))))
(define (board->lists b) (array->list* b))
;run on adjacent board positions
(define-syntax (for-adj stx)
  (syntax-case stx ()
    [(_ b (r row) (c col) diag? body ...)
     (with-syntax ([is (if (syntax->datum #'diag?) #''(0 0 1 1 1 -1 -1 -1) #''(0 0 1 -1))]
                   [js (if (syntax->datum #'diag?) #''(1 -1 0 -1 1 0 -1 1) #''(1 -1 0 0))])
       #'(for ([i is] [j js])
           (let ([r (+ row i)]
                 [c (+ col j)])
             (when (on-board? b r c)
               body ...))))]))
;mark is either hidden, assume-mine, or clear
;n is int equal to # adj mines or -1 for mine
(struct pos ([mark #:mutable] n) #:transparent)
(define (mine? p) (= (pos-n p) -1))
(define (mine-count b) (apply + (array->list (array-map (λ (p) (if (mine? p) 1 0)) b))))
;hidden0? is needed because only spaces with no mines in them and no mines adjacent
;to them are cleared recursively
(define (hidden0? p)
  (and (symbol=? (pos-mark p) 'hidden)
       (zero? (pos-n p))))
(define (show-pos p)
  (match-let ([(pos m n) p])
    (case m
      [(hidden) "."]
      [(assume-mine) "?"]
      [(clear) (if (zero? n) " " (number->string n))]
      [else (error "illegal mark" m)])))
;put "|" around positions
(define (show-board b)
  (for ([row (board->lists b)])
    (displayln (format "|~a|" (string-join (map show-pos row) "|")))))

;winning = every position is either cleared or a hidden mine
(define (win? b)
  (for*/and ([r (range 0 (board-rows b))]
             [c (range 0 (board-cols b))])
    (let ([p (board-ref b r c)])
      (or (symbol=? (pos-mark p) 'clear)
          (mine? p)))))

(define (init-board rows cols)
  (let ([chance (+ (/ (random) 10) 0.1)]
        ;empty board
        [b (array->mutable-array (build-array (vector rows cols)
                                              (λ (x) (pos 'hidden 0))))])
    ;loop whole board
    (for* ([row (range 0 rows)]
           [col (range 0 cols)])
      (when (< (random) chance)
        ;put a mine
        (array-set! b (vector row col) (pos 'hidden -1))
        ;increment adjacent mine counts unless that adjacent position is a mine
        (for-adj b (r row) (c col) #t
                 (let ([p (board-ref b r c)])
                   (unless (mine? p)
                     (array-set! b (vector r c) (pos 'hidden (add1 (pos-n p)))))))))
    b))

;only clear position if it's not a mine
;only continue recursing when it's a hidden0?
(define (try-clear! p)
  (cond [(mine? p) #f]
        [(hidden0? p) (set-pos-mark! p 'clear) #t]
        [else (set-pos-mark! p 'clear) #f]))

;the following player move functions return boolean where #f = lose, #t = still going
;assuming can never directly lose ((void) == #t from the set!)
;make sure to not allow overwriting an already cleared position
(define (toggle-assume! b row col)
  (let ([p (board-ref b row col)])
    (set-pos-mark! p (case (pos-mark p)
                       [(assume-mine) 'hidden]
                       [(hidden) 'assume-mine]
                       [(clear) 'clear]
                       [else (error "invalid mark" (pos-mark p))]))))

;clearing loses when the chosen position is a mine
;void = #t as far as if works, so no need to return #t
(define (clear! b row col)
  (let ([p (board-ref b row col)])
    (and (not (mine? p))
         ;not a mine, so recursively check adjacents, and maintain list of visited positions
         ;to avoid infinite loops
         (let ([seen '()])
           ;clear the chosen position first, only continuing if it's a 0
           (when (try-clear! p)
             (let clear-adj ([row row] [col col])
               (for-adj b (r row) (c col) #f
                        ;make sure its not seen
                        (when (and (not (member (list r c) seen))
                                   (try-clear! (board-ref b r c)))
                          ;it was cleared, so loop after saving this position as being seen
                          (set! seen (cons (list r c) seen))
                          (clear-adj r c)))))))))

(define assume-string "a")
(define clear-string "c")
;validates input...returns either #f for an error or the move to execute
(define (parse-and-create-move! b s)
  (match (string-split s)
    [(list type row col)
     (let ([row (string->number row)]
           [col (string->number col)])
       (and (number? row)
            (number? col)
            (let ([row (sub1 row)]
                  [col (sub1 col)])
              (and (on-board? b row col)
                   (or (and (string=? type assume-string) (λ () (toggle-assume! b row col)))
                       (and (string=? type clear-string) (λ () (clear! b row col))))))))]
    [else #f]))
(define (run)
  (displayln (string-append "--- Enter one of:\n"
                            (format "--- \"~a <row> <col>\" to clear at (row,col), or~n" clear-string)
                            (format (string-append "--- \"~a <row> <col>\" to flag a possible mine "
                                                   "(or clear a flag) at (row,col).~n")
                                    assume-string)))
  (let ([b (init-board 4 6)])
    (displayln (format "There are ~a mines.~n" (mine-count b)))
    (let run ()
      (show-board b)
      (display "enter move: ")
      ;parse either failed or gave the procedure to execute
      (let ([proc? (parse-and-create-move! b (read-line))])
        ;was the parse successful?
        (if proc?
            ;then run it
            (if (proc?)
                ;didn't lose, so either we won or we're not done
                (if (win? b) (displayln "CLEAR!") (run))
                (displayln "BOOM!"))
            ;parse failed
            (run))))))


enum Tile-Type <Empty Mine>;

class Tile {
    has Tile-Type $.type;
    has $.face is rw;
    method Str { with $!face { ~$!face } else { '.' } }
}

class Field {
    has @.grid;
    has Int $.width;
    has Int $.height;
    has Int $.mine-spots;
    has Int $.empty-spots;

    method new (Int $height, Int $width, Rat $mines-ratio=0.1) {

        my $mine-spots = round $width*$height*$mines-ratio;
        my $empty-spots = $width*$height - $mine-spots;

        my @grid;
        for ^$height X ^$width -> ($y, $x) {
            @grid[$y][$x] = Tile.new(type => Empty);
        }
        for (^$height).pick($mine-spots) Z (^$width).pick($mine-spots) -> ($y, $x) {
            @grid[$y][$x] = Tile.new( type => Mine);
        }
        self.bless(:$height, :$width, :@grid, :$mine-spots, :$empty-spots);
    }

    method open( $y, $x) {
        return if @!grid[$y][$x].face.defined;

        self.end-game("KaBoom") if @!grid[$y][$x].type ~~ Mine;

        my @neighbors = gather do
	    take [$y+.[0],$x+.[1]]
		if 0 <= $y + .[0] < $!height && 0 <= $x + .[1] < $!width
		 for [-1,-1],[+0,-1],[+1,-1],
		     [-1,+0],        [+1,+0],
		     [-1,+1],[+0,+1],[+1,+1];

        my $mines = +@neighbors.grep: { @!grid[.[0]][.[1]].type ~~ Mine };

        $!empty-spots--;
        @!grid[$y][$x].face = $mines || ' ';

        if $mines == 0 {
            self.open(.[0], .[1]) for @neighbors;
        }
        self.end-game("You won") if $!empty-spots == 0;
    }

    method end-game(Str $msg ) {
        for ^$!height X ^$!width -> ($y, $x) {
            @!grid[$y][$x].face = '*' if @!grid[$y][$x].type ~~ Mine
        }
        die $msg;
    }

    method mark ( $y, $x) {
        if !@!grid[$y][$x].face.defined {
            @!grid[$y][$x].face = "⚐";
            $!mine-spots-- if @!grid[$y][$x].type ~~ Mine;
        }
	elsif !@!grid[$y][$x].face eq "⚐" {
            undefine @!grid[$y][$x].face;
            $!mine-spots++ if @!grid[$y][$x].type ~~ Mine;
        }
        self.end-game("You won") if $!mine-spots == 0;
    }

    constant @digs = |('a'..'z') xx *;

    method Str {
        [~] flat '  ', @digs[^$!width], "\n",
	         ' ┌', '─' xx $!width, "┐\n",
	    join '', do for ^$!height -> $y {
	      $y, '│', @!grid[$y][*],   "│\n"; },
	         ' └', '─' xx $!width, '┘';
	}

    method valid ($y, $x) {
        0 <= $y < $!height && 0 <= $x < $!width
    }
}

sub a2n($a) { $a.ord > 64 ?? $a.ord % 32 - 1 !! +$a }

my $f = Field.new(6,10);

loop {
    say ~$f;
    my @w = prompt("[open loc|mark loc|loc]: ").words;
    last unless @w;
    unshift @w, 'open' if @w < 2;
    my ($x,$y) = $0, $1 if @w[1] ~~ /(<alpha>)(<digit>)|$1=<digit>$0=<alpha>/;
    $x = a2n($x);
    given @w[0] {
	when !$f.valid($y,$x) { say "invalid coordinates" }
	when /^o/ { $f.open($y,$x)   }
	when /^m/ { $f.mark($y,$x)   }
	default     { say "invalid cmd" }
    }
    CATCH {
	say "$_: end of game.";
	last;
    }
}

say ~$f;


puts <<EOS
    Minesweeper game.

    There is an n by m grid that has a random number of between 20% to 60%
    of randomly hidden mines that need to be found.

    Positions in the grid are modified by entering their coordinates
    where the first coordinate is horizontal in the grid and the second
    vertical. The top left of the grid is position 1,1; the bottom right is
    at n,m.

    * The total number of mines to be found is shown at the beginning of the
    game.
    * Each mine occupies a single grid point, and its position is initially
    unknown to the player
    * The grid is shown as a rectangle of characters between moves.
    * You are initially shown all grids as obscured, by a single dot '.'
    * You may mark what you think is the position of a mine which will show
    as a '?'
    * You can mark what you think is free space by entering its coordinates.
    :*  If the point is free space then it is cleared, as are any adjacent
    points that are also free space- this is repeated recursively for
    subsequent adjacent free points unless that point is marked as a mine
    or is a mine.
    ::*   Points marked as a mine show as a '?'.
    ::*   Other free points show as an integer count of the number of adjacent
    true mines in its immediate neighbourhood, or as a single space ' ' if the
    free point is not adjacent to any true mines.
    * Of course you loose if you try to clear space that starts on a mine.
    * You win when you have correctly identified all mines.

    When prompted you may:
        Toggle where you think a mine is at position x, y:
          m <x> <y>
        Clear the grid starting at position x, y (and print the result):
          c <x> <y>
        Print the grid so far:
          p
        Quit
          q
    Resigning will first show the grid with an 'N' for unfound true mines, a
    'Y' for found true mines and a '?' for where you marked clear space as a
    mine
EOS

WIDTH, HEIGHT = 6, 4
PCT = 0.15
NUM_MINES = (WIDTH * HEIGHT * PCT).round

def create_mines sx, sy
  arr = Array.new(WIDTH) { Array.new(HEIGHT, false) }
  NUM_MINES.times do
    x, y = rand(WIDTH), rand(HEIGHT)
    # place it if it isn't at (sx, sy) and we haven't already placed a mine
    redo if arr[x][y] or (x == sx and y == sy)
    arr[x][y] = true
  end
  arr
end

def num_marks
  $screen.inject(0) { |sum, row| sum + row.count("?") }
end

def show_grid revealed = false
  if revealed
    puts $mines.transpose.map { |row| row.map { |cell| cell ? "*" : " " }.join(" ") }
  else
    puts "Grid has #{NUM_MINES} mines, #{num_marks} marked."
    puts $screen.transpose.map{ |row| row.join(" ") }
  end
end

SURROUND = [-1,0,1].product([-1,0,1]) - [[0,0]]     # surround 8
def surrounding x, y
  # apply the passed block to each spot around (x, y)
  SURROUND.each do |dx, dy|
    # don't check if we're out of bounds, or at (0,0)
    yield(x+dx, y+dy) if (0...WIDTH).cover?(x+dx) and (0...HEIGHT).cover?(y+dy)
  end
end

def clear_space x, y
  return unless $screen[x][y] == "."
  # check nearby spaces
  count = 0
  surrounding(x, y) { |px, py| count += 1 if $mines[px][py] }
  if count == 0
    $screen[x][y] = " "
    surrounding(x, y) { |px, py| clear_space px, py }
  else
    $screen[x][y] = count.to_s
  end
end

def victory?
  return false if $mines.nil?  # first one, don't need to check
  return false if num_marks != NUM_MINES
  mines_left = NUM_MINES
  WIDTH.times do |x|
    HEIGHT.times do |y|
      mines_left -= 1 if $mines[x][y] and $screen[x][y] == "?"
    end
  end

  mines_left == 0
end

def check_input x, y
  x, y = x.to_i - 1, y.to_i - 1
  [x, y] if (0...WIDTH).cover?(x) and (0...HEIGHT).cover?(y)
end

$mines = nil
$screen = Array.new(WIDTH) { Array.new(HEIGHT, ".") }

puts "Welcome to Minesweeper!"
show_grid

loop do
  print "> "
  action = gets.chomp.downcase

  case action
  when "quit", "exit", "x", "q"
    puts "Bye!"
    break
  when /^m (\d+) (\d+)$/
    # mark this cell
    x, y = check_input $1, $2
    next unless x
    if $screen[x][y] == "."
      # mark it
      $screen[x][y] = "?"
      if victory?
        show_grid
        puts "You win!"
        break
      end
    elsif $screen[x][y] == "?"
      # unmark it
      $screen[x][y] = "."
    end
    show_grid
  when /^c (\d+) (\d+)$/
    x, y = check_input $1, $2
    next unless x
    $mines ||= create_mines(x, y)
    if $mines[x][y]
      puts "You hit a mine!"
      show_grid true
      break
    else
      clear_space x, y
      show_grid
      if victory?
        puts "You win!"
        break
      end
    end
  when "p"
    show_grid
  end
end


extern crate rand;

use std::io;
use std::io::Write;

fn main() {

    use minesweeper::{MineSweeper, GameStatus};

    let mut width = 6;
    let mut height = 4;
    let mut mine_perctg = 10;
    let mut game = MineSweeper::new(width, height, mine_perctg);

    loop {
        let mut command = String::new();

        println!(
            "\n\
             M I N E S W E E P E R\n\
             \n\
             Commands: \n\
             line col            - reveal line,col \n\
             m line col          - mark   line,col \n\
             q                   - quit\n\
             n                   - new game\n\
             n width height perc - new game size and mine percentage\n"
        );

        game.print();
        print!("> ");
        io::stdout().flush().unwrap();
        while let Ok(_) = io::stdin().read_line(&mut command) {
            let mut command_ok = false;
            {
                let values: Vec<&str> = command.trim().split(' ').collect();
                if values.len() == 1 {
                    if values[0] == "q" {
                        println!("Goodbye");
                        return;
                    } else if values[0] == "n" {
                        println!("New game");
                        game = MineSweeper::new(width, height, mine_perctg);
                        command_ok = true;
                    }
                } else if values.len() == 2 {
                    if let (Ok(x), Ok(y)) = (
                        values[0].parse::<usize>(),
                        values[1].parse::<usize>(),
                    )
                    {
                        game.play(x - 1, y - 1);

                        match game.game_status {
                            GameStatus::Won => println!("You won!"),
                            GameStatus::Lost => println!("You lost!"),
                            _ => (),
                        }
                        command_ok = true;
                    }
                } else if values.len() == 3 {
                    if values[0] == "m" {
                        if let (Ok(x), Ok(y)) = (
                            values[1].parse::<usize>(),
                            values[2].parse::<usize>(),
                        )
                        {
                            game.mark(x - 1, y - 1);
                            command_ok = true;
                        }
                    }
                } else if values.len() == 4 {
                    if values[0] == "n" {
                        if let (Ok(new_width), Ok(new_height), Ok(new_mines_perctg)) =
                            (
                                values[1].parse::<usize>(),
                                values[2].parse::<usize>(),
                                values[3].parse::<usize>(),
                            )
                        {
                            width = new_width;
                            height = new_height;
                            mine_perctg = new_mines_perctg;
                            game = MineSweeper::new(width, height, mine_perctg);
                            command_ok = true;
                        }
                    }
                }
            }

            if command_ok {
                game.print();
            } else {
                println!("Invalid command");
            }

            print!("> ");
            io::stdout().flush().unwrap();
            command.clear();
        }
    }
}

pub mod minesweeper {

    pub struct MineSweeper {
        cell: [[Cell; 100]; 100],
        pub game_status: GameStatus,
        mines: usize,
        width: usize,
        height: usize,
        revealed_count: usize,
    }

    #[derive(Copy, Clone)]
    struct Cell {
        content: CellContent,
        mark: Mark,
        revealed: bool,
    }

    #[derive(Copy, Clone)]
    enum CellContent {
        Empty,
        Mine,
        MineNeighbour { count: u8 },
    }

    #[derive(Copy, Clone)]
    enum Mark {
        None,
        Mine,
    }

    pub enum GameStatus {
        InGame,
        Won,
        Lost,
    }

    extern crate rand;

    use std::cmp::max;
    use std::cmp::min;
    use self::rand::Rng;
    use self::CellContent::*;
    use self::GameStatus::*;

    impl MineSweeper {
        pub fn new(width: usize, height: usize, percentage_of_mines: usize) -> MineSweeper {
            let mut game = MineSweeper {
                cell: [[Cell {
                    content: Empty,
                    mark: Mark::None,
                    revealed: false,
                }; 100]; 100],
                game_status: InGame,
                mines: (width * height * percentage_of_mines) / 100,
                width: width,
                height: height,
                revealed_count: 0,
            };
            game.put_mines();
            game.calc_neighbours();
            game
        }

        pub fn play(&mut self, x: usize, y: usize) {
            match self.game_status {
                InGame => {
                    if !self.cell[x][y].revealed {
                        match self.cell[x][y].content {
                            Mine => {
                                self.cell[x][y].revealed = true;
                                self.revealed_count += 1;
                                self.game_status = Lost;
                            }
                            Empty => {
                                self.flood_fill_reveal(x, y);
                                if self.revealed_count + self.mines == self.width * self.height {
                                    self.game_status = Won;
                                }
                            }
                            MineNeighbour { .. } => {
                                self.cell[x][y].revealed = true;
                                self.revealed_count += 1;
                                if self.revealed_count + self.mines == self.width * self.height {
                                    self.game_status = Won;
                                }
                            }
                        }
                    }
                }
                _ => println!("Game has ended"),
            }
        }

        pub fn mark(&mut self, x: usize, y: usize) {
            self.cell[x][y].mark = match self.cell[x][y].mark {
                Mark::None => Mark::Mine,
                Mark::Mine => Mark::None,
            }
        }

        pub fn print(&self) {
            print!("┌");
            for _ in 0..self.width {
                print!("─");
            }
            println!("┐");
            for y in 0..self.height {
                print!("│");
                for x in 0..self.width {
                    self.cell[x][y].print();
                }
                println!("│");
            }
            print!("└");
            for _ in 0..self.width {
                print!("─");
            }
            println!("┘");
        }

        fn put_mines(&mut self) {
            let mut rng = rand::thread_rng();
            for _ in 0..self.mines {
                while let (x, y, true) = (
                    rng.gen::<usize>() % self.width,
                    rng.gen::<usize>() % self.height,
                    true,
                )
                {
                    match self.cell[x][y].content {
                        Mine => continue,
                        _ => {
                            self.cell[x][y].content = Mine;
                            break;
                        }
                    }
                }
            }
        }

        fn calc_neighbours(&mut self) {
            for x in 0..self.width {
                for y in 0..self.height {
                    if !self.cell[x][y].is_bomb() {
                        let mut adjacent_bombs = 0;

                        for i in max(x as isize - 1, 0) as usize..min(x + 2, self.width) {
                            for j in max(y as isize - 1, 0) as usize..min(y + 2, self.height) {
                                adjacent_bombs += if self.cell[i][j].is_bomb() { 1 } else { 0 };
                            }
                        }

                        if adjacent_bombs == 0 {
                            self.cell[x][y].content = Empty;
                        } else {
                            self.cell[x][y].content = MineNeighbour { count: adjacent_bombs };
                        }
                    }
                }
            }
        }

        fn flood_fill_reveal(&mut self, x: usize, y: usize) {
            let mut stack = Vec::<(usize, usize)>::new();
            stack.push((x, y));

            while let Some((i, j)) = stack.pop() {
                if self.cell[i][j].revealed {
                    continue;
                }
                self.cell[i][j].revealed = true;
                self.revealed_count += 1;
                if let Empty = self.cell[i][j].content {
                    for m in max(i as isize - 1, 0) as usize..min(i + 2, self.width) {
                        for n in max(j as isize - 1, 0) as usize..min(j + 2, self.height) {
                            if !self.cell[m][n].is_bomb() && !self.cell[m][n].revealed {
                                stack.push((m, n));
                            }
                        }
                    }
                }
            }
        }
    }

    impl Cell {
        pub fn print(&self) {
            print!(
                "{}",
                if self.revealed {
                    match self.content {
                        Empty => ' ',
                        Mine => '*',
                        MineNeighbour { count } => char::from(count + b'0'),
                    }
                } else {
                    match self.mark {
                        Mark::Mine => '?',
                        Mark::None => '.',
                    }
                }
            );
        }

        pub fn is_bomb(&self) -> bool {
            match self.content {
                Mine => true,
                _ => false,
            }
        }
    }
}


package require Tcl 8.5
fconfigure stdout -buffering none

# Set up the grid and fill it with some mines
proc makeGrid {n m} {
    global grid mine
    unset -nocomplain grid mine
    set grid(size) [list $n $m]
    set grid(shown) 0
    set grid(marked) 0
    for {set j 1} {$j <= $m} {incr j} {
	for {set i 1} {$i <= $n} {incr i} {
	    set grid($i,$j) .
	}
    }
    set squares [expr {$m * $n}]
    set mine(count) [expr {int((rand()*0.4+0.2) * $squares)}]
    for {set count 0} {$count < $mine(count)} {incr count} {
	while 1 {
	    set i [expr {1+int(rand()*$n)}]
	    set j [expr {1+int(rand()*$m)}]
	    if {![info exist mine($i,$j)]} {
		set mine($i,$j) x
		break
	    }
	}
    }
    return $mine(count)
}

# Print out the grid
proc displayGrid {} {
    global grid
    lassign $grid(size) n m
    for {set j 1} {$j <= $m} {incr j} {
	set row "\t"
	for {set i 1} {$i <= $n} {incr i} {
	    append row $grid($i,$j)
	}
	puts $row
    }
}

# Toggle the possible-mine flag on a cell
proc markCell {x y} {
    global grid
    if {![info exist grid($x,$y)]} return
    if {$grid($x,$y) eq "."} {
	set grid($x,$y) "?"
	incr grid(marked)
    } elseif {$grid($x,$y) eq "?"} {
	set grid($x,$y) "."
	incr grid(marked) -1
    }
}

# Helper procedure that iterates over the 9 squares centered on a location
proc foreachAround {x y xv yv script} {
    global grid
    upvar 1 $xv i $yv j
    foreach i [list [expr {$x-1}] $x [expr {$x+1}]] {
	foreach j [list [expr {$y-1}] $y [expr {$y+1}]] {
	    if {[info exist grid($i,$j)]} {uplevel 1 $script}
	}
    }
}

# Reveal a cell; returns if it was a mine
proc clearCell {x y} {
    global grid mine
    if {![info exist grid($x,$y)] || $grid($x,$y) ne "."} {
	return 0; # Do nothing...
    }
    if {[info exist mine($x,$y)]} {
	set grid($x,$y) "!"
	revealGrid
	return 1; # Lose...
    }
    set surround 0
    foreachAround $x $y i j {incr surround [info exist mine($i,$j)]}
    incr grid(shown)
    if {$surround == 0} {
	set grid($x,$y) " "
	foreachAround $x $y i j {clearCell $i $j}
    } else {
	set grid($x,$y) $surround
    }
    return 0
}

# Check the winning condition
proc won? {} {
    global grid mine
    lassign $grid(size) n m
    expr {$grid(shown) + $mine(count) == $n * $m}
}

# Update the grid to show mine locations (marked or otherwise)
proc revealGrid {} {
    global grid mine
    lassign $grid(size) n m
    for {set j 1} {$j <= $m} {incr j} {
	for {set i 1} {$i <= $n} {incr i} {
	    if {![info exist mine($i,$j)]} continue
	    if {$grid($i,$j) eq "."} {
		set grid($i,$j) "x"
	    } elseif {$grid($i,$j) eq "?"} {
		set grid($i,$j) "X"
	    }
	}
    }
}

# The main game loop
proc play {n m} {
    set m [makeGrid $n $m]
    puts "There are $m true mines of fixed position in the grid\n"
    displayGrid
    while 1 {
	puts -nonewline "m x y/c x y/p/r: "
	if {[gets stdin line] < 0} break; # check for eof too!
	switch -nocase -regexp [string trim $line] {
	    {^m\s+\d+\s+\d+$} {
		markCell [lindex $line 1] [lindex $line 2]
	    }
	    {^c\s+\d+\s+\d+$} {
		if {[clearCell [lindex $line 1] [lindex $line 2]]} {
		    puts "KABOOM!"
		    displayGrid
		    break
		} elseif {[won?]} {
		    puts "You win!"
		    displayGrid
		    break
		}
	    }
	    {^p$} {
		displayGrid
	    }
	    {^r$} {
		puts "Resigning..."
		revealGrid
		displayGrid
		break
	    }
	}
    }
}

play 6 4


In your Vbaproject, insert :
- 1 Module
- 1 Class Module (Name it cMinesweeper)


import "/dynamic" for Struct
import "/fmt" for Fmt
import "random" for Random
import "/ioutil" for Input
import "/str" for Str

var Cell = Struct.create("Cell", ["isMine", "display"])

var lMargin = 4
var grid = []
var mineCount = 0
var minesMarked = 0
var isGameOver = false
var rand = Random.new()

var makeGrid = Fn.new { |n, m|
    if ( n <= 0 || m <= 0) Fiber.abort("Grid dimensions must be positive.")
    grid = List.filled(n, null)
    for (i in 0...n) {
        grid[i] = List.filled(m, null)
        for (j in 0...m) grid[i][j] = Cell.new(false, ".")
    }
    var min = (n * m * 0.1).round  // 10% of tiles
    var max = (n * m * 0.2).round  // 20% of tiles
    mineCount = min + rand.int(max - min + 1)
    var rm = mineCount
    while (rm > 0) {
        var x = rand.int(n)
        var y = rand.int(m)
        if (!grid[x][y].isMine) {
            rm = rm - 1
            grid[x][y].isMine = true
        }
    }
    minesMarked = 0
    isGameOver = false
}

var displayGrid = Fn.new { |isEndOfGame|
    if (!isEndOfGame) {
        System.print("Grid has %(mineCount) mine(s), %(minesMarked) mine(s) marked.")
    }
    var margin = " " * lMargin
    System.write("%(margin) ")
    for (i in 1..grid.count) System.write(i)
    System.print()
    System.print("%(margin) %("-" * grid.count)")
    for (y in 0...grid[0].count) {
        Fmt.write("$*d:", lMargin, y+1)
        for (x in 0...grid.count) System.write(grid[x][y].display)
        System.print()
    }
}

var endGame = Fn.new { |msg|
    isGameOver = true
    System.print(msg)
    var ans = Input.option("Another game (y/n)? : ", "ynYN")
    if (ans == "n" || ans == "N") return
    makeGrid.call(6, 4)
    displayGrid.call(false)
}

var resign = Fn.new {
    var found = 0
    for (y in 0...grid[0].count) {
        for (x in 0...grid.count) {
            if (grid[x][y].isMine) {
                if (grid[x][y].display == "?") {
                    grid[x][y].display = "Y"
                    found = found + 1
                } else if (grid[x][y].display != "x") {
                    grid[x][y].display = "N"
                }
            }
        }
    }
    displayGrid.call(true)
    var msg = "You found  %(found), out of %(mineCount) mine(s)."
    endGame.call(msg)
}

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

var markCell = Fn.new { |x, y|
    if (grid[x][y].display == "?") {
        minesMarked = minesMarked - 1
        grid[x][y].display = "."
    } else if (grid[x][y].display == ".") {
        minesMarked = minesMarked + 1
        grid[x][y].display = "?"
    }
}

var countAdjMines = Fn.new { |x, y|
    var count = 0
    for (j in y-1..y+1) {
        if (j >= 0 && j < grid[0].count) {
            for (i in x-1..x+1) {
                if (i >= 0 && i < grid.count) {
                    if (grid[i][j].isMine) count = count + 1
                }
            }
        }
    }
    return count
}

var clearCell // recursive function
clearCell = Fn.new { |x, y|
    if (x >= 0 && x < grid.count && y >= 0 && y < grid[0].count) {
        if (grid[x][y].display == ".") {
            if (!grid[x][y].isMine) {
                var count = countAdjMines.call(x, y)
                if (count > 0) {
                    grid[x][y].display = String.fromByte(48 + count)
                } else {
                    grid[x][y].display = " "
                    clearCell.call(x+1, y)
                    clearCell.call(x+1, y+1)
                    clearCell.call(x, y+1)
                    clearCell.call(x-1, y+1)
                    clearCell.call(x-1, y)
                    clearCell.call(x-1, y-1)
                    clearCell.call(x, y-1)
                    clearCell.call(x+1, y-1)
                }
            } else {
                grid[x][y].display = "x"
                System.print("Kaboom! You lost!")
                return false
            }
        }
    }
    return true
}

var testForWin = Fn.new {
    var isCleared = false
    if (minesMarked == mineCount) {
        isCleared = true
        for (x in 0...grid.count) {
            for (y in 0...grid[0].count) {
                if (grid[x][y].display == ".") isCleared = false
            }
        }
    }
    if (isCleared) System.print("You won!")
    return isCleared
}

var splitAction = Fn.new { |action|
    var fields = action.split(" ").where{ |s| s != "" }.toList
    if (fields.count != 3) return [0, 0, false]
    var x = Num.fromString(fields[1])
    if (x < 1 || x > grid.count) return [0, 0, false]
    var y = Num.fromString(fields[2])
    if (y < 1 || y > grid[0].count) return [0, 0, false]
    return [x, y, true]
}

usage.call()
makeGrid.call(6, 4)
displayGrid.call(false)
while (!isGameOver) {
    var action = Str.lower(Input.text("\n>", 1))
    var first = action[0]
    if (first == "h" || first == "?") {
        usage.call()
    } else if (first == "n") {
        makeGrid.call(6, 4)
        displayGrid.call(false)
    } else if (first == "c") {
        var res = splitAction.call(action)
        if (!res[2]) continue
        var x  = res[0]
        var y  = res[1]
        if (clearCell.call(x-1, y-1)) {
            displayGrid.call(false)
            if (testForWin.call()) resign.call()
        } else {
            resign.call()
        }
    } else if (first == "m") {
        var res = splitAction.call(action)
        if (!res[2]) continue
        var x  = res[0]
        var y  = res[1]
        markCell.call(x-1, y-1)
        displayGrid.call(false)
        if (testForWin.call()) resign.call()
    } else if (first == "q") {
        resign.call()
    } else {
        System.print("Invalid option, try again")
    }
}


V nuggets = Set(0..100)
L(s, n, t) cart_product(0 .. 100 I/ 6,
                        0 .. 100 I/ 9,
                        0 .. 100 I/ 20)
   nuggets.discard(6*s + 9*n + 20*t)

print(max(nuggets))


PROC Main()
  BYTE x,y,z,n
  BYTE ARRAY nuggets(101)

  FOR n=0 TO 100
  DO
    nuggets(n)=0
  OD

  FOR x=0 TO 100 STEP 6
  DO
    FOR y=0 TO 100 STEP 9
    DO
      FOR z=0 TO 100 STEP 20
      DO
        n=x+y+z
        IF n<=100 THEN
          nuggets(n)=1
        FI
      OD
    OD
  OD

  n=100
  DO
    IF nuggets(n)=0 THEN
      PrintF("The largest non McNugget number is %B%E",n)
      EXIT
    ELSEIF n=0 THEN
      PrintE("There is no result")
      EXIT
    ELSE
      n==-1
    FI
  OD
RETURN


with Ada.Text_IO; use Ada.Text_IO;

procedure McNugget is
   Limit : constant                      := 100;
   List  : array (0 .. Limit) of Boolean := (others => False);
   N     : Integer;
begin
   for A in 0 .. Limit / 6 loop
      for B in 0 .. Limit / 9 loop
         for C in 0 .. Limit / 20 loop
            N := A * 6 + B * 9 + C * 20;
            if N <= 100 then
               List (N) := True;
            end if;
         end loop;
      end loop;
   end loop;
   for N in reverse 1 .. Limit loop
      if not List (N) then
         Put_Line ("The largest non McNugget number is:" & Integer'Image (N));
         exit;
      end if;
   end loop;
end McNugget;


BEGIN
    # Solve the McNuggets problem: find the largest n <= 100 for which there #
    # are no non-negative integers x, y, z such that 6x + 9y + 20z = n       #
    INT max nuggets = 100;
    [ 0 : max nuggets ]BOOL sum;
    FOR i FROM LWB sum TO UPB sum DO sum[ i ] := FALSE OD;
    FOR x FROM 0 BY 6 TO max nuggets DO
        FOR y FROM x BY 9 TO max nuggets DO
            FOR z FROM y BY 20 TO max nuggets DO
                sum[ z ] := TRUE
            OD # z #
        OD # y #
    OD # x # ;
    # show the highest number that cannot be formed                          #
    INT largest := -1;
    FOR i FROM UPB sum BY -1 TO LWB sum WHILE sum[ largest := i ] DO SKIP OD;
    print( ( "The largest non McNugget number is: "
           , whole( largest, 0 )
           , newline
           )
         )
END


use AppleScript version "2.4"
use framework "Foundation"
use scripting additions

on run
    set setNuggets to mcNuggetSet(100, 6, 9, 20)

    script isMcNugget
        on |λ|(x)
            setMember(x, setNuggets)
        end |λ|
    end script
    set xs to dropWhile(isMcNugget, enumFromThenTo(100, 99, 1))

    set setNuggets to missing value -- Clear ObjC pointer value
    if 0 < length of xs then
        item 1 of xs
    else
        "No unreachable quantities in this range"
    end if
end run

-- mcNuggetSet :: Int -> Int -> Int -> Int -> ObjC Set
on mcNuggetSet(n, mcx, mcy, mcz)
    set upTo to enumFromTo(0)
    script fx
        on |λ|(x)
            script fy
                on |λ|(y)
                    script fz
                        on |λ|(z)
                            set v to sum({mcx * x, mcy * y, mcz * z})
                            if 101 > v then
                                {v}
                            else
                                {}
                            end if
                        end |λ|
                    end script
                    concatMap(fz, upTo's |λ|(n div mcz))
                end |λ|
            end script
            concatMap(fy, upTo's |λ|(n div mcy))
        end |λ|
    end script
    setFromList(concatMap(fx, upTo's |λ|(n div mcx)))
end mcNuggetSet

-- GENERIC FUNCTIONS ----------------------------------------------------

-- concatMap :: (a -> [b]) -> [a] -> [b]
on concatMap(f, xs)
    set lng to length of xs
    set acc to {}
    tell mReturn(f)
        repeat with i from 1 to lng
            set acc to acc & |λ|(item i of xs, i, xs)
        end repeat
    end tell
    return acc
end concatMap

-- drop :: Int -> [a] -> [a]
-- drop :: Int -> String -> String
on drop(n, xs)
    set c to class of xs
    if c is not script then
        if c is not string then
            if n < length of xs then
                items (1 + n) thru -1 of xs
            else
                {}
            end if
        else
            if n < length of xs then
                text (1 + n) thru -1 of xs
            else
                ""
            end if
        end if
    else
        take(n, xs) -- consumed
        return xs
    end if
end drop

-- dropWhile :: (a -> Bool) -> [a] -> [a]
-- dropWhile :: (Char -> Bool) -> String -> String
on dropWhile(p, xs)
    set lng to length of xs
    set i to 1
    tell mReturn(p)
        repeat while i ≤ lng and |λ|(item i of xs)
            set i to i + 1
        end repeat
    end tell
    drop(i - 1, xs)
end dropWhile

-- enumFromThenTo :: Int -> Int -> Int -> [Int]
on enumFromThenTo(x1, x2, y)
    set xs to {}
    repeat with i from x1 to y by (x2 - x1)
        set end of xs to i
    end repeat
    return xs
end enumFromThenTo

-- enumFromTo :: Int -> Int -> [Int]
on enumFromTo(m)
    script
        on |λ|(n)
            if m ≤ n then
                set lst to {}
                repeat with i from m to n
                    set end of lst to i
                end repeat
                return lst
            else
                return {}
            end if
        end |λ|
    end script
end enumFromTo

-- foldl :: (a -> b -> a) -> a -> [b] -> a
on foldl(f, startValue, xs)
    tell mReturn(f)
        set v to startValue
        set lng to length of xs
        repeat with i from 1 to lng
            set v to |λ|(v, item i of xs, i, xs)
        end repeat
        return v
    end tell
end foldl

-- Lift 2nd class handler function into 1st class script wrapper
-- mReturn :: First-class m => (a -> b) -> m (a -> b)
on mReturn(f)
    if class of f is script then
        f
    else
        script
            property |λ| : f
        end script
    end if
end mReturn

-- sum :: [Num] -> Num
on sum(xs)
    script add
        on |λ|(a, b)
            a + b
        end |λ|
    end script

    foldl(add, 0, xs)
end sum

-- NB All names of NSMutableSets should be set to *missing value*
-- before the script exits.
-- ( scpt files can not be saved if they contain ObjC pointer values )
-- setFromList :: Ord a => [a] -> Set a
on setFromList(xs)
    set ca to current application
    ca's NSMutableSet's ¬
        setWithArray:(ca's NSArray's arrayWithArray:(xs))
end setFromList

-- setMember :: Ord a => a -> Set a -> Bool
on setMember(x, objcSet)
    missing value is not (objcSet's member:(x))
end setMember


nonMcNuggets: function [lim][
    result: new 0..lim

    loop range.step:6 1 lim 'x [
        loop range.step:9 1 lim 'y [
            loop range.step:20 1 lim 'z
                -> 'result -- sum @[x y z]
        ]
    ]

    return result
]

print max nonMcNuggets 100


# syntax: GAWK -f MCNUGGETS_PROBLEM.AWK
# converted from Go
BEGIN {
    limit = 100
    for (a=0; a<=limit; a+=6) {
      for (b=a; b<=limit; b+=9) {
        for (c=b; c<=limit; c+=20) {
          arr[c] = 1
        }
      }
    }
    for (i=limit; i>=0; i--) {
      if (!arr[i]+0) {
        printf("%d\n",i)
        break
      }
    }
    exit(0)
}


10 DEFINT A-Z: DIM F(100)
20 FOR A=0 TO 100 STEP 6
30 FOR B=A TO 100 STEP 9
40 FOR C=B TO 100 STEP 20
50 F(C)=-1
60 NEXT C,B,A
70 FOR A=100 TO 0 STEP -1
80 IF NOT F(A) THEN PRINT A: END
90 NEXT A


get "libhdr"
manifest $( limit = 100 $)

let start() be
$(  let flags = vec limit
    for i = 0 to limit do flags!i := false

    for a = 0 to limit by 6
        for b = a to limit by 9
            for c = b to limit by 20
                do flags!c := true

    for i = limit to 0 by -1
        unless flags!i
        $(  writef("Maximum non-McNuggets number: %N.*N", i)
            finish
        $)
$)


100 ((↕⊣)(⌈´⊣×⊣¬∘∊⥊∘⊢)(<⊢)(+´×)¨(↕⌊∘÷)) 6‿9‿20


#include <stdio.h>

int
main() {
    int max = 0, i = 0, sixes, nines, twenties;

loopstart: while (i < 100) {
        for (sixes = 0; sixes*6 < i; sixes++) {
            if (sixes*6 == i) {
                i++;
                goto loopstart;
            }

            for (nines = 0; nines*9 < i; nines++) {
                if (sixes*6 + nines*9 == i) {
                    i++;
                    goto loopstart;
                }

                for (twenties = 0; twenties*20 < i; twenties++) {
                    if (sixes*6 + nines*9 + twenties*20 == i) {
                        i++;
                        goto loopstart;
                    }
                }
            }
        }
        max = i;
        i++;
    }

    printf("Maximum non-McNuggets number is %d\n", max);

    return 0;
}


using System;

public class McNuggets
{
   public static void Main()
   {
      bool[] isMcNuggetNumber = new bool[101];

      for (int x = 0; x <= 100/6; x++)
      {
         for (int y = 0; y <= 100/9; y++)
         {
            for (int z = 0; z <= 100/20; z++)
            {
               int mcNuggetNumber = x*6 + y*9 + z*20;
               if (mcNuggetNumber <= 100)
               {
                  isMcNuggetNumber[mcNuggetNumber] = true;
               }
            }
         }
      }

      for (int mnnCheck = isMcNuggetNumber.Length-1; mnnCheck >= 0; mnnCheck--)
      {
         if (!isMcNuggetNumber[mnnCheck])
         {
            Console.WriteLine("Largest non-McNuggett Number less than 100: " + mnnCheck.ToString());
            break;
         }
      }
   }
}


(defn cart [colls]
  (if (empty? colls)
    '(())
    (for [more (cart (rest colls))
          x (first colls)]
      (cons x more))))

(defn nuggets [[n6 n9 n20]] (+ (* 6 n6) (* 9 n9) (* 20 n20)))

(let [possible (distinct (map nuggets (cart (map range [18 13 6]))))
      mcmax (apply max (filter (fn [x] (not-any? #{x} possible)) (range 101)))]
  (printf "Maximum non-McNuggets number is %d\n" mcmax))


% Recursive nugget iterator.
% This yields all the nugget numbers of the given box sizes from start to max.
gen_nuggets = iter (start, max: int, sizes: sequence[int]) yields (int)
    si = sequence[int]
    if si$empty(sizes) then
        yield(start)
    else
        for i: int in int$from_to_by(start, max, si$bottom(sizes)) do
            for j: int in gen_nuggets(i, max, si$reml(sizes)) do
                yield(j)
            end
        end
    end
end gen_nuggets

start_up = proc ()
    max = 100
    ab = array[bool]
    po: stream := stream$primary_output()
    nuggets: ab := ab$fill(0,max+1,false)

    for nugget: int in gen_nuggets(0, max, sequence[int]$[6,9,20]) do
        nuggets[nugget] := true
    end

    maxn: int
    for i: int in ab$indexes(nuggets) do
        if ~nuggets[i] then maxn := i end
    end

    stream$putl(po, "Maximum non-McNuggets number: " || int$unparse(maxn))
end start_up


       IDENTIFICATION DIVISION.
       PROGRAM-ID.  MCNUGGETS.

       DATA DIVISION.
       WORKING-STORAGE SECTION.
       01 NUGGETS.
          03 NUGGET-FLAGS     PIC X OCCURS 100 TIMES.
             88 IS-NUGGET     VALUE 'X'.

       01 A                   PIC 999.
       01 B                   PIC 999.
       01 C                   PIC 999.

       PROCEDURE DIVISION.
       BEGIN.
           MOVE SPACES TO NUGGETS.
           PERFORM A-LOOP VARYING A FROM 0 BY 6
               UNTIL A IS GREATER THAN 100.
           MOVE 100 TO A.

       FIND-LARGEST.
           IF IS-NUGGET(A), SUBTRACT 1 FROM A, GO TO FIND-LARGEST.
           DISPLAY 'Largest non-McNugget number: ', A.
           STOP RUN.

       A-LOOP.
           PERFORM B-LOOP VARYING B FROM A BY 9
               UNTIL B IS GREATER THAN 100.

       B-LOOP.
           PERFORM C-LOOP VARYING C FROM B BY 20
               UNTIL C IS GREATER THAN 100.

       C-LOOP.
           IF C IS NOT EQUAL TO ZERO, MOVE 'X' TO NUGGET-FLAGS(C).


0010 limit#:=100
0020 DIM nugget#(0:limit#)
0030 FOR a#:=0 TO limit# STEP 6 DO
0040   FOR b#:=a# TO limit# STEP 9 DO
0050     FOR c#:=b# TO limit# STEP 20 DO nugget#(c#):=TRUE
0060   ENDFOR b#
0070 ENDFOR a#
0080 FOR i#:=limit# TO 0 STEP -1 DO
0090   IF NOT nugget#(i#) THEN
0100     PRINT "Maximum non-McNuggets number: ",i#
0110     END
0120   ENDIF
0130 ENDFOR i#


include "cowgol.coh";
const LIMIT := 100;

var flags: uint8[LIMIT+1];
MemZero(&flags[0], @bytesof flags);

var a: @indexof flags;
var b: @indexof flags;
var c: @indexof flags;

a := 0;
while a <= LIMIT loop
    b := a;
    while b <= LIMIT loop
        c := b;
        while c <= LIMIT loop
            flags[c] := 1;
            c := c + 20;
        end loop;
        b := b + 9;
    end loop;
    a := a + 6;
end loop;

a := LIMIT;
loop
    if flags[a] == 0 then
        print("Maximum non-McNuggets number: ");
        print_i32(a as uint32);
        print_nl();
        break;
    end if;
    a := a - 1;
end loop;


import 'dart:math';
main() {
  var nuggets = List<int>.generate(101, (int index) => index);
  for (int small in List<int>.generate((100 ~/ (6 + 1)), (int index) => index)) {
    for (int medium in List<int>.generate((100 ~/ (9 + 1)), (int index) => index)) {
      for (int large in List<int>.generate((100 ~/ (20 + 1)), (int index) => index)) {
        nuggets.removeWhere((element) => element == 6 * small + 9 * medium + 20 * large);
      }
    }
  }
  print('Largest non-McNuggets number: ${nuggets.reduce(max).toString() ?? 'none'}.');
}


proc nonrec main() void:
    byte LIMIT = 100;
    [LIMIT+1] bool nugget;
    byte a, b, c;

    for a from 0 upto LIMIT do
        nugget[a] := false
    od;

    for a from 0 by 6 upto LIMIT do
        for b from a by 9 upto LIMIT do
            for c from b by 20 upto LIMIT do
                nugget[c] := true
            od
        od
    od;

    a := LIMIT;
    while nugget[a] do a := a - 1 od;
    writeln("Maximum non-McNuggets number: ", a)
corp


func mcnugget(limit) {
    var sv = Array.Empty(limit + 1, false)
    for s in 0^6..limit {
        for n in s^9..limit {
            for t in n^20..limit {
                sv[t] = true
            }
        }
    }
    for i in limit^-1..0 {
        if !sv[i] {
            print("Maximum non-McNuggets number is \(i)")
            return
        }
    }
}

mcnugget(100)


defmodule Mcnugget do
  def solve(limit) do
    0..limit
    |> MapSet.new()
    |> MapSet.difference(
      for(
        x <- 0..limit,
        y <- 0..limit,
        z <- 0..limit,
        Integer.mod(x, 6) == 0,
        Integer.mod(y, 9) == 0,
        Integer.mod(z, 20) == 0,
        x + y + z <= limit,
        into: MapSet.new(),
        do: x + y + z
      )
    )
    |> Enum.max()
  end
end

Mcnugget.solve(100) |> IO.puts


// McNuggets. Nigel Galloway: October 28th., 2018
let fN n g = Seq.initInfinite(fun ng->ng*n+g)|>Seq.takeWhile(fun n->n<=100)
printfn "%d" (Set.maxElement(Set.difference (set[1..100]) (fN 20 0|>Seq.collect(fun n->fN 9 n)|>Seq.collect(fun n->fN 6 n)|>Set.ofSeq)))


USING: backtrack kernel math.ranges prettyprint sequences sets ;
101 <iota> [ 0 6 9 20 [ 100 swap <range> amb-lazy ] [email protected] ] bag-of diff last .


Dim As Integer l(100), a, b, c, n
For a = 0 To 100/6
    For b =  0 To 100/9
        For c = 0 To 100/20
            n = a*6 + b*9 + c*20
            If n <= 100 Then l(n) = true
        Next c
    Next b
Next a
For n = 100 To 1 Step -1
    If l(n) = false Then Print "El mayor número que no sea McNugget es:"; n: Exit For
Next n
End


package main

import "fmt"

func mcnugget(limit int) {
    sv := make([]bool, limit+1) // all false by default
    for s := 0; s <= limit; s += 6 {
        for n := s; n <= limit; n += 9 {
            for t := n; t <= limit; t += 20 {
                sv[t] = true
            }
        }
    }
    for i := limit; i >= 0; i-- {
        if !sv[i] {
            fmt.Println("Maximum non-McNuggets number is", i)
            return
        }
    }
}

func main() {
    mcnugget(100)
}


import Data.Set (Set, fromList, member)

gaps :: [Int]
gaps = dropWhile (`member` mcNuggets) [100,99 .. 1]

mcNuggets :: Set Int
mcNuggets =
  let size = enumFromTo 0 . quot 100
  in fromList $
     size 6 >>=
     \x ->
        size 9 >>=
        \y ->
           size 20 >>=
           \z ->
              let v = sum [6 * x, 9 * y, 20 * z]
              in [ v
                 | 101 > v ]

main :: IO ()
main =
  print $
  case gaps of
    x:_ -> show x
    []  -> "No unreachable quantities found ..."


public class McNuggets {

    public static void main(String... args) {
        int[] SIZES = new int[] { 6, 9, 20 };
        int MAX_TOTAL = 100;
        // Works like Sieve of Eratosthenes
        int numSizes = SIZES.length;
        int[] counts = new int[numSizes];
        int maxFound = MAX_TOTAL + 1;
        boolean[] found = new boolean[maxFound];
        int numFound = 0;
        int total = 0;
        boolean advancedState = false;
        do {
            if (!found[total]) {
                found[total] = true;
                numFound++;
            }

            // Advance state
            advancedState = false;
            for (int i = 0; i < numSizes; i++) {
                int curSize = SIZES[i];
                if ((total + curSize) > MAX_TOTAL) {
                    // Reset to zero and go to the next box size
                    total -= counts[i] * curSize;
                    counts[i] = 0;
                }
                else {
                    // Adding a box of this size still keeps the total at or below the maximum
                    counts[i]++;
                    total += curSize;
                    advancedState = true;
                    break;
                }
            }

        } while ((numFound < maxFound) && advancedState);

        if (numFound < maxFound) {
            // Did not find all counts within the search space
            for (int i = MAX_TOTAL; i >= 0; i--) {
                if (!found[i]) {
                    System.out.println("Largest non-McNugget number in the search space is " + i);
                    break;
                }
            }
        }
        else {
            System.out.println("All numbers in the search space are McNugget numbers");
        }

        return;
    }
}


(() => {
    'use strict';

    // main :: IO ()
    const main = () => {
        const
            size = n => enumFromTo(0)(
                quot(100, n)
            ),
            nuggets = new Set(
                size(6).flatMap(
                    x => size(9).flatMap(
                        y => size(20).flatMap(
                            z => {
                                const v = sum([6 * x, 9 * y, 20 * z]);
                                return 101 > v ? (
                                    [v]
                                ) : [];
                            }
                        ),
                    )
                )
            ),
            xs = dropWhile(
                x => nuggets.has(x),
                enumFromThenTo(100, 99, 1)
            );

        return 0 < xs.length ? (
            xs[0]
        ) : 'No unreachable quantities found in this range';
    };

    // GENERIC FUNCTIONS ----------------------------------

    // dropWhile :: (a -> Bool) -> [a] -> [a]
    const dropWhile = (p, xs) => {
        const lng = xs.length;
        return 0 < lng ? xs.slice(
            until(
                i => i === lng || !p(xs[i]),
                i => 1 + i,
                0
            )
        ) : [];
    };

    // enumFromThenTo :: Int -> Int -> Int -> [Int]
    const enumFromThenTo = (x1, x2, y) => {
        const d = x2 - x1;
        return Array.from({
            length: Math.floor(y - x2) / d + 2
        }, (_, i) => x1 + (d * i));
    };

    // ft :: Int -> Int -> [Int]
    const enumFromTo = m => n =>
        Array.from({
            length: 1 + n - m
        }, (_, i) => m + i);

    // quot :: Int -> Int -> Int
    const quot = (n, m) => Math.floor(n / m);

    // sum :: [Num] -> Num
    const sum = xs => xs.reduce((a, x) => a + x, 0);

    // until :: (a -> Bool) -> (a -> a) -> a -> a
    const until = (p, f, x) => {
        let v = x;
        while (!p(v)) v = f(v);
        return v;
    };

    // MAIN ---
    return console.log(
        main()
    );
})();


[
 [range(18) as $n6  |
  range(13) as $n9  |
  range(6)  as $n20 |
  ($n6 * 6 + $n9 * 9 + $n20 * 20)] |
 unique |
 . as $possible |
 range(101) |
 . as $n |
 select($possible|contains([$n])|not)
] |
max


function mcnuggets(max)
    b = BitSet(1:max)
    for i in 0:6:max, j in 0:9:max, k in 0:20:max
        delete!(b, i + j + k)
    end
    maximum(b)
end

println(mcnuggets(100))


// Version 1.2.71

fun mcnugget(limit: Int) {
    val sv = BooleanArray(limit + 1)  // all false by default
    for (s in 0..limit step 6)
        for (n in s..limit step 9)
            for (t in n..limit step 20) sv[t] = true

    for (i in limit downTo 0) {
        if (!sv[i]) {
            println("Maximum non-McNuggets number is $i")
            return
        }
    }
}

fun main(args: Array<String>) {
    mcnugget(100)
}


100 CLEAR
110 DIM a(100)
120 FOR a=0 TO 100/6
130   FOR b=0 TO 100/9
140     FOR c=0 TO 100/20
150       n=a*6+b*9+c*20
160       IF n<=100 THEN a(n)=1
170     NEXT c
180   NEXT b
190 NEXT a
200 FOR n=0 TO 100
210   IF a(n)=0 THEN l=n
220 NEXT n
230 PRINT"The Largest non McNugget number is:";l
240 END


function range(A,B)
    return function()
        return coroutine.wrap(function()
            for i = A, B do coroutine.yield(i) end
        end)
    end
end

function filter(stream, f)
    return function()
        return coroutine.wrap(function()
            for i in stream() do
                if f(i) then coroutine.yield(i) end
            end
        end)
    end
end

function triple(s1, s2, s3)
    return function()
        return coroutine.wrap(function()
            for x in s1() do
                for y in s2() do
                    for z in s3() do
                        coroutine.yield{x,y,z}
                    end
                end
            end
        end)
    end
end

function apply(f, stream)
    return function()
        return coroutine.wrap(function()
            for T in stream() do
                coroutine.yield(f(table.unpack(T)))
            end
        end)
    end
end

function exclude(s1, s2)
    local exlusions = {} for x in s1() do exlusions[x] = true end
    return function()
        return coroutine.wrap(function()
            for x in s2() do
                if not exlusions[x] then
                    coroutine.yield(x)
                end
            end
        end)
    end
end

function maximum(stream)
    local M = math.mininteger
    for x in stream() do
        M = math.max(M, x)
    end
    return M
end

local N = 100
local A, B, C = 6, 9, 20

local Xs = filter(range(0, N), function(x) return x  % A == 0 end)
local Ys = filter(range(0, N), function(x) return x  % B == 0 end)
local Zs = filter(range(0, N), function(x) return x  % C == 0 end)
local sum = filter(apply(function(x, y, z) return x + y + z end, triple(Xs, Ys, Zs)), function(x) return x <= N end)

print(maximum(exclude(sum, range(1, N))))


            NORMAL MODE IS INTEGER
            BOOLEAN NUGGET
            DIMENSION NUGGET(101)

            THROUGH CLEAR, FOR I=0, 1, I.G.100
CLEAR       NUGGET(I) = 0B

            THROUGH MARK, FOR A=0, 6, A.G.100
            THROUGH MARK, FOR B=A, 9, B.G.100
            THROUGH MARK, FOR C=B, 20, C.G.100
MARK        NUGGET(C) = 1B

SEARCH      THROUGH SEARCH, FOR I=100, -1, .NOT.NUGGET(I)

            PRINT FORMAT F, I
            VECTOR VALUES F = $29HMAXIMUM NON-MCNUGGET NUMBER: ,I2*$
            END OF PROGRAM


MODULE McNuggets;
FROM InOut IMPORT WriteCard, WriteString, WriteLn;

CONST Max = 100;
VAR a, b, c: CARDINAL;
    nugget: ARRAY [0..Max] OF BOOLEAN;

BEGIN
    FOR a := 0 TO Max DO
        nugget[a] := FALSE;
    END;

    FOR a := 0 TO Max BY 6 DO
        FOR b := a TO Max BY 9 DO
            FOR c := b TO Max BY 20 DO
                nugget[c] := TRUE;
            END;
        END;
    END;

    a := 100;
    REPEAT DEC(a); UNTIL NOT nugget[a];
    WriteString("Maximum non-McNuggets number: ");
    WriteCard(a, 2);
    WriteLn();
END McNuggets.


%McNuggets. Nigel Galloway, August 27th., 2019
var 0..99: n;
constraint forall(x in 0..16,y in 0..11,z in 0..5)(6*x + 9*y + 20*z!=n);
solve maximize n;
output [show(n)]


const Limit = 100

var mcnuggets: array[0..Limit, bool]

for a in countup(0, Limit, 6):
  for b in countup(a, Limit, 9):
    for c in countup(b, Limit, 20):
      mcnuggets[c] = true

for n in countdown(Limit, 0):
  if not mcnuggets[n]:
    echo "The largest non-McNuggets number is: ", n
    break


use ntheory qw/forperm gcd vecmin/;

sub Mcnugget_number {
    my $counts = shift;

    return 'No maximum' if 1 < gcd @$counts;

    my $min = vecmin @$counts;
    my @meals;
    my @min;

    my $a = -1;
    while (1) {
        $a++;
        for my $b (0..$a) {
            for my $c (0..$b) {
                my @s = ($a, $b, $c);
                forperm {
                    $meals[
                        $s[$_[0]] * $counts->[0]
                      + $s[$_[1]] * $counts->[1]
                      + $s[$_[2]] * $counts->[2]
                    ] = 1;
                } @s;
            }
        }
        for my $i (0..$#meals) {
            next unless $meals[$i];
            if ($min[-1] and $i == ($min[-1] + 1)) {
                push @min, $i;
                last if $min == @min
            } else {
                @min = $i;
            }
        }
        last if $min == @min
    }
    $min[0] ? $min[0] - 1 : 0
}

for my $counts ([6,9,20], [6,7,20], [1,3,20], [10,5,18], [5,17,44], [2,4,6], [3,6,15]) {
    print 'Maximum non-Mcnugget number using ' . join(', ', @$counts) . ' is: ' . Mcnugget_number($counts) . "\n"
}


with javascript_semantics
constant limit=100
sequence nuggets = repeat(false,limit+1)
for sixes=0 to limit by 6 do
    for nines=sixes to limit by 9 do
        for twenties=nines to limit by 20 do
            nuggets[twenties+1] = true
        end for
    end for
end for
printf(1,"Maximum non-McNuggets number is %d\n", rfind(false,nuggets)-1)


(de nuggets1 (M)
   (let Lst (range 0 M)
      (for A (range 0 M 6)
         (for B (range A M 9)
            (for C (range B M 20)
               (set (nth Lst (inc C))) ) ) )
      (apply max Lst) ) )


mcnugget: procedure options(main);
    declare nugget(0:100) bit, (a, b, c) fixed;
    do a=0 to 100; nugget(a) = '0'b; end;

    do a=0 to 100 by 6;
        do b=a to 100 by 9;
            do c=b to 100 by 20;
                nugget(c) = '1'b;
            end;
        end;
    end;

    do a=100 to 0 by -1;
        if ^nugget(a) then do;
            put skip list('Maximum non-McNuggets number:', a);
            stop;
        end;
    end;
end mcnugget;


100H:
BDOS: PROCEDURE (FN, ARG); DECLARE FN BYTE, ARG ADDRESS; GO TO 5; END BDOS;
EXIT: PROCEDURE; CALL BDOS(0,0); END EXIT;
PRINT: PROCEDURE (S); DECLARE S ADDRESS; CALL BDOS(9, S); END PRINT;

PRINT$NUMBER: PROCEDURE (N);
    DECLARE S (6) BYTE INITIAL ('...',13,10,'$');
    DECLARE P ADDRESS, (N, C BASED P) BYTE;
    P = .S(3);
DIGIT:
    P = P-1;
    C = N MOD 10 + '0';
    N = N/10;
    IF N>0 THEN GO TO DIGIT;
    CALL PRINT(P);
END PRINT$NUMBER;

DECLARE (A, B, C) BYTE;
DECLARE NUGGET (101) BYTE;

DO A=0 TO 100; NUGGET(A) = 0; END;
DO A=0 TO 100 BY 6;
    DO B=A TO 100 BY 9;
        DO C=B TO 100 BY 20;
            NUGGET(C) = -1;
        END;
    END;
END;

A = 100;
DO WHILE NUGGET(A); A = A-1; END;
CALL PRINT$NUMBER(A);
CALL EXIT;
EOF


$possible = @{}
For ($i=0; $i -lt 18; $i++) {
  For ($j=0; $j -lt 13; $j++) {
    For ( $k=0; $k -lt 6; $k++ ) {
      $possible[ $i*6 + $j*9 + $k*20 ] = $true
    }
  }
}

For ( $n=100; $n -gt 0; $n-- ) {
  If ($possible[$n]) {
    Continue
  }
  Else {
    Break
  }
}
Write-Host "Maximum non-McNuggets number is $n"


>>> from itertools import product
>>> nuggets = set(range(101))
>>> for s, n, t in product(range(100//6+1), range(100//9+1), range(100//20+1)):
	nuggets.discard(6*s + 9*n + 20*t)

>>> max(nuggets)
43
>>>


0 temp put
100 6 / times
  [ i 6 *
    100 9 / times
      [ dup i 9 * +
        100 20 / times
          [ dup i 20 * +
            dup 101 < if
              [ dup bit
                temp take | temp put ]
            drop ]
        drop ]
    drop ]
-1 temp take
101 times
  [ dup i bit & 0 =
    if
      [ nip i swap
        conclude ] ]
drop dup 0 < iff
  [ drop
    say "There are no non-McNugget numbers below 101" ]
else
  [ say "The largest non-McNugget number below 101 is "
    echo ]
char . emit


#lang racket
(apply max (set->list (for*/fold ((s (list->set (range 1 101))))
                                 ((x (in-range 0 101 20))
                                  (y (in-range x 101 9))
                                  (n (in-range y 101 6)))
                        (set-remove s n))))


sub Mcnugget-number (*@counts) {

    return '∞' if 1 < [gcd] @counts;

    my $min = min @counts;
    my @meals;
    my @min;

    for ^Inf -> $a {
        for 0..$a -> $b {
            for 0..$b -> $c {
                ($a, $b, $c).permutations.map: { @meals[ sum $_ Z* @counts ] = True }
            }
        }
        for @meals.grep: so *, :k {
            if @min.tail and @min.tail + 1 == $_ {
                @min.push: $_;
                last if $min == [email protected]min
            } else {
                @min = $_;
            }
        }
        last if $min == [email protected]min
    }
    @min[0] ?? @min[0] - 1 !! 0
}

for (6,9,20), (6,7,20), (1,3,20), (10,5,18), (5,17,44), (2,4,6), (3,6,15) -> $counts {
    put "Maximum non-Mcnugget number using {$counts.join: ', '} is: ",
        Mcnugget-number(|$counts)
}


/*REXX pgm solves the  McNuggets problem:  the largest McNugget number for given meals. */
parse arg y                                      /*obtain optional arguments from the CL*/
if y='' | y=","  then y= 6 9 20                  /*Not specified?  Then use the defaults*/
say 'The number of McNuggets in the serving sizes of: '    space(y)
$=
#= 0                                             /*the Y list must be in ascending order*/
z=.
       do j=1  for words(y);      _= word(y, j)  /*examine  Y  list for dups, neg, zeros*/
       if _==1               then signal done    /*Value ≡ 1?  Then all values possible.*/
       if _<1                then iterate        /*ignore zero and negative # of nuggets*/
       if wordpos(_, $)\==0  then iterate        /*search for duplicate values.         */
            do k=1  for #                        /*   "    "  multiple     "            */
            if _//word($,k)==0  then iterate j   /*a multiple of a previous value, skip.*/
            end   /*k*/
       $= $ _;      #= # + 1;     $.#= _         /*add─►list; bump counter; assign value*/
       end        /*j*/
if #<2                     then signal done      /*not possible, go and tell bad news.  */
_= gcd($)        if _\==1  then signal done      /* "     "       "  "   "    "    "    */
if #==2   then z= $.1 * $.2  -  $.1  -  $.2      /*special case, construct the result.  */
if z\==.  then signal done
h= 0                                             /*construct a theoretical high limit H.*/
       do j=2  for #-1;  _= j-1;       _= $._;       h= max(h, _ * $.j  -  _  -  $.j)
       end   /*j*/
@.=0
       do j=1  for #;    _= $.j                  /*populate the  Jth + Kth   summand.   */
         do a=_  by _  to h;           @.a= 1    /*populate every multiple as possible. */
         end   /*s*/

         do k=1  for h;  if \@.k  then iterate
         s= k + _;       @.s= 1                  /*add two #s;   mark as being possible.*/
         end   /*k*/
       end     /*j*/

       do z=h  by -1  for h  until \@.z          /*find largest integer not summed.     */
       end     /*z*/
say
done:  if z==.  then say 'The largest McNuggets number not possible.'
                else say 'The largest McNuggets number is: '          z
exit                                             /*stick a fork in it,  we're all done. */
/*──────────────────────────────────────────────────────────────────────────────────────*/
gcd: procedure; $=;    do j=1  for arg();  $=$ arg(j);  end;  $= space($)
     parse var $ x $;     x= abs(x);
       do  while $\=='';  parse var $ y $;  y= abs(y);  if y==0  then iterate
         do  until y==0;  parse value  x//y  y   with   y  x;  end
       end;              return x


Nuggets = list(100)

for six = 0 To 100/6
    for nine =  0 To 100/9
        for twenty = 0 To 100/20
            n = six*6 + nine*9 + twenty*20
            If n <= 100 and not (six = 0 and nine = 0 and twenty = 0)
               Nuggets[n] = true
            ok
        next
    next
next

for n = 100 to 1 step -1
    if Nuggets[n] = false
       ? "Maximum non-McNuggets number is: " + n
       exit
    ok
next


def mcnugget(limit)
  sv = (0..limit).to_a

  (0..limit).step(6) do |s|
    (0..limit).step(9) do |n|
      (0..limit).step(20) do |t|
        sv.delete(s + n + t)
      end
    end
  end

  sv.max
end

puts(mcnugget 100)


func maxNugget(limit: Int) -> Int {
  var (max, sixes, nines, twenties, i) = (0, 0, 0, 0, 0)

  mainLoop: while i < limit {
    sixes = 0

    while sixes * 6 < i {
      if sixes * 6 == i {
        i += 1
        continue mainLoop
      }

      nines = 0

      while nines * 9 < i {
        if sixes * 6 + nines * 9 == i {
          i += 1
          continue mainLoop
        }

        twenties = 0

        while twenties * 20 < i {
          if sixes * 6 + nines * 9 + twenties * 20 == i {
            i += 1
            continue mainLoop
          }

          twenties += 1
        }

        nines += 1
      }

      sixes += 1
    }

    max = i
    i += 1
  }

  return max
}

print(maxNugget(limit: 100))


templates largestNonMcNuggetNumber
  @: { largest: 0, mcNuggetNumbers: [1..$+20 -> 0] };
  @.mcNuggetNumbers([6,9,20]): 1..3 -> 1;
  1..$ -> #
  [email protected] !
  when <?([email protected]($) <=0>)> do @.largest: $;
  otherwise @.mcNuggetNumbers([$ + 6, $ + 9, $ + 20]): 1..3 -> 1;
end largestNonMcNuggetNumber

100 -> largestNonMcNuggetNumber -> !OUT::write


possible=()
for (( i=0; i<18; ++i )); do
  for (( j=0; j<13; ++j )); do
    for (( k=0; k<6; ++k )); do
      (( n = i*6 + j*9 + k*20 ))
      if (( n )); then
        possible[n]=1
      fi
    done
  done
done

for (( n=100; n; n-- )); do
  if [[ -n ${possible[n]} ]; then
    continue
  fi
  break
done

printf 'Maximum non-McNuggets number is %d\n' $n


fn mcnugget(limit int) {
    mut sv := []bool{len: limit+1} // all false by default
    for s := 0; s <= limit; s += 6 {
        for n := s; n <= limit; n += 9 {
            for t := n; t <= limit; t += 20 {
                sv[t] = true
            }
        }
    }
    for i := limit; i >= 0; i-- {
        if !sv[i] {
            println("Maximum non-McNuggets number is $i")
            return
        }
    }
}

fn main() {
   mcnugget(100)
}


var mcnugget = Fn.new { |limit|
    var sv = List.filled(limit+1, false)
    var s = 0
    while (s <= limit) {
        var n = s
        while (n <= limit) {
            var t = n
            while (t <= limit) {
                sv[t] = true
                t = t + 20
            }
            n = n + 9
        }
        s = s + 6
    }
    for (i in limit..0) {
        if (!sv[i]) {
            System.print("Maximum non-McNuggets number is %(i)")
            return
        }
    }
}

mcnugget.call(100)


int N, A(101), X, Y, Z;
[for N:= 0 to 100 do A(N):= false;
for X:= 0 to 100/6 do
    for Y:= 0 to 100/9 do
        for Z:= 0 to 100/20 do
            [N:= 6*X + 9*Y + 20*Z;
            if N <= 100 then A(N):= true;
            ];
for N:= 100 downto 0 do
    if A(N) = false then
        [IntOut(0, N);
        exit;
        ];
]


with Ada.Text_IO;

with CryptAda.Digests.Message_Digests.MD4;
with CryptAda.Digests.Hashes;
with CryptAda.Pragmatics;
with CryptAda.Utils.Format;

procedure RC_MD4 is
   use CryptAda.Digests.Message_Digests;
   use CryptAda.Digests;
   use CryptAda.Pragmatics;

   function To_Byte_Array (Item : String) return Byte_Array is
      Result : Byte_Array (Item'Range);
   begin
      for I in Result'Range loop
         Result (I) := Byte (Character'Pos (Item (I)));
      end loop;
      return Result;
   end To_Byte_Array;

   Text    : constant String                := "Rosetta Code";
   Bytes   : constant Byte_Array            := To_Byte_Array (Text);
   Handle  : constant Message_Digest_Handle := MD4.Get_Message_Digest_Handle;
   Pointer : constant Message_Digest_Ptr    := Get_Message_Digest_Ptr (Handle);
   Hash    : Hashes.Hash;
begin
   Digest_Start  (Pointer);
   Digest_Update (Pointer, Bytes);
   Digest_End    (Pointer, Hash);

   Ada.Text_IO.Put_Line
     ("""" & Text & """: " & CryptAda.Utils.Format.To_Hex_String (Hashes.Get_Bytes (Hash)));
end RC_MD4;


str := "Rosetta Code"
MsgBox, % "String:`n" (str) "`n`nMD4:`n" MD4(str)

; MD4 ===============================================================================
MD4(string, encoding = "utf-8")
{
    return CalcStringHash(string, 0x8002, encoding)
}

; CalcAddrHash ======================================================================
CalcAddrHash(addr, length, algid, byref hash = 0, byref hashlength = 0)
{
    static h := [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, "A", "B", "C", "D", "E", "F"]
    static b := h.minIndex()
    o := ""
    if (DllCall("advapi32\CryptAcquireContext", "Ptr*", hProv, "Ptr", 0, "Ptr", 0, "UInt", 24, "UInt", 0xF0000000))
    {
        if (DllCall("advapi32\CryptCreateHash", "Ptr", hProv, "UInt", algid, "UInt", 0, "UInt", 0, "Ptr*", hHash))
        {
            if (DllCall("advapi32\CryptHashData", "Ptr", hHash, "Ptr", addr, "UInt", length, "UInt", 0))
            {
                if (DllCall("advapi32\CryptGetHashParam", "Ptr", hHash, "UInt", 2, "Ptr", 0, "UInt*", hashlength, "UInt", 0))
                {
                    VarSetCapacity(hash, hashlength, 0)
                    if (DllCall("advapi32\CryptGetHashParam", "Ptr", hHash, "UInt", 2, "Ptr", &hash, "UInt*", hashlength, "UInt", 0))
                    {
                        loop, % hashlength
                        {
                            v := NumGet(hash, A_Index - 1, "UChar")
                            o .= h[(v >> 4) + b] h[(v & 0xf) + b]
                        }
                    }
                }
            }
            DllCall("advapi32\CryptDestroyHash", "Ptr", hHash)
        }
        DllCall("advapi32\CryPtreleaseContext", "Ptr", hProv, "UInt", 0)
    }
    return o
}

; CalcStringHash ====================================================================
CalcStringHash(string, algid, encoding = "utf-8", byref hash = 0, byref hashlength = 0)
{
    chrlength := (encoding = "cp1200" || encoding = "utf-16") ? 2 : 1
    length := (StrPut(string, encoding) - 1) * chrlength
    VarSetCapacity(data, length, 0)
    StrPut(string, &data, floor(length / chrlength), encoding)
    return CalcAddrHash(&data, length, algid, hash, hashlength)
}