Just another update

This commit is contained in:
Ingy döt Net 2015-02-20 00:35:01 -05:00
parent a25938f123
commit 00a190b0a6
6591 changed files with 94363 additions and 23227 deletions

View file

@ -11,7 +11,7 @@ Positions in the grid are modified by entering their coordinates where the first
:* 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 lose if you try to clear space that has a hidden mine.
* Of course you lose if you try to cjhlear space that has a hidden mine.
* You win when you have correctly identified all mines.
The Task is to '''create a program that allows you to play minesweeper on a 6 by 4 grid, and that assumes all user input is formatted correctly''' and so checking inputs for correct form may be omitted.

View file

@ -0,0 +1,223 @@
#include <iostream>
#include <string>
#include <windows.h>
using namespace std;
typedef unsigned char byte;
enum fieldValues : byte { OPEN, CLOSED = 10, MINE, UNKNOWN, FLAG, ERR };
class fieldData
{
public:
fieldData() : value( CLOSED ), open( false ) {}
byte value;
bool open, mine;
};
class game
{
public:
~game()
{ if( field ) delete [] field; }
game( int x, int y )
{
go = false; wid = x; hei = y;
field = new fieldData[x * y];
memset( field, 0, x * y * sizeof( fieldData ) );
oMines = ( ( 22 - rand() % 11 ) * x * y ) / 100;
mMines = 0;
int mx, my, m = 0;
for( ; m < oMines; m++ )
{
do
{ mx = rand() % wid; my = rand() % hei; }
while( field[mx + wid * my].mine );
field[mx + wid * my].mine = true;
}
graphs[0] = ' '; graphs[1] = '.'; graphs[2] = '*';
graphs[3] = '?'; graphs[4] = '!'; graphs[5] = 'X';
}
void gameLoop()
{
string c, r, a;
int col, row;
while( !go )
{
drawBoard();
cout << "Enter column, row and an action( c r a ):\nActions: o => open, f => flag, ? => unknown\n";
cin >> c >> r >> a;
if( c[0] > 'Z' ) c[0] -= 32; if( a[0] > 'Z' ) a[0] -= 32;
col = c[0] - 65; row = r[0] - 49;
makeMove( col, row, a );
}
}
private:
void makeMove( int x, int y, string a )
{
fieldData* fd = &field[wid * y + x];
if( fd->open && fd->value < CLOSED )
{
cout << "This cell is already open!";
Sleep( 3000 ); return;
}
if( a[0] == 'O' ) openCell( x, y );
else if( a[0] == 'F' )
{
fd->open = true;
fd->value = FLAG;
mMines++;
checkWin();
}
else
{
fd->open = true;
fd->value = UNKNOWN;
}
}
bool openCell( int x, int y )
{
if( !isInside( x, y ) ) return false;
if( field[x + y * wid].mine ) boom();
else
{
if( field[x + y * wid].value == FLAG )
{
field[x + y * wid].value = CLOSED;
field[x + y * wid].open = false;
mMines--;
}
recOpen( x, y );
checkWin();
}
return true;
}
void drawBoard()
{
system( "cls" );
cout << "Marked mines: " << mMines << " from " << oMines << "\n\n";
for( int x = 0; x < wid; x++ )
cout << " " << ( char )( 65 + x ) << " ";
cout << "\n"; int yy;
for( int y = 0; y < hei; y++ )
{
yy = y * wid;
for( int x = 0; x < wid; x++ )
cout << "+---";
cout << "+\n"; fieldData* fd;
for( int x = 0; x < wid; x++ )
{
fd = &field[x + yy]; cout<< "| ";
if( !fd->open ) cout << ( char )graphs[1] << " ";
else
{
if( fd->value > 9 )
cout << ( char )graphs[fd->value - 9] << " ";
else
{
if( fd->value < 1 ) cout << " ";
else cout << ( char )(fd->value + 48 ) << " ";
}
}
}
cout << "| " << y + 1 << "\n";
}
for( int x = 0; x < wid; x++ )
cout << "+---";
cout << "+\n\n";
}
void checkWin()
{
int z = wid * hei - oMines, yy;
fieldData* fd;
for( int y = 0; y < hei; y++ )
{
yy = wid * y;
for( int x = 0; x < wid; x++ )
{
fd = &field[x + yy];
if( fd->open && fd->value != FLAG ) z--;
}
}
if( !z ) lastMsg( "Congratulations, you won the game!");
}
void boom()
{
int yy; fieldData* fd;
for( int y = 0; y < hei; y++ )
{
yy = wid * y;
for( int x = 0; x < wid; x++ )
{
fd = &field[x + yy];
if( fd->value == FLAG )
{
fd->open = true;
fd->value = fd->mine ? MINE : ERR;
}
else if( fd->mine )
{
fd->open = true;
fd->value = MINE;
}
}
}
lastMsg( "B O O O M M M M M !" );
}
void lastMsg( string s )
{
go = true; drawBoard();
cout << s << "\n\n";
}
bool isInside( int x, int y ) { return ( x > -1 && y > -1 && x < wid && y < hei ); }
void recOpen( int x, int y )
{
if( !isInside( x, y ) || field[x + y * wid].open ) return;
int bc = getMineCount( x, y );
field[x + y * wid].open = true;
field[x + y * wid].value = bc;
if( bc ) return;
for( int yy = -1; yy < 2; yy++ )
for( int xx = -1; xx < 2; xx++ )
{
if( xx == 0 && yy == 0 ) continue;
recOpen( x + xx, y + yy );
}
}
int getMineCount( int x, int y )
{
int m = 0;
for( int yy = -1; yy < 2; yy++ )
for( int xx = -1; xx < 2; xx++ )
{
if( xx == 0 && yy == 0 ) continue;
if( isInside( x + xx, y + yy ) && field[x + xx + ( y + yy ) * wid].mine ) m++;
}
return m;
}
int wid, hei, mMines, oMines;
fieldData* field; bool go;
int graphs[6];
};
int main( int argc, char* argv[] )
{
srand( GetTickCount() );
game g( 4, 6 ); g.gameLoop();
return system( "pause" );
}

View file

@ -0,0 +1,117 @@
# Minesweeper:
type Field
size::(Int, Int)
numbers::Array{Int, 2}
possible_mines::Array{Bool, 2}
actual_mines::Array{Bool, 2}
visible::Array{Bool, 2}
end
function Field(x, y)
size = (x, y)
actual_mines = convert(Array{Bool, 2}, rand(x, y) .< 0.15)
possible_mines = zeros(Bool, x, y)
numbers = zeros(Int, x, y)
visible = zeros(Bool, x, y)
for i = 1:x
for j = 1:y
n = 0
for di = -1:1
for dj = -1:1
n += (0 < di+i <= x && 0 < dj+j <= y) ?
(actual_mines[di+i, dj+j] ? 1 : 0) : 0
end
end
numbers[i, j] = n
end
end
return Field(size, numbers, possible_mines, actual_mines, visible)
end
function printfield(f::Field; showall = false)
spaces = int(floor(log(10, f.size[2])))
str = " "^(4+spaces)
for i in 1:f.size[1]
str *= string(" ", i, " ")
end
str *= "\n" * " "^(4+spaces) * "___"^f.size[1] * "\n"
for j = 1:f.size[2]
str *= " " * string(j) * " "^(floor(log(10, j)) > 0 ? 1 : spaces+1) * "|"
for i = 1:f.size[1]
if showall
str *= f.actual_mines[i, j] ? " * " : " "
else
if f.visible[i, j]
str *= " " * string(f.numbers[i, j] > 0 ? f.numbers[i, j] : " ") * " "
elseif f.possible_mines[i, j]
str *= " ? "
else
str *= " . "
end
end
end
str *= "\r\n"
end
println("Found " * string(length(f.possible_mines[f.possible_mines.==true])) *
" of " * string(length(f.actual_mines[f.actual_mines.==true])) * " mines.\n")
print(str)
end
function parse_input(str::ASCIIString)
input = split(chomp(str), " ")
mode = input[1]
coords = length(input) > 1 ? (int(input[2]), int(input[3])) : (0, 0)
return mode, coords
end
function eval_input(f::Field, str::ASCIIString)
mode, coords = parse_input(str)
(coords[1] > f.size[1] || coords[2] > f.size[2]) && return true
if mode == "o"
reveal(f, coords...) || return false
elseif mode == "m" && f.visible[coords...] == false
f.possible_mines[coords...] = !f.possible_mines[coords...]
elseif mode == "close"
error("You closed the game.")
end
return true
end
function reveal(f::Field, x::Int, y::Int)
(x > f.size[1] || y > f.size[2]) && return true # check for index out of bounds
f.actual_mines[x, y] && return false # check for mines
f.visible[x, y] = true
if f.numbers[x, y] == 0
for di = -1:1
for dj = -1:1
if (0 < di+x <= f.size[1] && 0 < dj+y <= f.size[2]) &&
f.actual_mines[x+di, y+dj] == false &&
f.visible[x+di, y+dj] == false
reveal(f, x+di, y+dj)
end
end
end
end
return true
end
function play()
print("\nWelcome to Minesweeper\n\nEnter the gridsize (x y):\n")
s = split(readline(), " ")
f = Field(int(s[1]), int(s[2]))
won = false
while true
printfield(f)
print("\nWhat do you do? (\"o x y\" to reveal a field; \"m x y\" to toggle a mine; close)\n")
eval_input(f, readline()) || break
print("_"^80 * "\n")
(f.actual_mines == f.possible_mines ||
f.visible == !f.actual_mines) && (won = true; break)
end
println(won ? "You won the game!" : "You lost the game:\n")
printfield(f, showall = true)
end
play()

View file

@ -0,0 +1,83 @@
julia> include("minesweeper.jl")
Welcome to Minesweeper
Enter the gridsize (x y):
6 4
Found 0 of 5 mines.
1 2 3 4 5 6
__________________
1 | . . . . . .
2 | . . . . . .
3 | . . . . . .
4 | . . . . . .
What do you do? ("o x y" to reveal a field; "m x y" to toggle a mine; close)
o 1 1
________________________________________________________________________________
Found 0 of 5 mines.
1 2 3 4 5 6
__________________
1 | 1 . . . . .
2 | . . . . . .
3 | . . . . . .
4 | . . . . . .
What do you do? ("o x y" to reveal a field; "m x y" to toggle a mine; close)
o 1 2
________________________________________________________________________________
Found 0 of 5 mines.
1 2 3 4 5 6
__________________
1 | 1 . . . . .
2 | 2 . . . . .
3 | . . . . . .
4 | . . . . . .
What do you do? ("o x y" to reveal a field; "m x y" to toggle a mine; close)
o 2 1
________________________________________________________________________________
Found 0 of 5 mines.
1 2 3 4 5 6
__________________
1 | 1 2 . . . .
2 | 2 . . . . .
3 | . . . . . .
4 | . . . . . .
What do you do? ("o x y" to reveal a field; "m x y" to toggle a mine; close)
o 6 4
________________________________________________________________________________
Found 0 of 5 mines.
1 2 3 4 5 6
__________________
1 | 1 2 . . . .
2 | 2 . 2 1 1 1
3 | . . 2
4 | . . 1
What do you do? ("o x y" to reveal a field; "m x y" to toggle a mine; close)
m 2 2
________________________________________________________________________________
Found 1 of 5 mines.
1 2 3 4 5 6
__________________
1 | 1 2 . . . .
2 | 2 ? 2 1 1 1
3 | . . 2
4 | . . 1
What do you do? ("o x y" to reveal a field; "m x y" to toggle a mine; close)
close
ERROR: You closed the game.

View file

@ -0,0 +1,243 @@
function Minesweeper
% Game parameters (should be modified by user)
nRows = 6;
nCols = 4;
percentMines = 0.15;
% Create minefield
nMines = ceil(percentMines*nRows*nCols);
field = makeGrid(nRows, nCols, nMines);
% Create timer for updating in axes title
stopwatch = timer('TimerFcn', {@updateTime, field}, ...
'ExecutionMode', 'fixedRate', 'Period', 1, 'StartDelay', 1, ...
'TasksToExecute', 999);
% Specify callbacks
set(gcf, 'CloseRequestFcn', {@cleanUp, stopwatch})
set(gca, 'ButtonDownFcn', {@onClick, field, stopwatch})
end
function field = makeGrid(nRows, nCols, nMines)
% Create minefield with unit squares
% Use quadrant IV to make indexing semi-consistent
% i.e. square in ith row, jth column has lower-right corner at (j, -i)
figure
set(gcf, 'Color', [1 1 1])
axis([0 nCols -nRows 0])
axis square
axis manual
hold on
set(gca, 'GridLineStyle', '-')
grid on
set(gca, 'XTick', 0:nCols)
set(gca, 'YTick', -nRows:0)
set(gca, 'XTickLabel', [])
set(gca, 'YTickLabel', [])
set(gca, 'Color', [0.6 0.6 0.6])
setTitle(nMines, ': )', 0)
xlabel('left-click to dig, right-click to mark')
% Set up field structure
% text will contain the handles to the labels in each square
% One character per square (or other functions will break)
% . Nothing noted
% M Marked as mine
% ? Marked as unknown
% 1-8 Digits indicate how many mines this square touches
% * Mine (game over)
% (blank) Square has been (dug) and is not mined nor touching any mines
% squares will contain handles to the colored "fill" objects
% fill objects will be deleted once square is "dug"
% Use ishandle() to determine if square is not yet dug
% mines will contain a logical array indicating positions of mines
% true Mine
% false No mine
% Later versions of MATLAB use gobjects() to preallocate text and squares
field = struct('text', zeros(nRows, nCols), ...
'squares', zeros(nRows, nCols), ...
'mines', false(nRows, nCols));
% Create individual square color and label objects
for r = 1:nRows
for c = 1:nCols
field.squares(r, c) = ...
fill([c-1 c-1 c c c-1], [-r+1 -r -r -r+1 -r+1], [0.9 0.9 0.9]);
set(field.squares(r, c), 'HitTest', 'off')
field.text(r, c) = text(c-0.5, -r+0.5, '.');
set(field.text(r, c), 'FontSize', 12, 'FontWeight', 'bold', ...
'HorizontalAlignment', 'center', 'HitTest', 'off');
end
end
% Place mines randomly without repeats
k = 0;
while k < nMines
idx = randi(nRows*nCols);
if ~field.mines(idx)
field.mines(idx) = true;
k = k+1;
end
end
end
function onClick(obj, event, field, stopwatch)
if strcmp(stopwatch.Running, 'off')
start(stopwatch)
end
pt = get(obj, 'CurrentPoint');
r = ceil(-pt(1, 2));
c = ceil(pt(1, 1));
if r > 0 && c > 0 && r <= size(field.squares, 1) && ... % Not yet been "dug"
c <= size(field.squares, 2) && ishandle(field.squares(r, c))
buttons = {'normal' 'alt' 'extend'};
btn = find(strcmp(get(get(obj, 'Parent'), 'SelectionType'), buttons));
labels = '.M?'; % Unmarked, mine flag, unknown flag
currLabel = get(field.text(r, c), 'String');
if btn == 1 % Left click
if currLabel ~= labels(2); % Don't dig if flagged as mine
if field.mines(r, c) % Mine there -> you lose
gameLost(field, stopwatch, r, c)
else % No mine -> free to dig
minesLeft = countMineFlags(field);
digSquare(field, r, c)
if all(all(ishandle(field.squares) == field.mines))
gameWon(field, stopwatch)
else
faceTimer = timer('StartDelay', 0.5, ...
'StartFcn', {@setTitleOnTimer, minesLeft, ...
': o', stopwatch.TasksExecuted}, ...
'TimerFcn', {@setTitleOnTimer, minesLeft, ...
': )', stopwatch.TasksExecuted}, ...
'StopFcn', @deleteTimer);
start(faceTimer)
end
end
end
elseif btn == 2 % Right-click
% Rotate through labels list to the next one
switch find(currLabel == labels)
case 1
newLabel = labels(2);
case 2
newLabel = labels(3);
case 3
newLabel = labels(1);
end
set(field.text(r, c), 'String', newLabel);
setTitle(countMineFlags(field), ': )', stopwatch.TasksExecuted)
elseif btn == 3 % Middle-click
% Mark/unmark unknown flag
if currLabel == labels(1)
set(field.text(r, c), 'String', labels(3));
elseif currLabel == labels(3)
set(field.text(r, c), 'String', labels(1));
end
end
end
end
function updateTime(obj, event, field)
setTitle(countMineFlags(field), ': )', obj.TasksExecuted)
end
function deleteTimer(obj, event)
delete(obj)
end
function setTitleOnTimer(obj, event, mines, face, time)
setTitle(mines, face, time)
end
function setTitle(mines, face, time)
title(sprintf('%03d Mines %s Timer %03d', mines, face, time))
end
function minesLeft = countMineFlags(field)
% Determine how many mines are unmarked (negative means too many mines marked)
minesLeft = sum(field.mines(:));
for k = 1:numel(field.text)
if get(field.text(k), 'String') % Not an empty string
minesLeft = minesLeft-(get(field.text(k), 'String') == 'M');
end
end
end
function digSquare(field, r, c)
% If square is touching one or more mines then indicate the number
% Otherwise indicate no mines and dig surrounding squares recursively
% Assumes current square is clear of mines
delete(field.squares(r, c))
[nRows, nCols] = size(field.mines);
surrR = [r-1 r r+1 r-1 r+1 r-1 r r+1];
surrC = [c-1 c-1 c-1 c c c+1 c+1 c+1];
toDelete = surrR < 1 | surrR > nRows | surrC < 1 | surrC > nCols;
surrR(toDelete) = [];
surrC(toDelete) = [];
nearMines = sum(field.mines(sub2ind([nRows nCols], surrR, surrC)));
label = sprintf('%d', nearMines);
textColor = [0 0 0 ; 0 0 1 ; 0 1 0 ; 1 0 0 ; 0.5 0.1 0.9 ; ...
0.6 0 0 ; 0.2 0.5 0.3 ; 0.2 0.2 0.1 ; 0 0 0];
if ~nearMines
label = '';
for k = 1:length(surrR)
if ~field.mines(surrR(k), surrC(k)) && ...
ishandle(field.squares(surrR(k), surrC(k))) && ...
~strcmp(get(field.text(k), 'String'), 'M')
digSquare(field, surrR(k), surrC(k))
end
end
end
set(field.text(r, c), 'String', label, 'Color', textColor(nearMines+1, :))
end
function gameLost(field, stopwatch, r, c)
stop(stopwatch)
setTitle(countMineFlags(field), 'X (', stopwatch.TasksExecuted)
set(field.squares(r, c), 'FaceColor', [1 0 0])
for k = 1:numel(field.text)
if field.mines(k) && any(get(field.text(k), 'String') == '.?')
set(field.text(k), 'String', '*', 'FontSize', 20)
elseif ~field.mines(k) && ishandle(field.squares(k)) && ...
get(field.text(k), 'String') == 'M'
set(field.text(k), 'String', 'X', 'Color', [1 0 0])
end
end
set(gca, 'HitTest', 'off')
queryPlayAgain('Game over')
end
function gameWon(field, stopwatch)
% Flag any leftover mines and indicate win
stop(stopwatch)
set(field.text(ishandle(field.squares)), 'String', 'M')
setTitle(0, 'B )', stopwatch.TasksExecuted)
set(gca, 'HitTest', 'off')
queryPlayAgain('Minefield cleared!')
end
function queryPlayAgain(msg)
% Ask player if they want to play again
% Reset game by closing and reopening figure
choice = questdlg(sprintf('%s\nWould you like to play again?', msg), ...
'', 'Yes', 'No', 'No');
if strcmp(choice, 'Yes')
close
Minesweeper
end
end
function cleanUp(obj, event, stopwatch)
% Stop and close down all necessary processes
stop(stopwatch)
delete(stopwatch)
delete(obj)
end