A-M baby
This commit is contained in:
parent
764da6cbbb
commit
db842d013d
19005 changed files with 197040 additions and 7 deletions
22
Task/Minesweeper-game/0DESCRIPTION
Normal file
22
Task/Minesweeper-game/0DESCRIPTION
Normal file
|
|
@ -0,0 +1,22 @@
|
|||
There is an n by m grid that has a random number (between 10% to 20% of the total number of tiles, though older implementations may use 20%..60% instead) of randomly placed 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 lose if you try to clear 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.
|
||||
You may also omit all GUI parts of the task and work using text input and output.
|
||||
|
||||
Note: Changes may be made to the method of clearing mines to more closely follow a particular implementation of the game so long as such differences and the implementation that they more accurately follow are described.
|
||||
|
||||
<br>C.F: [[wp:Minesweeper (computer game)]]
|
||||
2
Task/Minesweeper-game/1META.yaml
Normal file
2
Task/Minesweeper-game/1META.yaml
Normal file
|
|
@ -0,0 +1,2 @@
|
|||
---
|
||||
note: games
|
||||
368
Task/Minesweeper-game/Ada/minesweeper-game.ada
Normal file
368
Task/Minesweeper-game/Ada/minesweeper-game.ada
Normal file
|
|
@ -0,0 +1,368 @@
|
|||
with Ada.Numerics.Discrete_Random;
|
||||
with Ada.Text_IO;
|
||||
|
||||
procedure Minesweeper is
|
||||
package IO renames Ada.Text_IO;
|
||||
package Nat_IO is new IO.Integer_IO (Natural);
|
||||
package Nat_RNG is new Ada.Numerics.Discrete_Random (Natural);
|
||||
|
||||
type Stuff is (Empty, Mine);
|
||||
type Field is record
|
||||
Contents : Stuff := Empty;
|
||||
Opened : Boolean := False;
|
||||
Marked : Boolean := False;
|
||||
end record;
|
||||
type Grid is array (Positive range <>, Positive range <>) of Field;
|
||||
|
||||
-- counts how many mines are in the surrounding fields
|
||||
function Mines_Nearby (Item : Grid; X, Y : Positive) return Natural is
|
||||
Result : Natural := 0;
|
||||
begin
|
||||
-- left of X:Y
|
||||
if X > Item'First (1) then
|
||||
-- above X-1:Y
|
||||
if Y > Item'First (2) then
|
||||
if Item (X - 1, Y - 1).Contents = Mine then
|
||||
Result := Result + 1;
|
||||
end if;
|
||||
end if;
|
||||
-- X-1:Y
|
||||
if Item (X - 1, Y).Contents = Mine then
|
||||
Result := Result + 1;
|
||||
end if;
|
||||
-- below X-1:Y
|
||||
if Y < Item'Last (2) then
|
||||
if Item (X - 1, Y + 1).Contents = Mine then
|
||||
Result := Result + 1;
|
||||
end if;
|
||||
end if;
|
||||
end if;
|
||||
-- above of X:Y
|
||||
if Y > Item'First (2) then
|
||||
if Item (X, Y - 1).Contents = Mine then
|
||||
Result := Result + 1;
|
||||
end if;
|
||||
end if;
|
||||
-- below of X:Y
|
||||
if Y < Item'Last (2) then
|
||||
if Item (X, Y + 1).Contents = Mine then
|
||||
Result := Result + 1;
|
||||
end if;
|
||||
end if;
|
||||
-- right of X:Y
|
||||
if X < Item'Last (1) then
|
||||
-- above X+1:Y
|
||||
if Y > Item'First (2) then
|
||||
if Item (X + 1, Y - 1).Contents = Mine then
|
||||
Result := Result + 1;
|
||||
end if;
|
||||
end if;
|
||||
-- X+1:Y
|
||||
if Item (X + 1, Y).Contents = Mine then
|
||||
Result := Result + 1;
|
||||
end if;
|
||||
-- below X+1:Y
|
||||
if Y < Item'Last (2) then
|
||||
if Item (X + 1, Y + 1).Contents = Mine then
|
||||
Result := Result + 1;
|
||||
end if;
|
||||
end if;
|
||||
end if;
|
||||
return Result;
|
||||
end Mines_Nearby;
|
||||
|
||||
-- outputs the grid
|
||||
procedure Put (Item : Grid) is
|
||||
Mines : Natural := 0;
|
||||
begin
|
||||
IO.Put (" ");
|
||||
for X in Item'Range (1) loop
|
||||
Nat_IO.Put (Item => X, Width => 3);
|
||||
end loop;
|
||||
IO.New_Line;
|
||||
IO.Put (" +");
|
||||
for X in Item'Range (1) loop
|
||||
IO.Put ("---");
|
||||
end loop;
|
||||
IO.Put ('+');
|
||||
IO.New_Line;
|
||||
for Y in Item'Range (2) loop
|
||||
Nat_IO.Put (Item => Y, Width => 3);
|
||||
IO.Put ('|');
|
||||
for X in Item'Range (1) loop
|
||||
if Item (X, Y).Opened then
|
||||
if Item (X, Y).Contents = Empty then
|
||||
if Item (X, Y).Marked then
|
||||
IO.Put (" - ");
|
||||
else
|
||||
Mines := Mines_Nearby (Item, X, Y);
|
||||
if Mines > 0 then
|
||||
Nat_IO.Put (Item => Mines, Width => 2);
|
||||
IO.Put (' ');
|
||||
else
|
||||
IO.Put (" ");
|
||||
end if;
|
||||
end if;
|
||||
else
|
||||
if Item (X, Y).Marked then
|
||||
IO.Put (" + ");
|
||||
else
|
||||
IO.Put (" X ");
|
||||
end if;
|
||||
end if;
|
||||
elsif Item (X, Y).Marked then
|
||||
IO.Put (" ? ");
|
||||
else
|
||||
IO.Put (" . ");
|
||||
end if;
|
||||
end loop;
|
||||
IO.Put ('|');
|
||||
IO.New_Line;
|
||||
end loop;
|
||||
IO.Put (" +");
|
||||
for X in Item'Range (1) loop
|
||||
IO.Put ("---");
|
||||
end loop;
|
||||
IO.Put ('+');
|
||||
IO.New_Line;
|
||||
end Put;
|
||||
|
||||
-- marks a field as possible bomb
|
||||
procedure Mark (Item : in out Grid; X, Y : in Positive) is
|
||||
begin
|
||||
if Item (X, Y).Opened then
|
||||
IO.Put_Line ("Field already open!");
|
||||
else
|
||||
Item (X, Y).Marked := not Item (X, Y).Marked;
|
||||
end if;
|
||||
end Mark;
|
||||
|
||||
-- clears a field and it's neighbours, if they don't have mines
|
||||
procedure Clear
|
||||
(Item : in out Grid;
|
||||
X, Y : in Positive;
|
||||
Killed : out Boolean)
|
||||
is
|
||||
-- clears the neighbours, if they don't have mines
|
||||
procedure Clear_Neighbours (The_X, The_Y : Positive) is
|
||||
begin
|
||||
-- mark current field opened
|
||||
Item (The_X, The_Y).Opened := True;
|
||||
-- only proceed if neighbours don't have mines
|
||||
if Mines_Nearby (Item, The_X, The_Y) = 0 then
|
||||
-- left of X:Y
|
||||
if The_X > Item'First (1) then
|
||||
-- above X-1:Y
|
||||
if The_Y > Item'First (2) then
|
||||
if not Item (The_X - 1, The_Y - 1).Opened and
|
||||
not Item (The_X - 1, The_Y - 1).Marked
|
||||
then
|
||||
Clear_Neighbours (The_X - 1, The_Y - 1);
|
||||
end if;
|
||||
end if;
|
||||
-- X-1:Y
|
||||
if not Item (The_X - 1, The_Y).Opened and
|
||||
not Item (The_X - 1, The_Y).Marked
|
||||
then
|
||||
Clear_Neighbours (The_X - 1, The_Y);
|
||||
end if;
|
||||
-- below X-1:Y
|
||||
if The_Y < Item'Last (2) then
|
||||
if not Item (The_X - 1, The_Y + 1).Opened and
|
||||
not Item (The_X - 1, The_Y + 1).Marked
|
||||
then
|
||||
Clear_Neighbours (The_X - 1, The_Y + 1);
|
||||
end if;
|
||||
end if;
|
||||
end if;
|
||||
-- above X:Y
|
||||
if The_Y > Item'First (2) then
|
||||
if not Item (The_X, The_Y - 1).Opened and
|
||||
not Item (The_X, The_Y - 1).Marked
|
||||
then
|
||||
Clear_Neighbours (The_X, The_Y - 1);
|
||||
end if;
|
||||
end if;
|
||||
-- below X:Y
|
||||
if The_Y < Item'Last (2) then
|
||||
if not Item (The_X, The_Y + 1).Opened and
|
||||
not Item (The_X, The_Y + 1).Marked
|
||||
then
|
||||
Clear_Neighbours (The_X, The_Y + 1);
|
||||
end if;
|
||||
end if;
|
||||
-- right of X:Y
|
||||
if The_X < Item'Last (1) then
|
||||
-- above X+1:Y
|
||||
if The_Y > Item'First (2) then
|
||||
if not Item (The_X + 1, The_Y - 1).Opened and
|
||||
not Item (The_X + 1, The_Y - 1).Marked
|
||||
then
|
||||
Clear_Neighbours (The_X + 1, The_Y - 1);
|
||||
end if;
|
||||
end if;
|
||||
-- X+1:Y
|
||||
if not Item (The_X + 1, The_Y).Opened and
|
||||
not Item (The_X + 1, The_Y).Marked
|
||||
then
|
||||
Clear_Neighbours (The_X + 1, The_Y);
|
||||
end if;
|
||||
-- below X+1:Y
|
||||
if The_Y < Item'Last (2) then
|
||||
if not Item (The_X + 1, The_Y + 1).Opened and
|
||||
not Item (The_X + 1, The_Y + 1).Marked
|
||||
then
|
||||
Clear_Neighbours (The_X + 1, The_Y + 1);
|
||||
end if;
|
||||
end if;
|
||||
end if;
|
||||
end if;
|
||||
end Clear_Neighbours;
|
||||
begin
|
||||
Killed := False;
|
||||
-- only clear closed and unmarked fields
|
||||
if Item (X, Y).Opened then
|
||||
IO.Put_Line ("Field already open!");
|
||||
elsif Item (X, Y).Marked then
|
||||
IO.Put_Line ("Field already marked!");
|
||||
else
|
||||
Killed := Item (X, Y).Contents = Mine;
|
||||
-- game over if killed, no need to clear
|
||||
if not Killed then
|
||||
Clear_Neighbours (X, Y);
|
||||
end if;
|
||||
end if;
|
||||
end Clear;
|
||||
|
||||
-- marks all fields as open
|
||||
procedure Open_All (Item : in out Grid) is
|
||||
begin
|
||||
for X in Item'Range (1) loop
|
||||
for Y in Item'Range (2) loop
|
||||
Item (X, Y).Opened := True;
|
||||
end loop;
|
||||
end loop;
|
||||
end Open_All;
|
||||
|
||||
-- counts the number of marks
|
||||
function Count_Marks (Item : Grid) return Natural is
|
||||
Result : Natural := 0;
|
||||
begin
|
||||
for X in Item'Range (1) loop
|
||||
for Y in Item'Range (2) loop
|
||||
if Item (X, Y).Marked then
|
||||
Result := Result + 1;
|
||||
end if;
|
||||
end loop;
|
||||
end loop;
|
||||
return Result;
|
||||
end Count_Marks;
|
||||
|
||||
-- read and validate user input
|
||||
procedure Get_Coordinates
|
||||
(Max_X, Max_Y : Positive;
|
||||
X, Y : out Positive;
|
||||
Valid : out Boolean)
|
||||
is
|
||||
begin
|
||||
Valid := False;
|
||||
IO.Put ("X: ");
|
||||
Nat_IO.Get (X);
|
||||
IO.Put ("Y: ");
|
||||
Nat_IO.Get (Y);
|
||||
Valid := X > 0 and X <= Max_X and Y > 0 and Y <= Max_Y;
|
||||
exception
|
||||
when Constraint_Error =>
|
||||
Valid := False;
|
||||
end Get_Coordinates;
|
||||
|
||||
-- randomly place bombs
|
||||
procedure Set_Bombs (Item : in out Grid; Max_X, Max_Y, Count : Positive) is
|
||||
Generator : Nat_RNG.Generator;
|
||||
X, Y : Positive;
|
||||
begin
|
||||
Nat_RNG.Reset (Generator);
|
||||
for I in 1 .. Count loop
|
||||
Placement : loop
|
||||
X := Nat_RNG.Random (Generator) mod Max_X + 1;
|
||||
Y := Nat_RNG.Random (Generator) mod Max_Y + 1;
|
||||
-- redo placement if X:Y already full
|
||||
if Item (X, Y).Contents = Empty then
|
||||
Item (X, Y).Contents := Mine;
|
||||
exit Placement;
|
||||
end if;
|
||||
end loop Placement;
|
||||
end loop;
|
||||
end Set_Bombs;
|
||||
|
||||
Width, Height : Positive;
|
||||
|
||||
begin
|
||||
-- can be dynamically set
|
||||
Width := 6;
|
||||
Height := 4;
|
||||
declare
|
||||
The_Grid : Grid (1 .. Width, 1 .. Height);
|
||||
-- 20% bombs
|
||||
Bomb_Count : Positive := Width * Height * 20 / 100;
|
||||
Finished : Boolean := False;
|
||||
Action : Character;
|
||||
Chosen_X, Chosen_Y : Positive;
|
||||
Valid_Entry : Boolean;
|
||||
begin
|
||||
IO.Put ("Nr. Bombs: ");
|
||||
Nat_IO.Put (Item => Bomb_Count, Width => 0);
|
||||
IO.New_Line;
|
||||
Set_Bombs
|
||||
(Item => The_Grid,
|
||||
Max_X => Width,
|
||||
Max_Y => Height,
|
||||
Count => Bomb_Count);
|
||||
while not Finished and Count_Marks (The_Grid) /= Bomb_Count loop
|
||||
Put (The_Grid);
|
||||
IO.Put ("Input (c/m/r): ");
|
||||
IO.Get (Action);
|
||||
case Action is
|
||||
when 'c' | 'C' =>
|
||||
Get_Coordinates
|
||||
(Max_X => Width,
|
||||
Max_Y => Height,
|
||||
X => Chosen_X,
|
||||
Y => Chosen_Y,
|
||||
Valid => Valid_Entry);
|
||||
if Valid_Entry then
|
||||
Clear
|
||||
(Item => The_Grid,
|
||||
X => Chosen_X,
|
||||
Y => Chosen_Y,
|
||||
Killed => Finished);
|
||||
if Finished then
|
||||
IO.Put_Line ("You stepped on a mine!");
|
||||
end if;
|
||||
else
|
||||
IO.Put_Line ("Invalid input, retry!");
|
||||
end if;
|
||||
when 'm' | 'M' =>
|
||||
Get_Coordinates
|
||||
(Max_X => Width,
|
||||
Max_Y => Height,
|
||||
X => Chosen_X,
|
||||
Y => Chosen_Y,
|
||||
Valid => Valid_Entry);
|
||||
if Valid_Entry then
|
||||
Mark (Item => The_Grid, X => Chosen_X, Y => Chosen_Y);
|
||||
else
|
||||
IO.Put_Line ("Invalid input, retry!");
|
||||
end if;
|
||||
when 'r' | 'R' =>
|
||||
Finished := True;
|
||||
when others =>
|
||||
IO.Put_Line ("Invalid input, retry!");
|
||||
end case;
|
||||
end loop;
|
||||
Open_All (The_Grid);
|
||||
IO.Put_Line
|
||||
("Solution: (+ = correctly marked, - = incorrectly marked)");
|
||||
Put (The_Grid);
|
||||
end;
|
||||
end Minesweeper;
|
||||
110
Task/Minesweeper-game/BASIC256/minesweeper-game.basic256
Normal file
110
Task/Minesweeper-game/BASIC256/minesweeper-game.basic256
Normal file
|
|
@ -0,0 +1,110 @@
|
|||
N = 6 : M = 5 : H = 25 : P = 0.2
|
||||
|
||||
fastgraphics
|
||||
graphsize N*H,(M+1)*H
|
||||
font "Arial",H/2+1,75
|
||||
dim f(N,M) # 1 open, 2 mine, 4 expected mine
|
||||
dim s(N,M) # count of mines in a neighborhood
|
||||
|
||||
trian1 = {1,1,H-1,1,H-1,H-1} : trian2 = {1,1,1,H-1,H-1,H-1}
|
||||
mine = {2,2, H/2,H/2-2, H-2,2, H/2+2,H/2, H-2,H-2, H/2,H/2+2, 2,H-2, H/2-2,H/2}
|
||||
flag = {H/2-1,3, H/2+1,3, H-4,H/5, H/2+1,H*2/5, H/2+1,H*0.9-2, H*0.8,H-2, H*0.2,H-2, H/2-1,H*0.9-2}
|
||||
|
||||
mines = int(N*M*P) : k = mines : act = 0
|
||||
while k>0
|
||||
i = int(rand*N) : j = int(rand*M)
|
||||
if not f[i,j] then
|
||||
f[i,j] = 2 : k = k - 1 # set mine
|
||||
s[i,j] = s[i,j] + 1 : gosub adj # count it
|
||||
|
||||
end if
|
||||
end while
|
||||
togo = M*N-mines : over = 0 : act = 1
|
||||
|
||||
gosub redraw
|
||||
while not over
|
||||
clickclear
|
||||
while not clickb
|
||||
pause 0.01
|
||||
end while
|
||||
i = int(clickx/H) : j = int(clicky/H)
|
||||
if i<N and j<M then
|
||||
if clickb=1 then
|
||||
if not (f[i,j]&4) then ai = i : aj = j : gosub opencell
|
||||
if not s[i,j] then gosub adj
|
||||
else
|
||||
if not (f[i,j]&1) then
|
||||
if f[i,j]&4 then mines = mines+1
|
||||
if not (f[i,j]&4) then mines = mines-1
|
||||
f[i,j] = (f[i,j]&~4)|(~f[i,j]&4)
|
||||
end if
|
||||
end if
|
||||
if not (togo or mines) then over = 1
|
||||
gosub redraw
|
||||
end if
|
||||
end while
|
||||
imgsave "Minesweeper_game_BASIC-256.png", "PNG"
|
||||
end
|
||||
|
||||
redraw:
|
||||
for i = 0 to N-1
|
||||
for j = 0 to M-1
|
||||
if over=-1 and f[i,j]&2 then f[i,j] = f[i,j]|1
|
||||
gosub drawcell
|
||||
next j
|
||||
next i
|
||||
# Counter
|
||||
color (32,32,32) : rect 0,M*H,N*H,H
|
||||
color white : x = 5 : y = M*H+H*0.05
|
||||
if not over then text x,y,"Mines: " + mines
|
||||
if over=1 then text x,y,"You won!"
|
||||
if over=-1 then text x,y,"You lost"
|
||||
refresh
|
||||
return
|
||||
|
||||
drawcell:
|
||||
color darkgrey
|
||||
rect i*H,j*H,H,H
|
||||
if f[i,j]&1=0 then # closed
|
||||
color black : stamp i*H,j*H,trian1
|
||||
color white : stamp i*H,j*H,trian2
|
||||
color grey : rect i*H+2,j*H+2,H-4,H-4
|
||||
if f[i,j]&4 then color blue : stamp i*H,j*H,flag
|
||||
else
|
||||
color 192,192,192 : rect i*H+1,j*H+1,H-2,H-2
|
||||
# Draw
|
||||
if f[i,j]&2 then # mine
|
||||
if not (f[i,j]&4) then color red
|
||||
if f[i,j]&4 then color darkgreen
|
||||
circle i*H+H/2,j*H+H/2,H/5 : stamp i*H,j*H,mine
|
||||
else
|
||||
if s[i,j] then color (32,32,32) : text i*H+H/3,j*H+1,s[i,j]
|
||||
end if
|
||||
end if
|
||||
return
|
||||
|
||||
adj:
|
||||
aj = j-1
|
||||
if j and i then ai = i-1 : gosub adjact
|
||||
if j then ai = i : gosub adjact
|
||||
if j and i<N-1 then ai = i+1 : gosub adjact
|
||||
aj = j
|
||||
if i then ai = i-1 : gosub adjact
|
||||
if i<N-1 then ai = i+1 : gosub adjact
|
||||
aj = j+1
|
||||
if j<M-1 and i then ai = i-1 : gosub adjact
|
||||
if j<M-1 then ai = i : gosub adjact
|
||||
if j<M-1 and i<N-1 then ai = i+1 : gosub adjact
|
||||
return
|
||||
|
||||
adjact:
|
||||
if not act then s[ai,aj] = s[ai,aj]+1 : return
|
||||
if act then gosub opencell : return
|
||||
|
||||
opencell:
|
||||
if not (f[ai,aj]&1) then
|
||||
f[ai,aj] = f[ai,aj]|1
|
||||
togo = togo-1
|
||||
end if
|
||||
if f[ai,aj]&2 then over = -1
|
||||
return
|
||||
415
Task/Minesweeper-game/C/minesweeper-game-1.c
Normal file
415
Task/Minesweeper-game/C/minesweeper-game-1.c
Normal file
|
|
@ -0,0 +1,415 @@
|
|||
#if 0
|
||||
|
||||
Unix build:
|
||||
|
||||
make CPPFLAGS=-DNDEBUG LDLIBS=-lcurses mines
|
||||
|
||||
dwlmines, by David Lambert; sometime in the twentieth Century. The
|
||||
program is meant to run in a terminal window compatible with curses
|
||||
if unix is defined to cpp, or to an ANSI terminal when compiled
|
||||
without unix macro defined. I suppose I have built this on a
|
||||
windows 98 computer using gcc running in a cmd window. The original
|
||||
probably came from a VAX running VMS with a vt100 sort of terminal.
|
||||
Today I have xterm and gcc available so I will claim only that it
|
||||
works with this combination.
|
||||
|
||||
As this program can automatically play all the trivially counted
|
||||
safe squares. Action is quick leaving the player with only the
|
||||
thoughtful action. Whereas 's' steps on the spot with the cursor,
|
||||
capital 'S' (Stomp) invokes autoplay.
|
||||
|
||||
The cursor motion keys are as in the vi editor; hjkl move the cursor.
|
||||
|
||||
'd' displays the number of unclaimed bombs and cells.
|
||||
|
||||
'f' flags a cell.
|
||||
|
||||
The numbers on the field indicate the number of bombs in the
|
||||
unclaimed neighboring cells. This is more useful than showing the
|
||||
values you expect. You may find unflagging a cell adjacent to a
|
||||
number will help you understand this.
|
||||
|
||||
There is extra code here. The multidimensional array allocator
|
||||
allocarray is much better than those of Numerical Recipes in C. If
|
||||
you subtracted the offset 1 to make the arrays FORTRAN like then
|
||||
allocarray could substitute for those of NR in C.
|
||||
#endif
|
||||
|
||||
#include <stdarg.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
#ifndef NDEBUG
|
||||
# define DEBUG_CODE(A) A
|
||||
#else
|
||||
# define DEBUG_CODE(A)
|
||||
#endif
|
||||
|
||||
|
||||
#include <time.h>
|
||||
|
||||
#define DIM(A) (sizeof((A))/sizeof(*(A)))
|
||||
#define MAX(A,B) ((A)<(B)?(B):(A))
|
||||
#define BIND(A,L,H) ((L)<(A)?(A)<(H)?(A):(H):(L))
|
||||
|
||||
#define SET_BIT(A,B) ((A)|=1<<(B))
|
||||
#define CLR_BIT(A,B) ((A)&=~(1<<(B)))
|
||||
#define TGL_BIT(A,B) ((A)^=1<<(B))
|
||||
#define INQ_BIT(A,B) ((A)&(1<<(B)))
|
||||
#define FOREVER for(;;)
|
||||
#define MODINC(i,mod) ((i)+1<(mod)?(i)+1:0)
|
||||
#define MODDEC(i,mod) (((i)<=0?(mod):(i))-1)
|
||||
|
||||
void error(int status,const char *message) {
|
||||
fprintf(stderr, "%s\n", message);
|
||||
exit(status);
|
||||
}
|
||||
|
||||
void*dwlcalloc(int n,size_t bytes) {
|
||||
void*rv = (void*)calloc(n,bytes);
|
||||
if (NULL == rv)
|
||||
error(1,"memory allocation failure");
|
||||
DEBUG_CODE(fprintf(stderr,"allocated address %p\n",rv);)
|
||||
return rv;
|
||||
}
|
||||
|
||||
void*allocarray(int rank,size_t*shape,size_t itemSize) {
|
||||
/*
|
||||
Allocates arbitrary dimensional arrays (and inits all pointers)
|
||||
with only 1 call to malloc. David W. Lambert, written before 1990.
|
||||
This is wonderful because one only need call free once to deallocate
|
||||
the space. Special routines for each size array are not need for
|
||||
allocation of for deallocation. Also calls to malloc might be expensive
|
||||
because they might have to place operating system requests. One call
|
||||
seems optimal.
|
||||
*/
|
||||
size_t size,i,j,dataSpace,pointerSpace,pointers,nextLevelIncrement;
|
||||
char*memory,*pc,*nextpc;
|
||||
if (rank < 2) {
|
||||
if (rank < 0)
|
||||
error(1,"invalid negative rank argument passed to allocarray");
|
||||
size = rank < 1 ? 1 : *shape;
|
||||
return dwlcalloc(size,itemSize);
|
||||
}
|
||||
pointerSpace = 0, dataSpace = 1;
|
||||
for (i = 0; i < rank-1; ++i)
|
||||
pointerSpace += (dataSpace *= shape[i]);
|
||||
pointerSpace *= sizeof(char*);
|
||||
dataSpace *= shape[i]*itemSize;
|
||||
memory = pc = dwlcalloc(1,pointerSpace+dataSpace);
|
||||
pointers = 1;
|
||||
for (i = 0; i < rank-2; ) {
|
||||
nextpc = pc + (pointers *= shape[i])*sizeof(char*);
|
||||
nextLevelIncrement = shape[++i]*sizeof(char*);
|
||||
for (j = 0; j < pointers; ++j)
|
||||
*((char**)pc) = nextpc, pc+=sizeof(char*), nextpc += nextLevelIncrement;
|
||||
}
|
||||
nextpc = pc + (pointers *= shape[i])*sizeof(char*);
|
||||
nextLevelIncrement = shape[++i]*itemSize;
|
||||
for (j = 0; j < pointers; ++j)
|
||||
*((char**)pc) = nextpc, pc+=sizeof(char*), nextpc += nextLevelIncrement;
|
||||
return memory;
|
||||
}
|
||||
|
||||
#define PRINT(element) \
|
||||
if (NULL == print_elt) \
|
||||
printf("%10.3e",*(double*)(element)); \
|
||||
else \
|
||||
(*print_elt)(element)
|
||||
|
||||
/* matprint prints an array in APL\360 style */
|
||||
/* with a NULL element printing function matprint assumes an array of double */
|
||||
void*matprint(void*a,int rank,size_t*shape,size_t size,void(*print_elt)()) {
|
||||
union {
|
||||
unsigned **ppu;
|
||||
unsigned *pu;
|
||||
unsigned u;
|
||||
} b;
|
||||
int i;
|
||||
if (rank <= 0 || NULL == shape)
|
||||
PRINT(a);
|
||||
else if (1 < rank) {
|
||||
for (i = 0; i < shape[0]; ++i)
|
||||
matprint(((void**)a)[i], rank-1,shape+1,size,print_elt);
|
||||
putchar('\n');
|
||||
for (i = 0, b.pu = a; i < shape[0]; ++i, b.u += size) {
|
||||
PRINT(b.pu);
|
||||
putchar(' ');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef __unix__
|
||||
# include <curses.h>
|
||||
# include <unistd.h>
|
||||
# define SRANDOM srandom
|
||||
# define RANDOM random
|
||||
#else
|
||||
# include <windows.h>
|
||||
void addch(int c) { putchar(c); }
|
||||
void addstr(const char*s) { fputs(s,stdout); }
|
||||
# define ANSI putchar(27),putchar('[')
|
||||
void initscr(void) { printf("%d\n",AllocConsole()); }
|
||||
void cbreak(void) { ; }
|
||||
void noecho(void) { ; }
|
||||
void nonl(void) { ; }
|
||||
int move(int r,int c) { ANSI; return printf("%d;%dH",r+1,c+1); }
|
||||
int mvaddch(int r,int c,int ch) { move(r,c); addch(ch); }
|
||||
void refresh(void) { ; }
|
||||
# define WA_STANDOUT 32
|
||||
int attr_on(int a,void*p) { ANSI; return printf("%dm",a); }
|
||||
int attr_off(int a,void*p) { attr_on(0,NULL); }
|
||||
# include <stdarg.h>
|
||||
void printw(const char*fmt,...) {
|
||||
va_list args;
|
||||
va_start(args,fmt);
|
||||
vprintf(fmt,args);
|
||||
va_end(args);
|
||||
}
|
||||
void clrtoeol(void) {
|
||||
ANSI;addstr("0J");
|
||||
}
|
||||
# define SRANDOM srand
|
||||
# define RANDOM rand
|
||||
#endif
|
||||
|
||||
#ifndef EXIT_SUCCESS
|
||||
# define EXIT_SUCCESS 1 /* just a guess */
|
||||
#endif
|
||||
|
||||
|
||||
#if 0
|
||||
cell status
|
||||
UNKN --- contains virgin earth (initial state)
|
||||
MINE --- has a mine
|
||||
FLAG --- was flagged
|
||||
#endif
|
||||
|
||||
enum {UNKN,MINE,FLAG}; /* bit numbers */
|
||||
|
||||
#define DETECT(CELL,PROPERTY) (!!INQ_BIT(CELL,PROPERTY))
|
||||
|
||||
DEBUG_CODE( \
|
||||
void pchr(void*a) { /* odd comment removed */ \
|
||||
putchar('A'+*(char*a)); /* should print the nth char of alphabet */\
|
||||
} /* where 'A' is 0 */ \
|
||||
)
|
||||
|
||||
char**bd; /* the board */
|
||||
size_t shape[2];
|
||||
#define RWS (shape[0])
|
||||
#define CLS (shape[1])
|
||||
|
||||
void populate(int x,int y,int pct) { /* finished size in col, row, % mines */
|
||||
int i,j,c;
|
||||
x = BIND(x,4,200), y = BIND(y,4,400); /* confine input as piecewise linear */
|
||||
shape[0] = x+2, shape[1] = y+2; bd = (char**)allocarray(2,shape,sizeof(char));
|
||||
memset(*bd,1<<UNKN,shape[0]*shape[1]*sizeof(char)); /* all unknown */
|
||||
for (i = 0; i < shape[0]; ++i) /* border is safe */
|
||||
bd[i][0] = bd[i][shape[1]-1] = 0;
|
||||
for (i = 0; i < shape[1]; ++i)
|
||||
bd[0][i] = bd[shape[0]-1][i] = 0;
|
||||
{
|
||||
time_t seed; /* now I would choose /dev/random */
|
||||
printf("seed is %u\n",(unsigned)seed);
|
||||
time(&seed), SRANDOM((unsigned)seed);
|
||||
}
|
||||
c = BIND(pct,1,99)*x*y/100; /* number of mines to set */
|
||||
while(c) {
|
||||
i = RANDOM(), j = 1+i%y, i = 1+(i>>16)%x;
|
||||
if (! DETECT(bd[i][j],MINE)) /* 1 mine per site */
|
||||
--c, SET_BIT(bd[i][j],MINE);
|
||||
}
|
||||
DEBUG_CODE(matprint(bd,2,shape,sizeof(int),pchr);)
|
||||
RWS = x+1, CLS = y+1; /* shape now stores the upper bounds */
|
||||
}
|
||||
|
||||
struct {
|
||||
int i,j;
|
||||
} neighbor[] = {
|
||||
{-1,-1}, {-1, 0}, {-1, 1},
|
||||
{ 0,-1}, /*home*/ { 0, 1},
|
||||
{ 1,-1}, { 1, 0}, { 1, 1}
|
||||
};
|
||||
/* NEIGHBOR seems to map 0..8 to local 2D positions */
|
||||
#define NEIGHBOR(I,J,K) (bd[(I)+neighbor[K].i][(J)+neighbor[K].j])
|
||||
|
||||
int cnx(int i,int j,char w) { /* count neighbors with property w */
|
||||
int k,c = 0;
|
||||
for (k = 0; k < DIM(neighbor); ++k)
|
||||
c += DETECT(NEIGHBOR(i,j,k),w);
|
||||
return c;
|
||||
}
|
||||
|
||||
int row,col;
|
||||
#define ME bd[row+1][col+1]
|
||||
|
||||
int step(void) {
|
||||
if (DETECT(ME,FLAG)) return 1; /* flags offer protection */
|
||||
if (DETECT(ME,MINE)) return 0; /* lose */
|
||||
CLR_BIT(ME,UNKN);
|
||||
return 1;
|
||||
}
|
||||
|
||||
int autoplay(void) {
|
||||
int i,j,k,change,m;
|
||||
if (!step()) return 0;
|
||||
do /* while changing */
|
||||
for (change = 0, i = 1; i < RWS; ++i)
|
||||
for (j = 1; j < CLS; ++j)
|
||||
if (!DETECT(bd[i][j],UNKN)) { /* consider nghbrs of safe cells */
|
||||
m = cnx(i,j,MINE);
|
||||
if (cnx(i,j,FLAG) == m) { /* mines appear flagged */
|
||||
for (k = 0; k < DIM(neighbor); ++k)
|
||||
if (DETECT(NEIGHBOR(i,j,k),UNKN)&&!DETECT(NEIGHBOR(i,j,k),FLAG)) {
|
||||
if (DETECT(NEIGHBOR(i,j,k),MINE)) { /* OOPS! */
|
||||
row = i+neighbor[k].i-1, col = j+neighbor[k].j-1;
|
||||
return 0;
|
||||
}
|
||||
change = 1, CLR_BIT(NEIGHBOR(i,j,k),UNKN);
|
||||
}
|
||||
} else if (cnx(i,j,UNKN) == m)
|
||||
for (k = 0; k < DIM(neighbor); ++k)
|
||||
if (DETECT(NEIGHBOR(i,j,k),UNKN))
|
||||
change = 1, SET_BIT(NEIGHBOR(i,j,k),FLAG);
|
||||
}
|
||||
while (change);
|
||||
return 1;
|
||||
}
|
||||
|
||||
void takedisplay(void) { initscr(), cbreak(), noecho(), nonl(); }
|
||||
|
||||
void help(void) {
|
||||
move(RWS,1),clrtoeol(), printw("move:hjkl flag:Ff step:Ss other:qd?");
|
||||
}
|
||||
|
||||
void draw(void) {
|
||||
int i,j,w;
|
||||
const char*s1 = " 12345678";
|
||||
move(1,1);
|
||||
for (i = 1; i < RWS; ++i, addstr("\n "))
|
||||
for (j = 1; j < CLS; ++j, addch(' ')) {
|
||||
w = bd[i][j];
|
||||
if (!DETECT(w,UNKN)) {
|
||||
w = cnx(i,j,MINE)-cnx(i,j,FLAG);
|
||||
if (w < 0) attr_on(WA_STANDOUT,NULL), w = -w;
|
||||
addch(s1[w]);
|
||||
attr_off(WA_STANDOUT,NULL);
|
||||
}
|
||||
else if (DETECT(w,FLAG)) addch('F');
|
||||
else addch('*');
|
||||
}
|
||||
move(row+1,2*col+1);
|
||||
refresh();
|
||||
}
|
||||
|
||||
void show(int win) {
|
||||
int i,j,w;
|
||||
const char*s1 = " 12345678";
|
||||
move(1,1);
|
||||
for (i = 1; i < RWS; ++i, addstr("\n "))
|
||||
for (j = 1; j < CLS; ++j, addch(' ')) {
|
||||
w = bd[i][j];
|
||||
if (!DETECT(w,UNKN)) {
|
||||
w = cnx(i,j,MINE)-cnx(i,j,FLAG);
|
||||
if (w < 0) attr_on(WA_STANDOUT,NULL), w = -w;
|
||||
addch(s1[w]);
|
||||
attr_off(WA_STANDOUT,NULL);
|
||||
}
|
||||
else if (DETECT(w,FLAG))
|
||||
if (DETECT(w,MINE)) addch('F');
|
||||
else attr_on(WA_STANDOUT,NULL), addch('F'),attr_off(WA_STANDOUT,NULL);
|
||||
else if (DETECT(w,MINE)) addch('M');
|
||||
else addch('*');
|
||||
}
|
||||
mvaddch(row+1,2*col,'('), mvaddch(row+1,2*(col+1),')');
|
||||
move(RWS,0);
|
||||
refresh();
|
||||
}
|
||||
|
||||
#define HINTBIT(W) s3[DETECT(bd[r][c],(W))]
|
||||
#define NEIGCNT(W) s4[cnx(r,c,(W))]
|
||||
|
||||
const char*s3="01", *s4="012345678";
|
||||
|
||||
void dbg(int r, int c) {
|
||||
int i,j,unkns=0,mines=0,flags=0,pct;
|
||||
char o[6];
|
||||
static int hint;
|
||||
for (i = 1; i < RWS; ++i)
|
||||
for (j = 1; j < CLS; ++j)
|
||||
unkns += DETECT(bd[i][j],UNKN),
|
||||
mines += DETECT(bd[i][j],MINE),
|
||||
flags += DETECT(bd[i][j],FLAG);
|
||||
move(RWS,1), clrtoeol();
|
||||
pct = 0.5+100.0*(mines-flags)/MAX(1,unkns-flags);
|
||||
if (++hint<4)
|
||||
o[0] = HINTBIT(UNKN), o[1] = HINTBIT(MINE), o[2] = HINTBIT(FLAG),
|
||||
o[3] = HINTBIT(UNKN), o[4] = NEIGCNT(MINE), o[5] = NEIGCNT(FLAG);
|
||||
else
|
||||
memset(o,'?',sizeof(o));
|
||||
printw("(%c%c%c) u=%c, m=%c, f=%c, %d/%d (%d%%) remain.",
|
||||
o[0],o[1],o[2],o[3],o[4],o[5],mines-flags,unkns-flags,pct);
|
||||
}
|
||||
#undef NEIGCNT
|
||||
#undef HINTBIT
|
||||
|
||||
void toggleflag(void) {
|
||||
if (DETECT(ME,UNKN))
|
||||
TGL_BIT(ME,FLAG);
|
||||
}
|
||||
int sureflag(void) {
|
||||
toggleflag();
|
||||
return autoplay();
|
||||
}
|
||||
int play(int*win) {
|
||||
int c = getch(), d = tolower(c);
|
||||
if ('q' == d) return 0;
|
||||
else if ('?' == c) help();
|
||||
else if ('h' == d) col = MODDEC(col,CLS-1);
|
||||
else if ('l' == d) col = MODINC(col,CLS-1);
|
||||
else if ('k' == d) row = MODDEC(row,RWS-1);
|
||||
else if ('j' == d) row = MODINC(row,RWS-1);
|
||||
else if ('f' == c) toggleflag();
|
||||
else if ('s' == c) return *win = step();
|
||||
else if ('S' == c) return *win = autoplay();
|
||||
else if ('F' == c) return *win = sureflag();
|
||||
else if ('d' == d) dbg(row+1,col+1);
|
||||
return 1;
|
||||
}
|
||||
|
||||
int convert(const char*name,const char*s) {
|
||||
if (strlen(s) == strspn(s,"0123456789"))
|
||||
return atoi(s);
|
||||
fprintf(stderr," use: %s [rows [columns [percentBombs]]]\n",name);
|
||||
fprintf(stderr,"default: %s 20 30 25\n",name);
|
||||
exit(EXIT_SUCCESS);
|
||||
}
|
||||
|
||||
void parse_command_line(int ac,char*av[],int*a,int*b,int*c) {
|
||||
switch (ac) {
|
||||
default:
|
||||
case 4: *c = convert(*av,av[3]);
|
||||
case 3: *b = convert(*av,av[2]);
|
||||
case 2: *a = convert(*av,av[1]);
|
||||
case 1: ;
|
||||
}
|
||||
}
|
||||
|
||||
int main(int ac,char*av[],char*env[]) {
|
||||
int win = 1, rows = 20, cols = 30, prct = 25;
|
||||
parse_command_line(ac,av,&rows,&cols,&prct);
|
||||
populate(rows,cols,prct);
|
||||
takedisplay();
|
||||
while(draw(), play(&win));
|
||||
show(win);
|
||||
free(bd);
|
||||
# ifdef __unix__
|
||||
{
|
||||
const char*s = "/bin/stty";
|
||||
execl(s,s,"sane",(const char*)NULL);
|
||||
}
|
||||
# endif
|
||||
return 0;
|
||||
}
|
||||
184
Task/Minesweeper-game/C/minesweeper-game-2.c
Normal file
184
Task/Minesweeper-game/C/minesweeper-game-2.c
Normal file
|
|
@ -0,0 +1,184 @@
|
|||
#include <ncurses.h>
|
||||
#include <locale.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
int width = 0, height = 0;
|
||||
int mine_ratio = 10, n_mines;
|
||||
int reveal = 0;
|
||||
|
||||
WINDOW *win, *wrap;
|
||||
|
||||
enum {
|
||||
M_NONE = 0,
|
||||
M_CLEARED = 1 << 0,
|
||||
M_MARKED = 1 << 1,
|
||||
M_MINED = 1 << 2,
|
||||
M_BOMBED = 1 << 3,
|
||||
};
|
||||
typedef struct { unsigned short flag, cnt; } mine_t;
|
||||
|
||||
#define for_i for (int i = 0; i < height; i++)
|
||||
#define for_j for (int j = 0; j < width; j++)
|
||||
void init_mines(void * ptr)
|
||||
{
|
||||
mine_t (*m)[width] = ptr;
|
||||
for_i for_j
|
||||
if (rand() % mine_ratio)
|
||||
m[i][j].flag = M_NONE;
|
||||
else {
|
||||
m[i][j].flag = M_MINED;
|
||||
n_mines ++;
|
||||
}
|
||||
|
||||
for_i for_j {
|
||||
m[i][j].cnt = 0;
|
||||
for (int x = j - 1; x <= j + 1; x++) {
|
||||
if (x < 0 || x > width) continue;
|
||||
for (int y = i - 1; y <= i + 1; y++) {
|
||||
if (y < 0 || y >= width) continue;
|
||||
m[i][j].cnt += 1 && (m[y][x].flag & M_MINED);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int mine_clear(void *ptr, int x, int y, int mass_clear)
|
||||
{
|
||||
mine_t (*m)[width] = ptr;
|
||||
unsigned short flag;
|
||||
if (x < 0 || x >= width || y < 0 || y >= height)
|
||||
return 1;
|
||||
flag = m[y][x].flag;
|
||||
|
||||
if (((flag & M_CLEARED) && 1) != mass_clear) return 1;
|
||||
|
||||
if ((flag & M_MINED) && !(flag & M_MARKED)) {
|
||||
m[y][x].flag |= M_BOMBED;
|
||||
reveal = 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!(flag & M_MARKED))
|
||||
flag = (m[y][x].flag |= M_CLEARED);
|
||||
|
||||
if (m[y][x].cnt && !mass_clear) return 1;
|
||||
if (flag & M_MARKED) return 1;
|
||||
|
||||
for (int i = y - 1; i <= y + 1; i++)
|
||||
for (int j = x - 1; j <= x + 1; j++)
|
||||
if (!mine_clear(ptr, j, i, 0)) return 0;
|
||||
return 1;
|
||||
}
|
||||
|
||||
void mine_mark(void *ptr, int x, int y)
|
||||
{
|
||||
mine_t (*m)[width] = ptr;
|
||||
if (m[y][x].flag & M_CLEARED) return;
|
||||
if (m[y][x].flag & M_MARKED)
|
||||
n_mines ++;
|
||||
else
|
||||
n_mines --;
|
||||
m[y][x].flag ^= M_MARKED;
|
||||
}
|
||||
|
||||
int check_wining(void *ptr)
|
||||
{
|
||||
mine_t (*m)[width] = ptr;
|
||||
int good = 1;
|
||||
for_i for_j {
|
||||
int f = m[i][j].flag;
|
||||
if ((f & M_MINED) && !(f & M_MARKED)) {
|
||||
m[i][j].flag = M_BOMBED;
|
||||
good = 0;
|
||||
}
|
||||
}
|
||||
mvwprintw(wrap, height + 1, 0, good ? "All clear! " : "BOOM! ");
|
||||
reveal = 1;
|
||||
return good;
|
||||
}
|
||||
|
||||
void repaint(void *ptr)
|
||||
{
|
||||
mine_t (*m)[width] = ptr, *p;
|
||||
box(win, 0, 0);
|
||||
for_i for_j {
|
||||
char c;
|
||||
p = &m[i][j];
|
||||
int f = p->flag;
|
||||
if (reveal)
|
||||
c = (f & M_BOMBED) ? 'X' : (f & M_MINED) ? 'o' : ' ';
|
||||
else if (p->flag & M_BOMBED)
|
||||
c = 'X';
|
||||
else if (p->flag & M_MARKED)
|
||||
c = '?';
|
||||
else if (p->flag & M_CLEARED)
|
||||
c = p->cnt ? p->cnt + '0' : ' ';
|
||||
else
|
||||
c = '.';
|
||||
mvwprintw(win, i + 1, 2 * j + 1, " %c", c);
|
||||
}
|
||||
if (reveal);
|
||||
else if (n_mines)
|
||||
mvwprintw(wrap, height + 1, 0, "Mines:%6d ", n_mines);
|
||||
else
|
||||
mvwprintw(wrap, height + 1, 0, "Claim victory? ");
|
||||
wrefresh(wrap);
|
||||
wrefresh(win);
|
||||
}
|
||||
|
||||
int main(int c, char **v)
|
||||
{
|
||||
MEVENT evt;
|
||||
|
||||
printf("%d\n", c);
|
||||
|
||||
if (c >= 3) {
|
||||
height = atoi(v[1]);
|
||||
width = atoi(v[2]);
|
||||
}
|
||||
if (height < 3) height = 15;
|
||||
if (width < 3) width = 30;
|
||||
|
||||
initscr();
|
||||
int mines[height][width];
|
||||
init_mines(mines);
|
||||
|
||||
win = newwin(height + 2, 2 * width + 2, 0, 0);
|
||||
wrap = newwin(height + 3, 2 * width + 2, 1, 0);
|
||||
|
||||
keypad(wrap, 1);
|
||||
mousemask(BUTTON1_CLICKED | BUTTON2_CLICKED | BUTTON3_CLICKED, 0);
|
||||
|
||||
while (1) {
|
||||
int ch;
|
||||
repaint(mines);
|
||||
if ((ch = wgetch(wrap)) != KEY_MOUSE) {
|
||||
if (ch != 'r') break;
|
||||
reveal = !reveal;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (getmouse(&evt) != OK) continue;
|
||||
|
||||
if ((evt.bstate & BUTTON1_CLICKED)) {
|
||||
if (evt.y == height + 2 && !n_mines) {
|
||||
check_wining(mines);
|
||||
break;
|
||||
}
|
||||
if (!mine_clear(mines, (evt.x - 1) / 2, evt.y - 1, 0))
|
||||
break;
|
||||
}
|
||||
else if ((evt.bstate & BUTTON2_CLICKED)) {
|
||||
if (!mine_clear(mines, (evt.x - 1) / 2, evt.y - 1, 1))
|
||||
break;
|
||||
}
|
||||
else if ((evt.bstate & BUTTON3_CLICKED))
|
||||
mine_mark(mines, (evt.x - 1)/2, evt.y - 1);
|
||||
}
|
||||
repaint(mines);
|
||||
|
||||
mousemask(0, 0);
|
||||
keypad(wrap, 0);
|
||||
endwin();
|
||||
return 0;
|
||||
}
|
||||
78
Task/Minesweeper-game/Clojure/minesweeper-game.clj
Normal file
78
Task/Minesweeper-game/Clojure/minesweeper-game.clj
Normal file
|
|
@ -0,0 +1,78 @@
|
|||
(defn take-random [n coll]
|
||||
(->> (repeatedly #(rand-nth coll))
|
||||
distinct
|
||||
(take n ,)))
|
||||
|
||||
(defn postwalk-fs
|
||||
"Depth first post-order traversal of form, apply successive fs at each level.
|
||||
(f1 (map f2 [..]))"
|
||||
[[f & fs] form]
|
||||
(f
|
||||
(if (and (seq fs) (coll? form))
|
||||
(into (empty form) (map (partial postwalk-fs fs) form))
|
||||
form)))
|
||||
|
||||
(defn neighbors [x y n m pred]
|
||||
(for [dx (range (Math/max 0 (dec x)) (Math/min n (+ 2 x)))
|
||||
dy (range (Math/max 0 (dec y)) (Math/min m (+ 2 y)))
|
||||
:when (pred dx dy)]
|
||||
[dx dy]))
|
||||
|
||||
(defn new-game [n m density]
|
||||
(let [mines (set (take-random (Math/floor (* n m density)) (range (* n m))))]
|
||||
(->> (for [y (range m)
|
||||
x (range n)
|
||||
:let [neighbor-mines (count (neighbors x y n m #(mines (+ %1 (* %2 n)))))]]
|
||||
(#(if (mines (+ (* y n) x)) (assoc % :mine true) %) {:value neighbor-mines}))
|
||||
(partition n ,)
|
||||
(postwalk-fs [vec vec] ,))))
|
||||
|
||||
(defn display [board]
|
||||
(postwalk-fs [identity println #(condp % nil
|
||||
:marked \?
|
||||
:opened (:value %)
|
||||
\.)] board))
|
||||
|
||||
(defn boom [{board :board}]
|
||||
(postwalk-fs [identity println #(if (:mine %) \* (:value %))] board)
|
||||
true)
|
||||
|
||||
(defn open* [board [[x y] & rest]]
|
||||
(if-let [value (get-in board [y x :value])] ; if nil? value -> nil? x -> nil? queue
|
||||
(recur
|
||||
(assoc-in board [y x :opened] true)
|
||||
(if (pos? value)
|
||||
rest
|
||||
(concat rest
|
||||
(neighbors x y (count (first board)) (count board)
|
||||
#(not (get-in board [%2 %1 :opened]))))))
|
||||
board))
|
||||
|
||||
(defn open [board x y]
|
||||
(let [x (dec x), y (dec y)]
|
||||
(condp (get-in board [y x]) nil
|
||||
:mine {:boom true :board board}
|
||||
:opened board
|
||||
(open* board [[x y]]))))
|
||||
|
||||
(defn mark [board x y]
|
||||
(let [x (dec x), y (dec y)]
|
||||
(assoc-in board [y x :marked] (not (get-in board [y x :marked])))))
|
||||
|
||||
(defn done? [board]
|
||||
(if (:boom board)
|
||||
(boom board)
|
||||
(do (display board)
|
||||
(->> (flatten board)
|
||||
(remove :mine ,)
|
||||
(every? :opened ,)))))
|
||||
|
||||
(defn play [n m density]
|
||||
(let [board (new-game n m density)]
|
||||
(println [:mines (count (filter :mine (flatten board)))])
|
||||
(loop [board board]
|
||||
(when-not (done? board)
|
||||
(print ">")
|
||||
(let [[cmd & xy] (.split #" " (read-line))
|
||||
[x y] (map #(Integer. %) xy)]
|
||||
(recur ((if (= cmd "mark") mark open) board x y)))))))
|
||||
87
Task/Minesweeper-game/Common-Lisp/minesweeper-game.lisp
Normal file
87
Task/Minesweeper-game/Common-Lisp/minesweeper-game.lisp
Normal file
|
|
@ -0,0 +1,87 @@
|
|||
(defclass minefield ()
|
||||
((mines :initform (make-hash-table :test #'equal))
|
||||
(width :initarg :width)
|
||||
(height :initarg :height)
|
||||
(grid :initarg :grid)))
|
||||
|
||||
(defun make-minefield (width height num-mines)
|
||||
(let ((minefield (make-instance 'minefield
|
||||
:width width
|
||||
:height height
|
||||
:grid (make-array
|
||||
(list width height)
|
||||
:initial-element #\.)))
|
||||
(mine-count 0))
|
||||
(with-slots (grid mines) minefield
|
||||
(loop while (< mine-count num-mines)
|
||||
do (let ((coords (list (random width) (random height))))
|
||||
(unless (gethash coords mines)
|
||||
(setf (gethash coords mines) T)
|
||||
(incf mine-count))))
|
||||
minefield)))
|
||||
|
||||
(defun print-field (minefield)
|
||||
(with-slots (width height grid) minefield
|
||||
(dotimes (y height)
|
||||
(dotimes (x width)
|
||||
(princ (aref grid x y)))
|
||||
(format t "~%"))))
|
||||
|
||||
(defun mine-list (minefield)
|
||||
(loop for key being the hash-keys of (slot-value minefield 'mines) collect key))
|
||||
|
||||
(defun count-nearby-mines (minefield coords)
|
||||
(length (remove-if-not
|
||||
(lambda (mine-coord)
|
||||
(and
|
||||
(> 2 (abs (- (car coords) (car mine-coord))))
|
||||
(> 2 (abs (- (cadr coords) (cadr mine-coord))))))
|
||||
(mine-list minefield))))
|
||||
|
||||
(defun clear (minefield coords)
|
||||
(with-slots (mines grid) minefield
|
||||
(if (gethash coords mines)
|
||||
(progn
|
||||
(format t "MINE! You lose.~%")
|
||||
(dolist (mine-coords (mine-list minefield))
|
||||
(setf (aref grid (car mine-coords) (cadr mine-coords)) #\x))
|
||||
(setf (aref grid (car coords) (cadr coords)) #\X)
|
||||
nil)
|
||||
(setf (aref grid (car coords) (cadr coords))
|
||||
(elt " 123456789"(count-nearby-mines minefield coords))))))
|
||||
|
||||
(defun mark (minefield coords)
|
||||
(with-slots (mines grid) minefield
|
||||
(setf (aref grid (car coords) (cadr coords)) #\?)))
|
||||
|
||||
(defun win-p (minefield)
|
||||
(with-slots (width height grid mines) minefield
|
||||
(let ((num-uncleared 0))
|
||||
(dotimes (y height)
|
||||
(dotimes (x width)
|
||||
(let ((square (aref grid x y)))
|
||||
(when (member square '(#\. #\?) :test #'char=)
|
||||
(incf num-uncleared)))))
|
||||
(= num-uncleared (hash-table-count mines)))))
|
||||
|
||||
(defun play-game ()
|
||||
(let ((minefield (make-minefield 6 4 5)))
|
||||
(format t "Greetings player, there are ~a mines.~%"
|
||||
(hash-table-count (slot-value minefield 'mines)))
|
||||
(loop
|
||||
(print-field minefield)
|
||||
(format t "Enter your command, examples: \"clear 0 1\" \"mark 1 2\" \"quit\".~%")
|
||||
(princ "> ")
|
||||
(let ((user-command (read-from-string (format nil "(~a)" (read-line)))))
|
||||
(format t "Your command: ~a~%" user-command)
|
||||
(case (car user-command)
|
||||
(quit (return-from play-game nil))
|
||||
(clear (unless (clear minefield (cdr user-command))
|
||||
(print-field minefield)
|
||||
(return-from play-game nil)))
|
||||
(mark (mark minefield (cdr user-command))))
|
||||
(when (win-p minefield)
|
||||
(format t "Congratulations, you've won!")
|
||||
(return-from play-game T))))))
|
||||
|
||||
(play-game)
|
||||
1
Task/Minesweeper-game/GUISS/minesweeper-game.guiss
Normal file
1
Task/Minesweeper-game/GUISS/minesweeper-game.guiss
Normal file
|
|
@ -0,0 +1 @@
|
|||
Start,Programs,Games,Minesweeper
|
||||
181
Task/Minesweeper-game/Icon/minesweeper-game.icon
Normal file
181
Task/Minesweeper-game/Icon/minesweeper-game.icon
Normal file
|
|
@ -0,0 +1,181 @@
|
|||
global DEFARGS,MF
|
||||
|
||||
record minefield(mask,grid,rows,cols,mines,density,marked)
|
||||
|
||||
$define _DEFAULTS [6, 4, .2, .6] # task defaults
|
||||
#$define _DEFAULTS [6, 7, .05, .1] # defaults for debugging
|
||||
$define _INDENT 6
|
||||
$define _MINE "Y"
|
||||
$define _TRUEMINE "Y"
|
||||
$define _FALSEMINE "N"
|
||||
$define _MASK "."
|
||||
$define _MARK "?"
|
||||
$define _TOGGLE1 ".?"
|
||||
$define _TOGGLE2 "?."
|
||||
|
||||
procedure main(arglist) #: play the game
|
||||
static trace
|
||||
initial trace := -1
|
||||
|
||||
DEFARGS := _DEFAULTS
|
||||
if *arglist = 0 then arglist := DEFARGS
|
||||
|
||||
newgame!arglist
|
||||
while c := trim(read()) do {
|
||||
c ? { tab(many(' '))
|
||||
case move(1) of {
|
||||
# required commands
|
||||
"c": clear() & showgrid() # c clear 1 sq and show
|
||||
"m": mark() # m flag/unflag a mine
|
||||
"p": showgrid() # p show the mine field
|
||||
"r": endgame("Resigning.") # r resign this game
|
||||
# optional commands
|
||||
"n": newgame!arglist # n new game grid
|
||||
"k": clearunmarked() & showgrid() # k clears adjecent unmarked cells if #flags = count
|
||||
"x": clearallunmarked() # x clears every unflagged cell at once win/loose fast
|
||||
"q": stop("Quitting") # q quit
|
||||
"t": &trace :=: trace # t toggle tracing for debugging
|
||||
default: usage()
|
||||
}}
|
||||
testforwin(g)
|
||||
}
|
||||
end
|
||||
|
||||
procedure newgame(r,c,l,h) #: start a new game
|
||||
local i,j,t
|
||||
|
||||
MF := minefield()
|
||||
|
||||
MF.rows := 0 < integer(\r) | DEFARGS[1]
|
||||
MF.cols := 0 < integer(\c) | DEFARGS[2]
|
||||
|
||||
every !(MF.mask := list(MF.rows)) := list(MF.cols,_MASK) # set mask
|
||||
every !(MF.grid := list(MF.rows)) := list(MF.cols,0) # default count
|
||||
|
||||
l := 1 > (0 < real(\l)) | DEFARGS[3]
|
||||
h := 1 > (0 < real(\h)) | DEFARGS[4]
|
||||
if l > h then l :=: h
|
||||
|
||||
until MF.density := l <= ( h >= ?0 ) # random density between l:h
|
||||
MF.mines := integer(MF.rows * MF.cols * MF.density) # mines needed
|
||||
MF.marked := 0
|
||||
|
||||
write("Creating ",r,"x",c," mine field with ",MF.mines," (",MF.density * 100,"%).")
|
||||
every 1 to MF.mines do until \MF.grid[r := ?MF.rows, c := ?MF.cols] := &null # set mines
|
||||
every \MF.grid[i := 1 to MF.rows,j:= 1 to MF.cols] +:= (/MF.grid[i-1 to i+1,j-1 to j+1], 1) # set counts
|
||||
|
||||
showgrid()
|
||||
return
|
||||
end
|
||||
|
||||
procedure usage() #: show usage
|
||||
return write(
|
||||
"h or ? - this help\n",
|
||||
"n - start a new game\n",
|
||||
"c i j - clears x,y and displays the grid\n",
|
||||
"m i j - marks (toggles) x,y\n",
|
||||
"p - displays the grid\n",
|
||||
"k i j - clears adjecent unmarked cells if #marks = count\n",
|
||||
"x - clears ALL unmarked flags at once\n",
|
||||
"r - resign the game\n",
|
||||
"q - quit the game\n",
|
||||
"where i is the (vertical) row number and j is the (horizontal) column number." )
|
||||
end
|
||||
|
||||
procedure getn(n) #: command parsing
|
||||
tab(many(' '))
|
||||
if n := n >= ( 0 < integer(tab(many(&digits)))) then return n
|
||||
else write("Invalid or out of bounds grid square.")
|
||||
end
|
||||
|
||||
procedure showgrid() #: show grid
|
||||
local r,c,x
|
||||
|
||||
write(right("",_INDENT)," ",repl("----+----|",MF.cols / 10 + 1)[1+:MF.cols])
|
||||
every r := 1 to *MF.mask do {
|
||||
writes(right(r,_INDENT)," : ")
|
||||
every c := 1 to *MF.mask[r] do
|
||||
writes( \MF.mask[r,c] | map(\MF.grid[r,c],"0"," ") | _MINE)
|
||||
write()
|
||||
}
|
||||
write(MF.marked," marked mines and ",MF.mines - MF.marked," mines left to be marked.")
|
||||
end
|
||||
|
||||
procedure mark() #: mark/toggle squares
|
||||
local i,j
|
||||
|
||||
if \MF.mask[i := getn(MF.rows), j :=getn(MF.cols)] := map(MF.mask[i,j],_TOGGLE1,_TOGGLE2) then {
|
||||
case MF.mask[i,j] of {
|
||||
_MASK : MF.marked -:= 1
|
||||
_MARK : MF.marked +:= 1
|
||||
}
|
||||
}
|
||||
end
|
||||
|
||||
procedure clear() #: clear a square
|
||||
local i,j
|
||||
|
||||
if ( i := getn(MF.rows) ) & ( j :=getn(MF.cols) ) then
|
||||
if /MF.mask[i,j] then
|
||||
write(i," ",j," was already clear")
|
||||
else if /MF.grid[i,j] then endgame("KABOOM! You lost.")
|
||||
else return revealclearing(i,j)
|
||||
end
|
||||
|
||||
procedure revealclearing(i,j) #: reaveal any clearing
|
||||
|
||||
if \MF.mask[i,j] := &null then {
|
||||
if MF.grid[i,j] = 0 then
|
||||
every revealclearing(i-1 to i+1,j-1 to j+1)
|
||||
return
|
||||
}
|
||||
end
|
||||
|
||||
procedure clearunmarked() #: clears adjecent unmarked cells if #flags = count
|
||||
local i,j,k,m,n
|
||||
|
||||
if ( i := getn(MF.rows) ) & ( j :=getn(MF.cols) ) then
|
||||
if /MF.mask[i,j] & ( k := 0 < MF.grid[i,j] ) then {
|
||||
every (\MF.mask[i-1 to i+1,j-1 to j+1] == _MARK) & ( k -:= 1)
|
||||
if k = 0 then {
|
||||
every (m := i-1 to i+1) & ( n := j-1 to j+1) do
|
||||
if \MF.mask[m,n] == _MASK then MF.mask[m,n] := &null
|
||||
revealclearing(i,j)
|
||||
return
|
||||
}
|
||||
else
|
||||
write("Marked squares must match adjacent mine count.")
|
||||
}
|
||||
else write("Must be adjecent to one or more marks to clear surrounding squares.")
|
||||
end
|
||||
|
||||
procedure clearallunmarked() #: fast win or loose
|
||||
local i,j,k
|
||||
|
||||
every (i := 1 to MF.rows) & (j := 1 to MF.cols) do {
|
||||
if \MF.mask[i,j] == _MASK then {
|
||||
MF.mask[i,j] := &null
|
||||
if /MF.grid[i,j] then k := 1
|
||||
}
|
||||
}
|
||||
if \k then endgame("Kaboom - you loose.")
|
||||
end
|
||||
|
||||
procedure testforwin() #: win when rows*cols-#_MARK-#_MASK are clear and no Kaboom
|
||||
local t,x
|
||||
|
||||
t := MF.rows * MF.cols - MF.mines
|
||||
every x := !!MF.mask do if /x then t -:= 1
|
||||
if t = 0 then endgame("You won!")
|
||||
end
|
||||
|
||||
procedure endgame(tag) #: end the game
|
||||
local i,j,m
|
||||
|
||||
every !(m := list(MF.rows)) := list(MF.cols) # new mask
|
||||
every (i := 1 to MF.rows) & (j := 1 to MF.cols) do
|
||||
if \MF.mask[i,j] == _MARK then
|
||||
m[i,j] := if /MF.grid[i,j] then _TRUEMINE else _FALSEMINE
|
||||
MF.mask := m
|
||||
write(tag) & showgrid()
|
||||
end
|
||||
100
Task/Minesweeper-game/J/minesweeper-game-1.j
Normal file
100
Task/Minesweeper-game/J/minesweeper-game-1.j
Normal file
|
|
@ -0,0 +1,100 @@
|
|||
NB. minefield.ijs script
|
||||
NB. =========================================================
|
||||
NB. Game engine
|
||||
|
||||
NB.require 'guid'
|
||||
NB.([ 9!:1) _2 (3!:4) , guids 1 NB. randomly set initial random seed
|
||||
|
||||
coclass 'mineswpeng'
|
||||
|
||||
newMinefield=: 3 : 0
|
||||
if. 0=#y do. y=. 9 9 end.
|
||||
Marked=: Cleared=: y$0
|
||||
NMines=: <. */(0.01*10+?20),y NB. 10..20% of tiles are mines
|
||||
mines=. (i. e. NMines ? */) y NB. place mines
|
||||
Map=: (9*mines) >. y{. (1,:3 3) +/@,;.3 (-1+y){.mines
|
||||
)
|
||||
|
||||
markTiles=: 3 : 0
|
||||
Marked=: (<"1 <:y) (-.@{)`[`]} Marked NB. toggle marked state of cell(s)
|
||||
)
|
||||
|
||||
clearTiles=: clearcell@:<: NB. decrement coords - J arrays are 0-based
|
||||
|
||||
clearcell=: verb define
|
||||
if. #y do.
|
||||
free=. (#~ (Cleared < 0 = Map) {~ <"1) y
|
||||
Cleared=: 1 (<"1 y)} Cleared NB. set cell(s) as cleared
|
||||
if. #free do.
|
||||
clearcell (#~ Cleared -.@{~ <"1) ~. (<:$Map) (<."1) 0 >. getNbrs free
|
||||
end.
|
||||
end.
|
||||
)
|
||||
|
||||
getNbrs=: [: ,/^:(3=#@$) +"1/&(<: 3 3#: i.9)
|
||||
|
||||
eval=: verb define
|
||||
if. 9 e. Cleared #&, Map do. NB. cleared mine(s)?
|
||||
1; 'KABOOM!!'
|
||||
elseif. *./ 9 = (-.Cleared) #&, Map do. NB. all cleared except mines?
|
||||
1; 'Minefield cleared.'
|
||||
elseif. do. NB. else...
|
||||
0; (": +/, Marked>Cleared),' of ',(":NMines),' mines marked.'
|
||||
end. NB. result: isEnd; message
|
||||
)
|
||||
|
||||
showField=: 4 : 0
|
||||
idx=. y{ (2 <. Marked + +:Cleared) ,: 2
|
||||
|: idx} (11&{ , 12&{ ,: Map&{) x NB. transpose result - J arrays are row,column
|
||||
)
|
||||
|
||||
NB. =========================================================
|
||||
NB. User interface
|
||||
|
||||
Minesweeper_z_=: conew&'mineswp'
|
||||
|
||||
coclass 'mineswp'
|
||||
coinsert 'mineswpeng' NB. insert game engine locale in copath
|
||||
|
||||
Tiles=: ' 12345678**.?'
|
||||
|
||||
create=: ] startgame@[ smoutput bind Instructions
|
||||
destroy=: codestroy
|
||||
quit=: destroy
|
||||
|
||||
startgame=: update@newMinefield
|
||||
clear=: update@clearTiles
|
||||
mark=: update@markTiles
|
||||
|
||||
update=: 3 : 0
|
||||
'isend msg'=. eval ''
|
||||
smoutput msg
|
||||
smoutput < Tiles showField isend
|
||||
if. isend do.
|
||||
msg=. ('K'={.msg) {:: 'won';'lost'
|
||||
smoutput 'You ',msg,'! Try again?'
|
||||
destroy ''
|
||||
end.
|
||||
empty''
|
||||
)
|
||||
|
||||
Instructions=: 0 : 0
|
||||
=== MineSweeper ===
|
||||
Object:
|
||||
Uncover (clear) all the tiles that are not mines.
|
||||
|
||||
How to play:
|
||||
- the left, top tile is: 1 1
|
||||
- clear an uncleared tile (.) using the command:
|
||||
clear__fld <column index> <row index>
|
||||
- mark and uncleared tile (?) as a suspected mine using the command:
|
||||
mark__fld <column index> <row index>
|
||||
- if you uncover a number, that is the number of mines adjacent
|
||||
to the tile
|
||||
- if you uncover a mine (*) the game ends (you lose)
|
||||
- if you uncover all tiles that are not mines the game ends (you win).
|
||||
- quit a game before winning or losing using the command:
|
||||
quit__fld ''
|
||||
- start a new game using the command:
|
||||
fld=: MineSweeper <num columns> <num rows>
|
||||
)
|
||||
99
Task/Minesweeper-game/J/minesweeper-game-2.j
Normal file
99
Task/Minesweeper-game/J/minesweeper-game-2.j
Normal file
|
|
@ -0,0 +1,99 @@
|
|||
load 'minefield.ijs'
|
||||
fld=: Minesweeper 6 4
|
||||
=== MineSweeper ===
|
||||
Object:
|
||||
Uncover (clear) all the tiles that are not mines.
|
||||
|
||||
How to play:
|
||||
- the left, top tile is: 1 1
|
||||
- clear an uncleared tile (.) using the command:
|
||||
clear__fld <column index> <row index>
|
||||
- mark and uncleared tile (?) as a suspected mine using the command:
|
||||
mark__fld <column index> <row index>
|
||||
- if you uncover a number, that is the number of mines adjacent
|
||||
to the tile
|
||||
- if you uncover a mine (*) the game ends (you lose)
|
||||
- if you uncover all tiles that are not mines the game ends (you win).
|
||||
- quit a game before winning or losing using the command:
|
||||
quit__fld ''
|
||||
- start a new game using the command:
|
||||
fld=: MineSweeper <num columns> <num rows>
|
||||
|
||||
0 of 5 mines marked.
|
||||
┌──────┐
|
||||
│......│
|
||||
│......│
|
||||
│......│
|
||||
│......│
|
||||
└──────┘
|
||||
clear__fld 1 1
|
||||
0 of 5 mines marked.
|
||||
┌──────┐
|
||||
│2.....│
|
||||
│......│
|
||||
│......│
|
||||
│......│
|
||||
└──────┘
|
||||
clear__fld 6 4
|
||||
0 of 5 mines marked.
|
||||
┌──────┐
|
||||
│2..2 │
|
||||
│...2 │
|
||||
│..31 │
|
||||
│..1 │
|
||||
└──────┘
|
||||
mark__fld 3 1 ,: 3 2 NB. mark and clear both accept lists of coordinates
|
||||
2 of 5 mines marked.
|
||||
┌──────┐
|
||||
│2.?2 │
|
||||
│..?2 │
|
||||
│..31 │
|
||||
│..1 │
|
||||
└──────┘
|
||||
clear__fld 1 2 , 1 3 ,: 1 4
|
||||
2 of 5 mines marked.
|
||||
┌──────┐
|
||||
│2.?2 │
|
||||
│3.?2 │
|
||||
│2.31 │
|
||||
│1.1 │
|
||||
└──────┘
|
||||
clear__fld 2 1
|
||||
KABOOM!!
|
||||
┌──────┐
|
||||
│2**2 │
|
||||
│3**2 │
|
||||
│2*31 │
|
||||
│111 │
|
||||
└──────┘
|
||||
You lost! Try again?
|
||||
fld=: Minesweeper 20 10 NB. create bigger minefield
|
||||
... NB. instructions elided
|
||||
0 of 50 mines marked.
|
||||
┌────────────────────┐
|
||||
│....................│
|
||||
│....................│
|
||||
│....................│
|
||||
│....................│
|
||||
│....................│
|
||||
│....................│
|
||||
│....................│
|
||||
│....................│
|
||||
│....................│
|
||||
│....................│
|
||||
└────────────────────┘
|
||||
clear__fld >: 4$.$. 9 > Map__fld NB. Autosolve ;-)
|
||||
Minefield cleared.
|
||||
┌────────────────────┐
|
||||
│1***2**2**2*2*2*1111│
|
||||
│123222222221212222*1│
|
||||
│11 1223*421│
|
||||
│*3321 11223**5**1 │
|
||||
│3***211 1*2**6**432 │
|
||||
│2*433*222223**423*2 │
|
||||
│1111*4*4*2 13*2 3*41│
|
||||
│11112*3**321211 2**1│
|
||||
│3*3112334*3*211 1332│
|
||||
│***1 1*12*312*1 1*1│
|
||||
└────────────────────┘
|
||||
You won! Try again?
|
||||
114
Task/Minesweeper-game/Locomotive-Basic/minesweeper-game.bas
Normal file
114
Task/Minesweeper-game/Locomotive-Basic/minesweeper-game.bas
Normal file
|
|
@ -0,0 +1,114 @@
|
|||
10 mode 1:randomize time
|
||||
20 defint a-z
|
||||
30 boardx=6:boardy=4
|
||||
40 dim a(boardx,boardy)
|
||||
50 dim c(boardx+2,boardy+2)
|
||||
60 dim c2(boardx+2,boardy+2)
|
||||
70 nmines=int((rnd/3+.1)*boardx*boardy)
|
||||
80 for i=1 to nmines
|
||||
90 ' place random mines
|
||||
100 xp=int(rnd*(boardx-1)+1)
|
||||
110 yp=int(rnd*(boardy-1)+1)
|
||||
120 if a(xp,yp) then 100
|
||||
130 a(xp,yp)=64
|
||||
140 for xx=xp to xp+2
|
||||
150 for yy=yp to yp+2
|
||||
160 c(xx,yy)=c(xx,yy)+1
|
||||
170 next yy
|
||||
180 next xx
|
||||
190 next i
|
||||
200 gosub 350
|
||||
210 x=1:y=1
|
||||
220 gosub 600
|
||||
230 ' wait for key press
|
||||
240 k$=lower$(inkey$)
|
||||
250 if k$="" then 240
|
||||
260 if k$="q" and y>1 then gosub 660:y=y-1:gosub 600
|
||||
270 if k$="a" and y<boardy then gosub 660:y=y+1:gosub 600
|
||||
280 if k$="o" and x>1 then gosub 660:x=x-1:gosub 600
|
||||
290 if k$="p" and x<boardx then gosub 660:x=x+1:gosub 600
|
||||
300 if k$="m" then a(x,y)=a(x,y) xor 128:gosub 600:gosub 1070
|
||||
310 if k$=" " then a(x,y)=a(x,y) or 512:gosub 700:sx=x:sy=y:gosub 450:x=sx:y=sy:gosub 600
|
||||
320 goto 240
|
||||
330 end
|
||||
340 ' print board
|
||||
350 mode 1
|
||||
360 gosub 450
|
||||
370 locate 1,12
|
||||
380 print "Move on the board with the Q,A,O,P keys"
|
||||
390 print "Press Space to clear"
|
||||
400 print "Press M to mark as a potential mine"
|
||||
410 print
|
||||
420 print "There are"nmines"mines."
|
||||
430 return
|
||||
440 ' update board
|
||||
450 for y=1 to boardy
|
||||
460 for x=1 to boardx
|
||||
470 locate 2*x,y
|
||||
480 gosub 530
|
||||
490 next
|
||||
500 next
|
||||
510 return
|
||||
520 ' print tile
|
||||
530 if a(x,y) and 128 then print "?":return
|
||||
540 if c(x+1,y+1)=0 then d$=" " else d$=chr$(c(x+1,y+1)+48)
|
||||
550 if a(x,y) and 256 then print d$:return
|
||||
560 'if a(x,y) and 64 then print "M":return
|
||||
570 print "."
|
||||
580 return
|
||||
590 ' turn on tile
|
||||
600 locate 2*x,y
|
||||
610 pen 0:paper 1
|
||||
620 gosub 530
|
||||
630 pen 1:paper 0
|
||||
640 return
|
||||
650 ' turn off tile
|
||||
660 locate 2*x,y
|
||||
670 gosub 530
|
||||
680 return
|
||||
690 ' clear tile
|
||||
700 if a(x,y) and 64 then locate 15,20:print "*** BOOM! ***":end
|
||||
710 locate 1,25:print "-WAIT-";
|
||||
720 for x2=1 to boardx
|
||||
730 for y2=1 to boardy
|
||||
740 c2(x2+1,y2+1)=a(x2,y2)
|
||||
750 next
|
||||
760 next
|
||||
770 ' iterate clearing
|
||||
780 cl=0
|
||||
790 for x2=1 to boardx
|
||||
800 for y2=1 to boardy
|
||||
810 if c2(x2+1,y2+1) and 512 then gosub 940:cl=cl+1
|
||||
820 next y2
|
||||
830 next x2
|
||||
840 if cl then 780
|
||||
850 for x2=1 to boardx
|
||||
860 for y2=1 to boardy
|
||||
870 vv=c2(x2+1,y2+1)
|
||||
880 if vv>1000 then a(x2,y2)=vv xor 1024
|
||||
890 next y2
|
||||
900 next x2
|
||||
910 locate 1,25:print " ";
|
||||
920 return
|
||||
930 ' find neighbors
|
||||
940 c2(x2+1,y2+1)=(c2(x2+1,y2+1) xor 512) or 256 or 1024
|
||||
950 for ii=0 to 2
|
||||
960 for jj=0 to 2
|
||||
970 if ii=0 and jj=0 then 1030
|
||||
980 if c2(x2+ii,y2+jj) and 64 then 1030
|
||||
990 if c2(x2+ii,y2+jj) and 128 then 1030
|
||||
1000 if c2(x2+ii,y2+jj) and 1024 then 1030
|
||||
1010 c2(x2+ii,y2+jj)=c2(x2+ii,y2+jj) or 512
|
||||
1020 ' next tile
|
||||
1030 next jj
|
||||
1040 next ii
|
||||
1050 return
|
||||
1060 ' update discovered mine count
|
||||
1070 mm=0
|
||||
1080 for x2=1 to boardx
|
||||
1090 for y2=1 to boardy
|
||||
1100 if (a(x2,y2) and 128)>0 and (a(x2,y2) and 64)>0 then mm=mm+1
|
||||
1110 next
|
||||
1120 next
|
||||
1130 if mm=nmines then locate 5,22:print "Congratulations, you've won!":end
|
||||
1140 return
|
||||
|
|
@ -0,0 +1,46 @@
|
|||
DynamicModule[{m = 6, n = 4, minecount, grid, win, reset, clear,
|
||||
checkwin},
|
||||
reset[] :=
|
||||
Module[{minesdata, adjacentmines},
|
||||
minecount = RandomInteger[Round[{.1, .2} m*n]];
|
||||
minesdata =
|
||||
Normal@SparseArray[# -> 1 & /@
|
||||
RandomSample[Tuples[Range /@ {m, n}], minecount], {m, n}];
|
||||
adjacentmines =
|
||||
ArrayPad[
|
||||
Total[RotateLeft[
|
||||
ArrayPad[minesdata,
|
||||
1], #] & /@ {{-1, -1}, {0, -1}, {1, -1}, {-1, 0}, {1,
|
||||
0}, {-1, 1}, {0, 1}, {1, 1}}], -1];
|
||||
grid = Array[{If[minesdata[[#1, #2]] == 1, "*",
|
||||
adjacentmines[[#1, #2]]], ".", 1} &, {m, n}]; win = ""];
|
||||
clear[i_, j_] :=
|
||||
If[grid[[i, j, 1]] == "*", win = "You lost.";
|
||||
grid = grid /. {{n_Integer, "?", _} :> {n, "x", 0}, {"*",
|
||||
".", _} :> {"*", "*", 0}},
|
||||
grid[[i, j]] = {grid[[i, j, 1]], grid[[i, j, 1]], 0};
|
||||
If[grid[[i, j, 2]] == 0, grid[[i, j, 2]] = "";
|
||||
clear[i + #[[1]],
|
||||
j + #[[2]]] & /@ {{-1, -1}, {0, -1}, {1, -1}, {-1, 0}, {1,
|
||||
0}, {-1, 1}, {0, 1}, {1, 1}}]] /;
|
||||
1 <= i <= m && 1 <= j <= n && grid[[i, j, 2]] == ".";
|
||||
checkwin[] :=
|
||||
If[FreeQ[grid, {_Integer, "?", _} | {_, "*", _} | {_Integer,
|
||||
".", _}], win = "You win.";
|
||||
grid = grid /. {{"*", ".", _} :> {"*", "?", 1}}];
|
||||
reset[];
|
||||
Panel@Column@{Row@{Dynamic@minecount, "\t",
|
||||
Button["Reset", reset[]]},
|
||||
Grid[Table[
|
||||
With[{i = i, j = j},
|
||||
EventHandler[
|
||||
Button[Dynamic[grid[[i, j, 2]]], Null, ImageSize -> {17, 17},
|
||||
Appearance ->
|
||||
Dynamic[If[grid[[i, j, 3]] == 0, "Pressed",
|
||||
"DialogBox"]]], {{"MouseClicked", 1} :>
|
||||
If[win == "", clear[i, j]; checkwin[]], {"MouseClicked",
|
||||
2} :> If[win == "",
|
||||
Switch[grid[[i, j, 2]], ".", grid[[i, j, 2]] = "?";
|
||||
minecount--, "?", grid[[i, j, 2]] = "."; minecount++];
|
||||
checkwin[]]}]], {i, 1, m}, {j, 1, n}], Spacings -> {0, 0}],
|
||||
Dynamic[win]}]
|
||||
254
Task/Minesweeper-game/PHP/minesweeper-game.php
Normal file
254
Task/Minesweeper-game/PHP/minesweeper-game.php
Normal file
|
|
@ -0,0 +1,254 @@
|
|||
<?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>
|
||||
<style>
|
||||
table {
|
||||
border-collapse: collapse;
|
||||
}
|
||||
|
||||
td, a {
|
||||
text-align: center;
|
||||
width: 1em;
|
||||
height: 1em;
|
||||
}
|
||||
|
||||
a {
|
||||
display: block;
|
||||
color: black;
|
||||
text-decoration: none;
|
||||
font-size: 2em;
|
||||
}
|
||||
</style>
|
||||
<script>
|
||||
function flag(number, e) {
|
||||
if (e.which === 2 || e.which === 3) {
|
||||
location = '?flag=' + number;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
</script>
|
||||
<?php
|
||||
echo "<p>This field contains $_SESSION[numberofmines] mines.";
|
||||
?>
|
||||
<table border="1">
|
||||
<?php
|
||||
// array_shift() affects array, so we need a copy
|
||||
$mine_copy = $_SESSION['minesweeper'];
|
||||
|
||||
for ($x = 1; $x <= MINEGRID_HEIGHT; $x++) {
|
||||
echo '<tr>';
|
||||
for ($y = 1; $y <= MINEGRID_WIDTH; $y++) {
|
||||
echo '<td>';
|
||||
|
||||
$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 '<a>*</a>';
|
||||
}
|
||||
else {
|
||||
echo '<a>.</a>';
|
||||
}
|
||||
}
|
||||
else {
|
||||
echo '<a href=# onmousedown="return flag(',
|
||||
($x - 1) * MINEGRID_WIDTH + $y,
|
||||
',event)" oncontextmenu="return false">?</a>';
|
||||
}
|
||||
break;
|
||||
case ACTIVATED_MINE:
|
||||
echo '<a>:(</a>';
|
||||
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 '<a>*</a>';
|
||||
}
|
||||
else {
|
||||
echo '<a>.</a>';
|
||||
}
|
||||
}
|
||||
elseif (!empty($won)) {
|
||||
echo '<a>*</a>';
|
||||
}
|
||||
else {
|
||||
echo '<a href="?explore=',
|
||||
($x - 1) * MINEGRID_WIDTH + $y,
|
||||
'" onmousedown="return flag(',
|
||||
($x - 1) * MINEGRID_WIDTH + $y,
|
||||
',event)" oncontextmenu="return false">.</a>';
|
||||
}
|
||||
break;
|
||||
case 0:
|
||||
echo '<a></a>';
|
||||
break;
|
||||
default:
|
||||
echo '<a>', $number, '</a>';
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
?>
|
||||
</table>
|
||||
<?php
|
||||
if (!empty($lost)) {
|
||||
unset($_SESSION['minesweeper']);
|
||||
echo '<p>You lost :(. <a href="?">Reboot?</a>';
|
||||
}
|
||||
elseif (!empty($won)) {
|
||||
unset($_SESSION['minesweeper']);
|
||||
echo '<p>Congratulations. You won :).';
|
||||
}
|
||||
56
Task/Minesweeper-game/PicoLisp/minesweeper-game.l
Normal file
56
Task/Minesweeper-game/PicoLisp/minesweeper-game.l
Normal file
|
|
@ -0,0 +1,56 @@
|
|||
# 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!!" ) )
|
||||
136
Task/Minesweeper-game/Python/minesweeper-game.py
Normal file
136
Task/Minesweeper-game/Python/minesweeper-game.py
Normal file
|
|
@ -0,0 +1,136 @@
|
|||
'''
|
||||
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)) )
|
||||
176
Task/Minesweeper-game/Ruby/minesweeper-game.rb
Normal file
176
Task/Minesweeper-game/Ruby/minesweeper-game.rb
Normal file
|
|
@ -0,0 +1,176 @@
|
|||
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
|
||||
loop do
|
||||
x, y = rand(WIDTH), rand(HEIGHT)
|
||||
|
||||
# place it if it isn't at (sx, sy) and we haven't already placed a mine
|
||||
arr[x][y] = true and break if !arr[x][y] and (x != sx or y != sy)
|
||||
end
|
||||
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 }.join("\n")
|
||||
else
|
||||
puts "Grid has #{NUM_MINES} mines, #{num_marks} marked."
|
||||
puts $screen.transpose.map(&:join).join("\n")
|
||||
end
|
||||
end
|
||||
|
||||
def surrounding x, y
|
||||
# apply the passed block to each spot around (x, y)
|
||||
(-1..1).each do |dx|
|
||||
(-1..1).each do |dy|
|
||||
# don't check if we're out of bounds, or at (0,0)
|
||||
next if !(0...WIDTH).include?(x + dx) or !(0...HEIGHT).include?(y + dy)
|
||||
next if dx == 0 and dy == 0
|
||||
|
||||
yield(dx, dy)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def clear_space x, y
|
||||
return unless $screen[x][y] == "."
|
||||
|
||||
# check nearby spaces
|
||||
count = 0
|
||||
|
||||
surrounding(x, y) do |dx, dy|
|
||||
count += 1 if $mines[x + dx][y + dy]
|
||||
end
|
||||
|
||||
if count == 0
|
||||
$screen[x][y] = " "
|
||||
surrounding(x, y) do |dx, dy|
|
||||
clear_space x + dx, y + dy
|
||||
end
|
||||
else
|
||||
$screen[x][y] = count.to_s
|
||||
end
|
||||
end
|
||||
|
||||
def victory?
|
||||
return false if $mines == nil # first one, don't need to check
|
||||
|
||||
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
|
||||
|
||||
$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 = $1.to_i - 1, $2.to_i - 1
|
||||
|
||||
if $screen[x][y] == "."
|
||||
# mark it
|
||||
$screen[x][y] = "?"
|
||||
if victory?
|
||||
puts "You win!"
|
||||
break
|
||||
end
|
||||
elsif $screen[x][y] == "?"
|
||||
# unmark it
|
||||
$screen[x][y] = "."
|
||||
end
|
||||
show_grid
|
||||
when /^c (\d) (\d)$/
|
||||
x, y = $1.to_i - 1, $2.to_i - 1
|
||||
$mines ||= create_mines(x, y)
|
||||
if $mines[x][y]
|
||||
puts "You hit a mine!"
|
||||
$screen[x][y] = "*"
|
||||
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
|
||||
150
Task/Minesweeper-game/Tcl/minesweeper-game.tcl
Normal file
150
Task/Minesweeper-game/Tcl/minesweeper-game.tcl
Normal file
|
|
@ -0,0 +1,150 @@
|
|||
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
|
||||
Loading…
Add table
Add a link
Reference in a new issue