Data commit
This commit is contained in:
parent
7387c8f97b
commit
cb5bb5e222
199093 changed files with 3378972 additions and 0 deletions
3
Task/Minesweeper-game/00-META.yaml
Normal file
3
Task/Minesweeper-game/00-META.yaml
Normal file
|
|
@ -0,0 +1,3 @@
|
|||
---
|
||||
from: http://rosettacode.org/wiki/Minesweeper_game
|
||||
note: games
|
||||
23
Task/Minesweeper-game/00-TASK.txt
Normal file
23
Task/Minesweeper-game/00-TASK.txt
Normal file
|
|
@ -0,0 +1,23 @@
|
|||
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 neighborhood, 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)]]
|
||||
|
||||
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;
|
||||
556
Task/Minesweeper-game/AutoHotkey/minesweeper-game.ahk
Normal file
556
Task/Minesweeper-game/AutoHotkey/minesweeper-game.ahk
Normal file
|
|
@ -0,0 +1,556 @@
|
|||
; Minesweeper.ahk - v1.0.6
|
||||
; (c) Dec 28, 2008 by derRaphael
|
||||
; Licensed under the Terms of EUPL 1.0
|
||||
; Modded by Sobriquet and re-licenced as CeCILL v2
|
||||
; Modded (again) by Sobriquet and re-licenced as GPL v1.3
|
||||
|
||||
#NoEnv
|
||||
#NoTrayIcon
|
||||
SetBatchLines,-1
|
||||
#SingleInstance,Off
|
||||
/*
|
||||
[InGameSettings]
|
||||
*/
|
||||
Level =Beginner
|
||||
Width =9
|
||||
Height =9
|
||||
MineMax =10
|
||||
Marks =1
|
||||
Color =1
|
||||
Sound =0
|
||||
BestTimeBeginner =999 seconds Anonymous
|
||||
BestTimeIntermediate=999 seconds Anonymous
|
||||
BestTimeExpert =999 seconds Anonymous
|
||||
; above settings are accessed as variables AND modified by IniWrite - be careful
|
||||
BlockSize =16
|
||||
Title =Minesweeper
|
||||
MineCount =0
|
||||
mColor =Blue,Green,Red,Purple,Navy,Olive,Maroon,Teal
|
||||
GameOver =0
|
||||
TimePassed =0
|
||||
|
||||
; Add mines randomly
|
||||
While (MineCount<MineMax) ; loop as long as neccessary
|
||||
{
|
||||
Random,x,1,%Width% ; get random horizontal position
|
||||
Random,y,1,%Height% ; get random vertical position
|
||||
If (T_x%x%y%y%!="M") ; only if not already a mine
|
||||
T_x%x%y%y%:="M" ; assign as mine
|
||||
,MineCount++ ; keep count
|
||||
}
|
||||
|
||||
Gui +OwnDialogs
|
||||
;Menu,Tray,Icon,C:\WINDOWS\system32\winmine.exe,1
|
||||
Menu,GameMenu,Add,&New F2,NewGame
|
||||
Menu,GameMenu,Add
|
||||
Menu,GameMenu,Add,&Beginner,LevelMenu
|
||||
Menu,GameMenu,Add,&Intermediate,LevelMenu
|
||||
Menu,GameMenu,Add,&Expert,LevelMenu
|
||||
Menu,GameMenu,Add,&Custom...,CustomMenu
|
||||
Menu,GameMenu,Add
|
||||
Menu,GameMenu,Add,&Marks (?),ToggleMenu
|
||||
Menu,GameMenu,Add,Co&lor,ToggleMenu
|
||||
Menu,GameMenu,Add,&Sound,ToggleMenu
|
||||
Menu,GameMenu,Add
|
||||
Menu,GameMenu,Add,Best &Times...,BestTimesMenu
|
||||
Menu,GameMenu,Add
|
||||
Menu,GameMenu,Add,E&xit,GuiClose
|
||||
Menu,GameMenu,Check,% "&" level . (level="Custom" ? "..." : "")
|
||||
If (Marks)
|
||||
Menu,GameMenu,Check,&Marks (?)
|
||||
If (Color)
|
||||
Menu,GameMenu,Check,Co&lor
|
||||
If (Sound)
|
||||
Menu,GameMenu,Check,&Sound
|
||||
|
||||
Menu,HelpMenu,Add,&Contents F1,HelpMenu
|
||||
Menu,HelpMenu,Add,&Search for Help on...,HelpMenu
|
||||
Menu,HelpMenu,Add,Using &Help,HelpMenu
|
||||
Menu,HelpMenu,Add
|
||||
Menu,HelpMenu,Add,&About Minesweeper...,AboutMenu
|
||||
|
||||
Menu,MainMenu,Add,&Game,:GameMenu
|
||||
Menu,MainMenu,Add,&Help,:HelpMenu
|
||||
Gui,Menu,MainMenu
|
||||
|
||||
Gui,Font,s22,WingDings
|
||||
Gui,Add,Button,% "h31 w31 y13 gNewGame vNewGame x" Width*BlockSize/2-4,K ; J=Smiley / K=Line / L=Frowny / m=Circle
|
||||
Gui,Font,s16 Bold,Arial
|
||||
Gui,Add,Text,% "x13 y14 w45 Border Center vMineCount c" (color ? "Red" : "White"),% SubStr("00" MineCount,-2) ; Remaining mine count
|
||||
Gui,Add,Text,% "x" Width*BlockSize-34 " y14 w45 Border Center vTimer c" (color ? "Red" : "White"),000 ; Timer
|
||||
|
||||
; Buttons
|
||||
Gui,Font,s11,WingDings
|
||||
Loop,% Height ; iterate vertically
|
||||
{
|
||||
y:=A_Index ; remember line
|
||||
Loop,% Width ; set covers
|
||||
{
|
||||
x:=A_Index
|
||||
Gui,Add,Button,% "vB_x" x "y" y " w" BlockSize ; mark variable / width
|
||||
. " h" BlockSize " " (x = 1 ; height / if 1st block
|
||||
? "x" 12 " y" y*BlockSize+39 ; fix vertical offset
|
||||
: "yp x+0") ; otherwise stay inline /w prev. box
|
||||
}
|
||||
}
|
||||
|
||||
; Show Gui
|
||||
Gui,Show,% "w" ((Width>9 ? Width : 9))*BlockSize+24 " h" Height*BlockSize+68,%Title%
|
||||
OnMessage(0x53,"WM_HELP") ; invoke Help handling for tooltips
|
||||
Return ;--------------------------------------------------------; End of auto-execute section
|
||||
#IfWinActive Minesweeper ahk_class AutoHotkeyGUI ; variable %title% not supported
|
||||
|
||||
StartGame(x,y) {
|
||||
Global
|
||||
If (TimePassed)
|
||||
Return
|
||||
If (T_x%x%y%y%="M") ; we'll save you this time
|
||||
{
|
||||
T_x%x%y%y%:="" ; remove this mine
|
||||
Loop,% Height
|
||||
{
|
||||
y:=A_Index
|
||||
Loop,% Width
|
||||
{
|
||||
x:=A_Index
|
||||
If ( T_x%x%y%y%!="M") ; add it to first available non-mine square
|
||||
T_x%x%y%y%:="M"
|
||||
,break:=1
|
||||
IfEqual,break,1,Break
|
||||
}
|
||||
IfEqual,break,1,Break
|
||||
}
|
||||
}
|
||||
Loop,% Height ; iterate over height
|
||||
{
|
||||
y:=A_Index
|
||||
Loop,% Width ; iterate over width
|
||||
{
|
||||
x:=A_Index
|
||||
Gui,Font
|
||||
If (T_x%x%y%y%="M") { ; check for mine
|
||||
Gui,Font,s11,WingDings
|
||||
hColor:="Black" ; set color for text
|
||||
} Else {
|
||||
Loop,3 { ; loop over neighbors: three columns vertically
|
||||
ty:=y-2+A_Index ; calculate top offset
|
||||
Loop,3 { ; and three horizontally
|
||||
tx:=x-2+A_Index ; calculate left offset
|
||||
If (T_x%tx%y%ty%="M") ; no mine and inbound
|
||||
T_x%x%y%y%++ ; update hint txt
|
||||
}
|
||||
}
|
||||
Gui,Font,s11 Bold,Courier New Bold
|
||||
If (Color)
|
||||
Loop,Parse,mColor,`, ; find color
|
||||
If (T_x%x%y%y% = A_Index) { ; hinttxt to color
|
||||
hColor:=A_LoopField ; set color for text
|
||||
Break
|
||||
}
|
||||
Else hColor:="Black"
|
||||
}
|
||||
Gui,Add,Text,% "c" hColor " Border +Center vT_x" x "y" y ; set color / variable
|
||||
. " w" BlockSize " h" BlockSize " " (x = 1 ; width / height / if 1st block
|
||||
? "x" 12 " y" y*BlockSize+39 ; fix vertical position
|
||||
: "yp x+0") ; otherwise align to previous box
|
||||
,% T_x%x%y%y% ; M is WingDings for mine
|
||||
GuiControl,Hide,T_x%x%y%y%
|
||||
}
|
||||
}
|
||||
GuiControl,,Timer,% "00" . TimePassed:=1
|
||||
SetTimer,UpdateTimer,1000 ; start timer
|
||||
If (Sound)
|
||||
SoundPlay,C:\WINDOWS\media\chord.wav
|
||||
}
|
||||
|
||||
GuiSize:
|
||||
If (TimePassed)
|
||||
SetTimer,UpdateTimer,On ; for cheat below
|
||||
Return
|
||||
|
||||
UpdateTimer: ; timer
|
||||
GuiControl,,Timer,% (++TimePassed < 999) ? SubStr("00" TimePassed,-2) : 999
|
||||
If (Sound)
|
||||
SoundPlay,C:\WINDOWS\media\chord.wav
|
||||
Return
|
||||
|
||||
Check(x,y){
|
||||
Global
|
||||
If (GameOver || B_x%x%y%y% != "" ; the game is over / prevent click on flagged squares and already-opened squares
|
||||
|| x<1 || x>Width || y<1 || y>Height) ; do not check neighbor on illegal squares
|
||||
Return
|
||||
If (T_x%x%y%y%="") { ; empty field?
|
||||
CheckNeighbor(x,y) ; uncover it and any neighbours
|
||||
} Else If (T_x%x%y%y% != "M") { ; no Mine, ok?
|
||||
GuiControl,Hide,B_x%x%y%y% ; hide covering button
|
||||
GuiControl,Show,T_x%x%y%y%
|
||||
B_x%x%y%y%:=1 ; remember we been here
|
||||
UpdateChecks()
|
||||
} Else { ; ewww ... it's a mine!
|
||||
SetTimer,UpdateTimer,Off ; kill timer
|
||||
GuiControl,,T_x%x%y%y%,N ; set to Jolly Roger=N to mark death location
|
||||
GuiControl,,NewGame,L ; set Smiley Btn to Frown=L
|
||||
RevealAll()
|
||||
If (Sound) ; do we sound?
|
||||
If (FileExist("C:\Program Files\Microsoft Office\Office12\MEDIA\Explode.wav"))
|
||||
SoundPlay,C:\Program Files\Microsoft Office\Office12\MEDIA\Explode.wav
|
||||
Else
|
||||
SoundPlay,C:\WINDOWS\Media\notify.wav
|
||||
}
|
||||
}
|
||||
|
||||
CheckNeighbor(x,y) { ; This function checks neighbours of the clicked
|
||||
Global ; field and uncovers empty fields plus adjacent hint fields
|
||||
If (GameOver || B_x%x%y%y%!="")
|
||||
Return
|
||||
GuiControl,Hide,B_x%x%y%y% ; uncover it
|
||||
GuiControl,Show,T_x%x%y%y%
|
||||
B_x%x%y%y%:=1 ; remember it
|
||||
UpdateChecks()
|
||||
If (T_x%x%y%y%!="") ; is neighbour an nonchecked 0 value field?
|
||||
Return
|
||||
If (y-1>=1) ; check upper neighbour
|
||||
CheckNeighbor(x,y-1)
|
||||
If (y+1<=Height) ; check lower neighbour
|
||||
CheckNeighbor(x,y+1)
|
||||
If (x-1>=1) ; check left neighbour
|
||||
CheckNeighbor(x-1,y)
|
||||
If (x+1<=Width) ; check right neighbour
|
||||
CheckNeighbor(x+1,y)
|
||||
If (x-1>=1 && y-1>=1) ; check corner neighbour
|
||||
CheckNeighbor(x-1,y-1)
|
||||
If (x-1>=1 && y+1<=Height) ; check corner neighbour
|
||||
CheckNeighbor(x-1,y+1)
|
||||
If (x+1<=Width && y-1>=1) ; check corner neighbour
|
||||
CheckNeighbor(x+1,y-1)
|
||||
If (x+1<=Width && y+1<=Height) ; check corner neighbour
|
||||
CheckNeighbor(x+1,y+1)
|
||||
}
|
||||
|
||||
UpdateChecks() {
|
||||
Global
|
||||
MineCount:=MineMax, Die1:=Die2:=0
|
||||
Loop,% Height
|
||||
{
|
||||
y:=A_Index
|
||||
Loop,% Width
|
||||
{
|
||||
x:=A_Index
|
||||
If (B_x%x%y%y%="O")
|
||||
MineCount--
|
||||
If (T_x%x%y%y%="M" && B_x%x%y%y%!="O") || (T_x%x%y%y%!="M" && B_x%x%y%y%="O")
|
||||
Die1++
|
||||
If (B_x%x%y%y%="" && T_x%x%y%y%!="M")
|
||||
Die2++
|
||||
}
|
||||
}
|
||||
GuiControl,,MineCount,% SubStr("00" MineCount,-2)
|
||||
If (Die1 && Die2)
|
||||
Return ; only get past here if flags+untouched squares match mines perfectly
|
||||
SetTimer,UpdateTimer,Off ; game won - kill timer
|
||||
GuiControl,,NewGame,J ; set Smiley Btn to Smile=J
|
||||
RevealAll()
|
||||
If (Sound) ; play sound
|
||||
SoundPlay,C:\WINDOWS\Media\tada.wav
|
||||
If (level!="Custom" && TimePassed < SubStr(BestTime%level%,1,InStr(BestTime%level%," ")-1) )
|
||||
{
|
||||
InputBox,name,Congratulations!,You have the fastest time`nfor level %level%.`nPlease enter your name.`n,,,,,,,,%A_UserName%
|
||||
If (name && !ErrorLevel)
|
||||
{
|
||||
BestTime%level%:=%TimePassed% seconds %name%
|
||||
IniWrite,BestTime%level%,%A_ScriptFullPath%,InGameSettings,BestTime%level%
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
RevealAll(){
|
||||
Global
|
||||
Loop,% Height ; uncover all
|
||||
{
|
||||
y:=A_Index
|
||||
Loop,% Width
|
||||
{
|
||||
x:=A_Index
|
||||
If(T_x%x%y%y%="M")
|
||||
{
|
||||
GuiControl,Hide,B_x%x%y%y%
|
||||
GuiControl,Show,T_x%x%y%y%
|
||||
}
|
||||
}
|
||||
}
|
||||
GameOver:=True ; remember the game's over to block clicks
|
||||
}
|
||||
|
||||
~F2::NewGame()
|
||||
NewGame(){
|
||||
NewGame:
|
||||
Reload
|
||||
ExitApp
|
||||
}
|
||||
|
||||
LevelMenu:
|
||||
If (A_ThisMenuItem="&Beginner")
|
||||
level:="Beginner", Width:=9, Height:=9, MineMax:=10
|
||||
Else If (A_ThisMenuItem="&Intermediate")
|
||||
level:="Intermediate", Width:=16, Height:=16, MineMax:=40
|
||||
Else If (A_ThisMenuItem="&Expert")
|
||||
level:="Expert", Width:=30, Height:=16, MineMax:=99
|
||||
IniWrite,%level%,%A_ScriptFullPath%,InGameSettings,level
|
||||
IniWrite,%Width%,%A_ScriptFullPath%,InGameSettings,Width
|
||||
IniWrite,%Height%,%A_ScriptFullPath%,InGameSettings,Height
|
||||
IniWrite,%MineMax%,%A_ScriptFullPath%,InGameSettings,MineMax
|
||||
IniWrite,%Marks%,%A_ScriptFullPath%,InGameSettings,Marks
|
||||
IniWrite,%Sound%,%A_ScriptFullPath%,InGameSettings,Sound
|
||||
IniWrite,%Color%,%A_ScriptFullPath%,InGameSettings,Color
|
||||
NewGame()
|
||||
Return
|
||||
|
||||
CustomMenu: ; label for setting window
|
||||
Gui,2:+Owner1 ; make Gui#2 owned by gameWindow
|
||||
Gui,2:Default ; set to default
|
||||
Gui,1:+Disabled ; disable gameWindow
|
||||
Gui,-MinimizeBox +E0x00000400
|
||||
Gui,Add,Text,x15 y36 w38 h16,&Height:
|
||||
Gui,Add,Edit,Number x60 y33 w38 h20 vHeight HwndHwndHeight,%Height% ; use inGame settings
|
||||
Gui,Add,Text,x15 y60 w38 h16,&Width:
|
||||
Gui,Add,Edit,Number x60 y57 w38 h20 vWidth HwndHwndWidth,%Width%
|
||||
Gui,Add,Text,x15 y85 w38 h16,&Mines:
|
||||
Gui,Add,Edit,Number x60 y81 w38 h20 vMineMax HwndHwndMines,%MineMax%
|
||||
Gui,Add,Button,x120 y33 w60 h26 Default HwndHwndOK,OK
|
||||
Gui,Add,Button,x120 y75 w60 h26 g2GuiClose HwndHwndCancel,Cancel ; jump directly to 2GuiClose label
|
||||
Gui,Show,w195 h138,Custom Field
|
||||
Return
|
||||
|
||||
2ButtonOK: ; label for OK button in settings window
|
||||
Gui,2:Submit,NoHide
|
||||
level:="Custom"
|
||||
MineMax:=MineMax<10 ? 10 : MineMax>((Width-1)*(Height-1)) ? ((Width-1)*(Height-1)) : MineMax
|
||||
Width:=Width<9 ? 9 : Width>30 ? 30 : Width
|
||||
Height:=Height<9 ? 9 : Height>24 ? 24 : Height
|
||||
GoSub,LevelMenu
|
||||
Return
|
||||
|
||||
2GuiClose:
|
||||
2GuiEscape:
|
||||
Gui,1:-Disabled ; reset GUI status and destroy setting window
|
||||
Gui,1:Default
|
||||
Gui,2:Destroy
|
||||
Return
|
||||
|
||||
ToggleMenu:
|
||||
Toggle:=RegExReplace(RegExReplace(A_ThisMenuItem,"\s.*"),"&")
|
||||
temp:=%Toggle%
|
||||
%Toggle%:=!%Toggle%
|
||||
Menu,GameMenu,ToggleCheck,%A_ThisMenuItem%
|
||||
IniWrite,% %Toggle%,%A_ScriptFullPath%,InGameSettings,%Toggle%
|
||||
Return
|
||||
|
||||
BestTimesMenu:
|
||||
Gui,3:+Owner1
|
||||
Gui,3:Default
|
||||
Gui,1:+Disabled
|
||||
Gui,-MinimizeBox +E0x00000400
|
||||
Gui,Add,Text,x15 y22 w250 vBestTimeBeginner HwndHwndBTB,Beginner: %BestTimeBeginner%
|
||||
Gui,Add,Text,x15 y38 w250 vBestTimeIntermediate HwndHwndBTI,Intermediate: %BestTimeIntermediate%
|
||||
Gui,Add,Text,x15 y54 w250 vBestTimeExpert HwndHwndBTE,Expert: %BestTimeExpert%
|
||||
Gui,Add,Button,x38 y89 w75 h20 HwndHwndRS,&Reset Scores
|
||||
Gui,Add,Button,x173 y89 w45 h20 Default HwndHwndOK,OK
|
||||
Gui,Show,w255 h122,Fastest Mine Sweepers
|
||||
Return
|
||||
|
||||
3ButtonResetScores:
|
||||
BestTimeBeginner =999 seconds Anonymous
|
||||
BestTimeIntermediate=999 seconds Anonymous
|
||||
BestTimeExpert =999 seconds Anonymous
|
||||
GuiControl,,BestTimeBeginner,Beginner: %BestTimeBeginner%`nIntermediate: %BestTimeIntermediate%`nExpert: %BestTimeExpert%
|
||||
GuiControl,,BestTimeIntermediate,Intermediate: %BestTimeIntermediate%`nExpert: %BestTimeExpert%
|
||||
GuiControl,,BestTimeExpert,Expert: %BestTimeExpert%
|
||||
IniWrite,%BestTimeBeginner%,%A_ScriptFullPath%,InGameSettings,BestTimeBeginner
|
||||
IniWrite,%BestTimeIntermediate%,%A_ScriptFullPath%,InGameSettings,BestTimeIntermediate
|
||||
IniWrite,%BestTimeExpert%,%A_ScriptFullPath%,InGameSettings,BestTimeExpert
|
||||
3GuiEscape: ; fall through:
|
||||
3GuiClose:
|
||||
3ButtonOK:
|
||||
Gui,1:-Disabled ; reset GUI status and destroy setting window
|
||||
Gui,1:Default
|
||||
Gui,3:Destroy
|
||||
Return
|
||||
|
||||
^q::
|
||||
GuiClose:
|
||||
ExitApp
|
||||
|
||||
HelpMenu:
|
||||
;Run C:\WINDOWS\Help\winmine.chm
|
||||
Return
|
||||
|
||||
AboutMenu:
|
||||
Msgbox,64,About Minesweeper,AutoHotkey (r) Minesweeper`nVersion 1.0.6`nCopyright (c) 2014`nby derRaphael and Sobriquet
|
||||
Return
|
||||
|
||||
~LButton::
|
||||
~!LButton::
|
||||
~^LButton::
|
||||
~#LButton::
|
||||
Tooltip
|
||||
If (GetKeyState("RButton","P"))
|
||||
Return
|
||||
If A_OSVersion not in WIN_2003,WIN_XP,WIN_2000,WIN_NT4,WIN_95,WIN_98,WIN_ME
|
||||
If(A_PriorHotkey="~*LButton Up" && A_TimeSincePriorHotkey<100)
|
||||
GoTo,*MButton Up ; invoke MButton handling for autofill on left double-click in vista+
|
||||
If (GameOver)
|
||||
Return
|
||||
MouseGetPos,,y
|
||||
If (y>47)
|
||||
GuiControl,,NewGame,m
|
||||
Return
|
||||
|
||||
~*LButton Up::
|
||||
If (GetKeyState("RButton","P"))
|
||||
GoTo,*MButton Up
|
||||
If (GameOver)
|
||||
Return
|
||||
GuiControl,,NewGame,K
|
||||
control:=GetControlFromClassNN(), NumX:=NumY:=0
|
||||
RegExMatch(control,"Si)T_x(?P<X>\d+)y(?P<Y>\d+)",Num) ; get Position
|
||||
StartGame(NumX,NumY) ; start game if neccessary
|
||||
Check(NumX,NumY)
|
||||
Return
|
||||
|
||||
+LButton::
|
||||
*MButton::
|
||||
Tooltip
|
||||
If (GameOver)
|
||||
Return
|
||||
MouseGetPos,,y
|
||||
If (y>47)
|
||||
GuiControl,,NewGame,m
|
||||
Return
|
||||
|
||||
+LButton Up::
|
||||
*MButton Up::
|
||||
If (GameOver)
|
||||
Return
|
||||
GuiControl,,NewGame,K
|
||||
StartGame(NumX,NumY) ; start game if neccessary
|
||||
If (GetKeyState("Esc","P"))
|
||||
{
|
||||
SetTimer,UpdateTimer,Off
|
||||
Return
|
||||
}
|
||||
control:=GetControlFromClassNN(), NumX:=NumY:=0
|
||||
RegExMatch(control,"Si)T_x(?P<X>\d+)y(?P<y>\d+)",Num)
|
||||
If ( !NumX || !NumY || B_x%NumX%y%NumY%!=1)
|
||||
Return
|
||||
temp:=0
|
||||
Loop,3 { ; loop over neighbors: three columns vertically
|
||||
ty:=NumY-2+A_Index ; calculate top offset
|
||||
Loop,3 { ; and three horizontally
|
||||
tx:=NumX-2+A_Index ; calculate left offset
|
||||
If (B_x%tx%y%ty% = "O") ; count number of marked mines around position
|
||||
temp++
|
||||
}
|
||||
}
|
||||
If (temp=T_x%NumX%y%NumY%)
|
||||
Loop,3 { ; loop over neighbors: three columns vertically
|
||||
ty:=NumY-2+A_Index ; calculate top offset
|
||||
Loop,3 { ; and three horizontally
|
||||
tx:=NumX-2+A_Index ; calculate left offset
|
||||
Check(tx,ty) ; simulate user clicking on each surrounding square
|
||||
}
|
||||
}
|
||||
Return
|
||||
|
||||
~*RButton::
|
||||
If (GameOver || GetKeyState("LButton","P"))
|
||||
Return
|
||||
control:=GetControlFromClassNN(), NumX:=NumY:=0
|
||||
RegExMatch(control,"Si)T_x(?P<X>\d+)y(?P<y>\d+)",Num) ; grab 'em
|
||||
If ( !NumX || !NumY || B_x%NumX%y%NumY%=1)
|
||||
Return
|
||||
StartGame(NumX,NumY) ; start counter if neccessary
|
||||
B_x%NumX%y%NumY%:=(B_x%NumX%y%NumY%="" ? "O" : (B_x%NumX%y%NumY%="O" && Marks=1 ? "I" : ""))
|
||||
GuiControl,,B_x%NumX%y%NumY%,% B_x%NumX%y%NumY%
|
||||
UpdateChecks()
|
||||
Return
|
||||
|
||||
~*RButton Up::
|
||||
If (GetKeyState("LButton","P"))
|
||||
GoTo,*MButton Up
|
||||
Return
|
||||
|
||||
GetControlFromClassNN(){
|
||||
Global width
|
||||
MouseGetPos,,,,control
|
||||
If (SubStr(control,1,6)="Button")
|
||||
NumX:=mod(SubStr(control,7)-2,width)+1,NumY:=(SubStr(control,7)-2)//width+1
|
||||
Else If (SubStr(control,1,6)="Static")
|
||||
NumX:=mod(SubStr(control,7)-3,width)+1,NumY:=(SubStr(control,7)-3)//width+1
|
||||
Return "T_x" NumX "y" NumY
|
||||
}
|
||||
|
||||
WM_HELP(_,_lphi)
|
||||
{
|
||||
Global
|
||||
hItemHandle:=NumGet(_lphi+0,12)
|
||||
If (hItemHandle=HwndBTB || hItemHandle=HwndBTI || hItemHandle=HwndBTE)
|
||||
ToolTip Displays a player's best game time`, and the player's name`, for`neach level of play: Beginner`, Intermediate`, and Expert.
|
||||
Else If (hItemHandle=HwndRS)
|
||||
ToolTip Click to clear the current high scores.
|
||||
Else If (hItemHandle=HwndOK)
|
||||
ToolTip Closes the dialog box and saves any changes you`nhave made.
|
||||
Else If (hItemHandle=HwndCancel)
|
||||
ToolTip Closes the dialog box without saving any changes you have`nmade.
|
||||
Else If (hItemHandle=HwndHeight)
|
||||
ToolTip Specifies the number of vertical squares on the`nplaying field.
|
||||
Else If (hItemHandle=HwndWidth)
|
||||
ToolTip Specifies the number of horizontal squares on the`nplaying field.
|
||||
Else If (hItemHandle=HwndMines)
|
||||
ToolTip Specifies the number of mines to be placed on the`nplaying field.
|
||||
}
|
||||
|
||||
:*?B0:xyzzy:: ; cheat
|
||||
KeyWait,Shift,D T1 ; 1 sec grace period to press shift
|
||||
If (ErrorLevel)
|
||||
Return
|
||||
While,GetKeyState("Shift","P")
|
||||
{
|
||||
control:=GetControlFromClassNN()
|
||||
If (%control% = "M")
|
||||
SplashImage,,B X0 Y0 W1 H1 CW000000 ; black pixel
|
||||
Else
|
||||
SplashImage,,B X0 Y0 W1 H1 CWFFFFFF ; white pixel
|
||||
Sleep 100
|
||||
}
|
||||
SplashImage,Off
|
||||
Return
|
||||
|
||||
/*
|
||||
Version History
|
||||
=================
|
||||
Dec 29, 2008
|
||||
1.0.0 Initial Release
|
||||
1.0.1 BugFix
|
||||
- Game Restart Issues mentioned by Frankie
|
||||
- Guess count fixup I
|
||||
- Startbehaviour of game (time didnt start when 1st click was RMB Guess)
|
||||
Dec 30, 2008
|
||||
1.0.2 BugFix
|
||||
- Field Size Control vs Max MineCount / mentioned by °digit° / IsNull
|
||||
1.0.3 BugFix
|
||||
- Guess count fixup II mentioned by °digit°
|
||||
- Corrected count when 'guessed' field uncovered
|
||||
Dec 31, 2008
|
||||
1.0.4 BugFix
|
||||
- Fix of Min Field & MineSettings
|
||||
Mar 7, 2014
|
||||
1.0.5 AddFeatures
|
||||
- Make appearance more like original
|
||||
- Make first click always safe
|
||||
- Re-license as CeCILL v2
|
||||
Mar 8, 2014
|
||||
1.0.6 AddFeatures
|
||||
- Add cheat code
|
||||
- Add middle-button shortcut
|
||||
- Re-license as GPL 1.3
|
||||
*/
|
||||
110
Task/Minesweeper-game/BASIC256/minesweeper-game.basic
Normal file
110
Task/Minesweeper-game/BASIC256/minesweeper-game.basic
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
|
||||
190
Task/Minesweeper-game/BCPL/minesweeper-game.bcpl
Normal file
190
Task/Minesweeper-game/BCPL/minesweeper-game.bcpl
Normal file
|
|
@ -0,0 +1,190 @@
|
|||
get "libhdr"
|
||||
|
||||
static $( randstate = 0 $)
|
||||
|
||||
manifest $(
|
||||
nummask = #XF
|
||||
flagmask = #X10
|
||||
bombmask = #X20
|
||||
revealed = #X40
|
||||
MAXINT = (~0)>>1
|
||||
MININT = ~MAXINT
|
||||
$)
|
||||
|
||||
let min(x,y) = x<y -> x, y
|
||||
and max(x,y) = x>y -> x, y
|
||||
|
||||
let rand() = valof
|
||||
$( randstate := random(randstate)
|
||||
resultis randstate >> 7
|
||||
$)
|
||||
|
||||
let randto(x) = valof
|
||||
$( let r, mask = ?, 1
|
||||
while mask<x do mask := (mask << 1) | 1
|
||||
r := rand() & mask repeatuntil r < x
|
||||
resultis r
|
||||
$)
|
||||
|
||||
// Place a bomb on the field (if not already a bomb)
|
||||
let placebomb(field, xsize, ysize, x, y) =
|
||||
(field!(y*xsize+x) & bombmask) ~= 0 -> false,
|
||||
valof
|
||||
$( for xa = max(x-1, 0) to min(x+1, xsize-1)
|
||||
for ya = max(y-1, 0) to min(y+1, ysize-1)
|
||||
$( let loc = ya*xsize+xa
|
||||
let n = field!loc & nummask
|
||||
field!loc := (field!loc & ~nummask) | (n + 1)
|
||||
$)
|
||||
field!(y*xsize+x) := field!(y*xsize+x) | bombmask
|
||||
resultis true
|
||||
$)
|
||||
|
||||
// Populate the field with N bombs
|
||||
let populate(field, xsize, ysize, nbombs) be
|
||||
$( for i=0 to xsize*ysize-1 do field!i := 0
|
||||
while nbombs > 0
|
||||
$( let x, y = randto(xsize), randto(ysize)
|
||||
if placebomb(field, xsize, ysize, x, y) then
|
||||
nbombs := nbombs - 1
|
||||
$)
|
||||
$)
|
||||
|
||||
// Reveal field (X,Y) - returns true if stepped on a bomb
|
||||
let reveal(field, xsize, ysize, x, y) =
|
||||
(field!(y*xsize+x) & bombmask) ~= 0 -> true,
|
||||
valof
|
||||
$( let loc = y*xsize+x
|
||||
field!loc := field!loc | revealed
|
||||
if (field!loc & nummask) = 0 then
|
||||
for xa = max(x-1, 0) to min(x+1, xsize-1)
|
||||
for ya = max(y-1, 0) to min(y+1, ysize-1)
|
||||
if (field!(ya*xsize+xa) &
|
||||
(bombmask | flagmask | revealed)) = 0 do
|
||||
reveal(field, xsize, ysize, xa, ya)
|
||||
resultis false
|
||||
$)
|
||||
|
||||
// Toggle flag
|
||||
let toggleflag(field, xsize, ysize, x, y) be
|
||||
$( let loc = y*xsize+x
|
||||
field!loc := field!loc neqv flagmask
|
||||
$)
|
||||
|
||||
// Show the field. Returns true if won.
|
||||
let showfield(field, xsize, ysize, kaboom) = valof
|
||||
$( let bombs, flags, hidden, found = 0, 0, 0, 0
|
||||
for i=0 to xsize*ysize-1
|
||||
$( if (field!i & revealed) = 0 do hidden := hidden + 1
|
||||
unless (field!i & bombmask) = 0 do bombs := bombs + 1
|
||||
unless (field!i & flagmask) = 0 do flags := flags + 1
|
||||
if (field!i & bombmask) ~= 0 & (field!i & flagmask) ~= 0
|
||||
do found := found + 1
|
||||
$)
|
||||
writef("Bombs: %N - Flagged: %N - Hidden: %N*N", bombs, flags, hidden)
|
||||
wrch('+')
|
||||
for x=0 to xsize-1 do wrch('-')
|
||||
writes("+*N")
|
||||
for y=0 to ysize-1
|
||||
$( wrch('|')
|
||||
for x=0 to xsize-1
|
||||
$( let loc = y*xsize+x
|
||||
test kaboom & (field!loc & bombmask) ~= 0 do
|
||||
wrch('**')
|
||||
or test (field!loc & (flagmask | revealed)) = flagmask do
|
||||
wrch('?')
|
||||
or test (field!loc & revealed) = 0 do
|
||||
wrch('.')
|
||||
or test (field!loc & nummask) = 0 do
|
||||
wrch(' ')
|
||||
or
|
||||
wrch('0' + (field!loc & nummask))
|
||||
$)
|
||||
writes("|*N")
|
||||
$)
|
||||
wrch('+')
|
||||
for x=0 to xsize-1 do wrch('-')
|
||||
writes("+*N")
|
||||
resultis found = bombs
|
||||
$)
|
||||
|
||||
// Ask a question, get number
|
||||
let ask(q, min, max) = valof
|
||||
$( let n = ?
|
||||
$( writes(q)
|
||||
n := readn()
|
||||
$) repeatuntil min <= n <= max
|
||||
resultis n
|
||||
$)
|
||||
|
||||
// Read string
|
||||
let reads(v) = valof
|
||||
$( let ch = ?
|
||||
v%0 := 0
|
||||
$( ch := rdch()
|
||||
if ch = endstreamch then resultis false
|
||||
v%0 := v%0 + 1
|
||||
v%(v%0) := ch
|
||||
$) repeatuntil ch = '*N'
|
||||
resultis true
|
||||
$)
|
||||
|
||||
// Play game given field
|
||||
let play(field, xsize, ysize) be
|
||||
$( let x = ?
|
||||
let y = ?
|
||||
let ans = vec 80
|
||||
if showfield(field, xsize, ysize, false)
|
||||
$( writes("*NYou win!*N")
|
||||
finish
|
||||
$)
|
||||
$( writes("*NR)eveal, F)lag, Q)uit? ")
|
||||
unless reads(ans) finish
|
||||
unless ans%0 = 2 & ans%2='*N' loop
|
||||
ans%1 := ans%1 | 32
|
||||
if ans%1 = 'q' then finish
|
||||
$) repeatuntil ans%1='r' | ans%1='f'
|
||||
|
||||
y := ask("Row? ", 1, ysize)-1
|
||||
x := ask("Column? ", 1, xsize)-1
|
||||
|
||||
switchon ans%1 into
|
||||
$( case 'r':
|
||||
unless (field!(y*xsize+x) & flagmask) = 0
|
||||
$( writes("*NError: that field is flagged, unflag it first.*N")
|
||||
endcase
|
||||
$)
|
||||
unless (field!(y*xsize+x) & revealed) = 0
|
||||
$( writes("*NError: that field is already revealed.*N")
|
||||
endcase
|
||||
$)
|
||||
if reveal(field, xsize, ysize, x, y)
|
||||
$( writes("*N K A B O O M *N*N")
|
||||
showfield(field, xsize, ysize, true)
|
||||
finish
|
||||
$)
|
||||
endcase
|
||||
case 'f':
|
||||
test (field!(y*xsize+x) & revealed) = 0
|
||||
do toggleflag(field, xsize, ysize, x, y)
|
||||
or writes("*NError: that field is already revealed.*N")
|
||||
endcase
|
||||
$)
|
||||
wrch('*N')
|
||||
$) repeat
|
||||
|
||||
let start() be
|
||||
$( let field, xsize, ysize, bombs = ?, ?, ?, ?
|
||||
|
||||
writes("Minesweeper*N-----------*N*N")
|
||||
randstate := ask("Random seed? ", MININT, MAXINT)
|
||||
xsize := ask("Width (4-64)? ", 4, 64)
|
||||
ysize := ask("Height (4-22)? ", 4, 22)
|
||||
|
||||
// 10 to 20% bombs
|
||||
bombs := muldiv(xsize,ysize,10) + randto(muldiv(xsize,ysize,10)+1)
|
||||
|
||||
field := getvec(xsize*ysize)
|
||||
populate(field, xsize, ysize, bombs)
|
||||
play(field, xsize, ysize)
|
||||
$)
|
||||
223
Task/Minesweeper-game/C++/minesweeper-game.cpp
Normal file
223
Task/Minesweeper-game/C++/minesweeper-game.cpp
Normal 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" );
|
||||
}
|
||||
266
Task/Minesweeper-game/C-sharp/minesweeper-game.cs
Normal file
266
Task/Minesweeper-game/C-sharp/minesweeper-game.cs
Normal file
|
|
@ -0,0 +1,266 @@
|
|||
using System;
|
||||
using System.Drawing;
|
||||
using System.Windows.Forms;
|
||||
|
||||
class MineFieldModel
|
||||
{
|
||||
public int RemainingMinesCount{
|
||||
get{
|
||||
var count = 0;
|
||||
ForEachCell((i,j)=>{
|
||||
if (Mines[i,j] && !Marked[i,j])
|
||||
count++;
|
||||
});
|
||||
return count;
|
||||
}
|
||||
}
|
||||
|
||||
public bool[,] Mines{get; private set;}
|
||||
public bool[,] Opened{get;private set;}
|
||||
public bool[,] Marked{get; private set;}
|
||||
public int[,] Values{get;private set; }
|
||||
public int Width{ get{return Mines.GetLength(1);} }
|
||||
public int Height{ get{return Mines.GetLength(0);} }
|
||||
|
||||
public MineFieldModel(bool[,] mines)
|
||||
{
|
||||
this.Mines = mines;
|
||||
this.Opened = new bool[Height, Width]; // filled with 'false' by default
|
||||
this.Marked = new bool[Height, Width];
|
||||
this.Values = CalculateValues();
|
||||
}
|
||||
|
||||
private int[,] CalculateValues()
|
||||
{
|
||||
int[,] values = new int[Height, Width];
|
||||
ForEachCell((i,j) =>{
|
||||
var value = 0;
|
||||
ForEachNeighbor(i,j, (i1,j1)=>{
|
||||
if (Mines[i1,j1])
|
||||
value++;
|
||||
});
|
||||
values[i,j] = value;
|
||||
});
|
||||
return values;
|
||||
}
|
||||
|
||||
// Helper method for iterating over cells
|
||||
public void ForEachCell(Action<int,int> action)
|
||||
{
|
||||
for (var i = 0; i < Height; i++)
|
||||
for (var j = 0; j < Width; j++)
|
||||
action(i,j);
|
||||
}
|
||||
|
||||
// Helper method for iterating over cells' neighbors
|
||||
public void ForEachNeighbor(int i, int j, Action<int,int> action)
|
||||
{
|
||||
for (var i1 = i-1; i1 <= i+1; i1++)
|
||||
for (var j1 = j-1; j1 <= j+1; j1++)
|
||||
if (InBounds(j1, i1) && !(i1==i && j1 ==j))
|
||||
action(i1, j1);
|
||||
}
|
||||
|
||||
private bool InBounds(int x, int y)
|
||||
{
|
||||
return y >= 0 && y < Height && x >=0 && x < Width;
|
||||
}
|
||||
|
||||
public event Action Exploded = delegate{};
|
||||
public event Action Win = delegate{};
|
||||
public event Action Updated = delegate{};
|
||||
|
||||
public void OpenCell(int i, int j){
|
||||
if(!Opened[i,j]){
|
||||
if (Mines[i,j])
|
||||
Exploded();
|
||||
else{
|
||||
OpenCellsStartingFrom(i,j);
|
||||
Updated();
|
||||
CheckForVictory();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void OpenCellsStartingFrom(int i, int j)
|
||||
{
|
||||
Opened[i,j] = true;
|
||||
ForEachNeighbor(i,j, (i1,j1)=>{
|
||||
if (!Mines[i1,j1] && !Opened[i1,j1] && !Marked[i1,j1])
|
||||
OpenCellsStartingFrom(i1, j1);
|
||||
});
|
||||
}
|
||||
|
||||
void CheckForVictory(){
|
||||
int notMarked = 0;
|
||||
int wrongMarked = 0;
|
||||
ForEachCell((i,j)=>{
|
||||
if (Mines[i,j] && !Marked[i,j])
|
||||
notMarked++;
|
||||
if (!Mines[i,j] && Marked[i,j])
|
||||
wrongMarked++;
|
||||
});
|
||||
if (notMarked == 0 && wrongMarked == 0)
|
||||
Win();
|
||||
}
|
||||
|
||||
public void Mark(int i, int j){
|
||||
if (!Opened[i,j])
|
||||
Marked[i,j] = true;
|
||||
Updated();
|
||||
CheckForVictory();
|
||||
}
|
||||
}
|
||||
|
||||
class MineFieldView: UserControl{
|
||||
public const int CellSize = 40;
|
||||
|
||||
MineFieldModel _model;
|
||||
public MineFieldModel Model{
|
||||
get{ return _model; }
|
||||
set
|
||||
{
|
||||
_model = value;
|
||||
this.Size = new Size(_model.Width * CellSize+1, _model.Height * CellSize+2);
|
||||
}
|
||||
}
|
||||
|
||||
public MineFieldView(){
|
||||
//Enable double-buffering to eliminate flicker
|
||||
this.SetStyle(ControlStyles.AllPaintingInWmPaint | ControlStyles.UserPaint | ControlStyles.DoubleBuffer,true);
|
||||
this.Font = new Font(FontFamily.GenericSansSerif, 14, FontStyle.Bold);
|
||||
|
||||
this.MouseUp += (o,e)=>{
|
||||
Point cellCoords = GetCell(e.Location);
|
||||
if (Model != null)
|
||||
{
|
||||
if (e.Button == MouseButtons.Left)
|
||||
Model.OpenCell(cellCoords.Y, cellCoords.X);
|
||||
else if (e.Button == MouseButtons.Right)
|
||||
Model.Mark(cellCoords.Y, cellCoords.X);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
Point GetCell(Point coords)
|
||||
{
|
||||
var rgn = ClientRectangle;
|
||||
var x = (coords.X - rgn.X)/CellSize;
|
||||
var y = (coords.Y - rgn.Y)/CellSize;
|
||||
return new Point(x,y);
|
||||
}
|
||||
|
||||
static readonly Brush MarkBrush = new SolidBrush(Color.Blue);
|
||||
static readonly Brush ValueBrush = new SolidBrush(Color.Black);
|
||||
static readonly Brush UnexploredBrush = new SolidBrush(SystemColors.Control);
|
||||
static readonly Brush OpenBrush = new SolidBrush(SystemColors.ControlDark);
|
||||
|
||||
|
||||
protected override void OnPaint(PaintEventArgs e)
|
||||
{
|
||||
base.OnPaint(e);
|
||||
var g = e.Graphics;
|
||||
if (Model != null)
|
||||
{
|
||||
Model.ForEachCell((i,j)=>
|
||||
{
|
||||
var bounds = new Rectangle(j * CellSize, i * CellSize, CellSize, CellSize);
|
||||
if (Model.Opened[i,j])
|
||||
{
|
||||
g.FillRectangle(OpenBrush, bounds);
|
||||
if (Model.Values[i,j] > 0)
|
||||
{
|
||||
DrawStringInCenter(g, Model.Values[i,j].ToString(), ValueBrush, bounds);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
g.FillRectangle(UnexploredBrush, bounds);
|
||||
if (Model.Marked[i,j])
|
||||
{
|
||||
DrawStringInCenter(g, "?", MarkBrush, bounds);
|
||||
}
|
||||
var outlineOffset = 1;
|
||||
var outline = new Rectangle(bounds.X+outlineOffset, bounds.Y+outlineOffset, bounds.Width-2*outlineOffset, bounds.Height-2*outlineOffset);
|
||||
g.DrawRectangle(Pens.Gray, outline);
|
||||
}
|
||||
g.DrawRectangle(Pens.Black, bounds);
|
||||
});
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
static readonly StringFormat FormatCenter = new StringFormat
|
||||
{
|
||||
LineAlignment = StringAlignment.Center,
|
||||
Alignment=StringAlignment.Center
|
||||
};
|
||||
|
||||
void DrawStringInCenter(Graphics g, string s, Brush brush, Rectangle bounds)
|
||||
{
|
||||
PointF center = new PointF(bounds.X + bounds.Width/2, bounds.Y + bounds.Height/2);
|
||||
g.DrawString(s, this.Font, brush, center, FormatCenter);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
class MineSweepForm: Form
|
||||
{
|
||||
|
||||
MineFieldModel CreateField(int width, int height)
|
||||
{
|
||||
var field = new bool[height, width];
|
||||
int mineCount = (int)(0.2 * height * width);
|
||||
var rnd = new Random();
|
||||
while(mineCount > 0)
|
||||
{
|
||||
var x = rnd.Next(width);
|
||||
var y = rnd.Next(height);
|
||||
if (!field[y,x])
|
||||
{
|
||||
field[y,x] = true;
|
||||
mineCount--;
|
||||
}
|
||||
}
|
||||
return new MineFieldModel(field);
|
||||
}
|
||||
|
||||
public MineSweepForm()
|
||||
{
|
||||
var model = CreateField(6, 4);
|
||||
var counter = new Label{ };
|
||||
counter.Text = model.RemainingMinesCount.ToString();
|
||||
var view = new MineFieldView
|
||||
{
|
||||
Model = model, BorderStyle = BorderStyle.FixedSingle,
|
||||
};
|
||||
var stackPanel = new FlowLayoutPanel
|
||||
{
|
||||
Dock = DockStyle.Fill,
|
||||
FlowDirection = FlowDirection.TopDown,
|
||||
Controls = {counter, view}
|
||||
};
|
||||
this.Controls.Add(stackPanel);
|
||||
model.Updated += delegate{
|
||||
view.Invalidate();
|
||||
counter.Text = model.RemainingMinesCount.ToString();
|
||||
};
|
||||
model.Exploded += delegate {
|
||||
MessageBox.Show("FAIL!");
|
||||
Close();
|
||||
};
|
||||
model.Win += delegate {
|
||||
MessageBox.Show("WIN!");
|
||||
view.Enabled = false;
|
||||
};
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
class Program
|
||||
{
|
||||
static void Main()
|
||||
{
|
||||
Application.Run(new MineSweepForm());
|
||||
}
|
||||
}
|
||||
416
Task/Minesweeper-game/C/minesweeper-game-1.c
Normal file
416
Task/Minesweeper-game/C/minesweeper-game-1.c
Normal file
|
|
@ -0,0 +1,416 @@
|
|||
#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>
|
||||
#include <ctype.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;
|
||||
}
|
||||
134
Task/Minesweeper-game/Ceylon/minesweeper-game.ceylon
Normal file
134
Task/Minesweeper-game/Ceylon/minesweeper-game.ceylon
Normal file
|
|
@ -0,0 +1,134 @@
|
|||
import ceylon.random {
|
||||
|
||||
DefaultRandom
|
||||
}
|
||||
|
||||
class Cell() {
|
||||
|
||||
shared variable Boolean covered = true;
|
||||
shared variable Boolean flagged = false;
|
||||
shared variable Boolean mined = false;
|
||||
shared variable Integer adjacentMines = 0;
|
||||
|
||||
string =>
|
||||
if (covered && !flagged)
|
||||
then "."
|
||||
else if (covered && flagged)
|
||||
then "?"
|
||||
else if (!covered && mined)
|
||||
then "X"
|
||||
else if (!covered && adjacentMines > 0)
|
||||
then adjacentMines.string
|
||||
else " ";
|
||||
}
|
||||
|
||||
"The main function of the module. Run this one."
|
||||
shared void run() {
|
||||
|
||||
value random = DefaultRandom();
|
||||
value chanceOfBomb = 0.2;
|
||||
|
||||
value width = 6;
|
||||
value height = 4;
|
||||
|
||||
value grid = Array { for (j in 1..height) Array { for (i in 1..width) Cell() } };
|
||||
|
||||
function getCell(Integer x, Integer y) => grid[y]?.get(x);
|
||||
|
||||
void initializeGrid() {
|
||||
|
||||
for (row in grid) {
|
||||
for (cell in row) {
|
||||
cell.covered = true;
|
||||
cell.flagged = false;
|
||||
cell.mined = random.nextFloat() < chanceOfBomb;
|
||||
}
|
||||
}
|
||||
|
||||
function countAdjacentMines(Integer x, Integer y) => count {
|
||||
for (j in y - 1 .. y + 1)
|
||||
for (i in x - 1 .. x + 1)
|
||||
if (exists cell = getCell(i, j))
|
||||
cell.mined
|
||||
};
|
||||
|
||||
for (j->row in grid.indexed) {
|
||||
for (i->cell in row.indexed) {
|
||||
cell.adjacentMines = countAdjacentMines(i, j);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void displayGrid() {
|
||||
print(" " + "".join(1..width));
|
||||
print(" " + "-".repeat(width));
|
||||
for (j->row in grid.indexed) {
|
||||
print("``j + 1``|``"".join(row)``|``j + 1``");
|
||||
}
|
||||
print(" " + "-".repeat(width));
|
||||
print(" " + "".join(1..width));
|
||||
}
|
||||
|
||||
Boolean won() =>
|
||||
expand(grid).every((cell) => (cell.flagged && cell.mined) || (!cell.flagged && !cell.mined));
|
||||
|
||||
void uncoverNeighbours(Integer x, Integer y) {
|
||||
for (j in y - 1 .. y + 1) {
|
||||
for (i in x - 1 .. x + 1) {
|
||||
if (exists cell = getCell(i, j), cell.covered, !cell.flagged, !cell.mined) {
|
||||
cell.covered = false;
|
||||
if (cell.adjacentMines == 0) {
|
||||
uncoverNeighbours(i, j);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
while (true) {
|
||||
print("Welcome to minesweeper!
|
||||
-----------------------");
|
||||
initializeGrid();
|
||||
while (true) {
|
||||
displayGrid();
|
||||
print("
|
||||
The number of mines to find is ``count(expand(grid)*.mined)``.
|
||||
What would you like to do?
|
||||
[1] reveal a free space (or blow yourself up)
|
||||
[2] mark (or unmark) a mine");
|
||||
assert (exists instruction = process.readLine());
|
||||
print("Please enter the coordinates. eg 2 4");
|
||||
assert (exists line2 = process.readLine());
|
||||
value coords = line2.split().map(Integer.parse).narrow<Integer>().sequence();
|
||||
if (exists x = coords[0], exists y = coords[1], exists cell = getCell(x - 1, y - 1)) {
|
||||
switch (instruction)
|
||||
case ("1") {
|
||||
if (cell.mined) {
|
||||
print("=================
|
||||
=== You lose! ===
|
||||
=================");
|
||||
expand(grid).each((cell) => cell.covered = false);
|
||||
displayGrid();
|
||||
break;
|
||||
}
|
||||
else if (cell.covered) {
|
||||
cell.covered = false;
|
||||
uncoverNeighbours(x - 1, y - 1);
|
||||
}
|
||||
}
|
||||
case ("2") {
|
||||
if (cell.covered) {
|
||||
cell.flagged = !cell.flagged;
|
||||
}
|
||||
}
|
||||
else { print("bad choice"); }
|
||||
if (won()) {
|
||||
print("****************
|
||||
*** You win! ***
|
||||
****************");
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
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)
|
||||
219
Task/Minesweeper-game/EasyLang/minesweeper-game.easy
Normal file
219
Task/Minesweeper-game/EasyLang/minesweeper-game.easy
Normal file
|
|
@ -0,0 +1,219 @@
|
|||
len cell[] 56
|
||||
len cnt[] 56
|
||||
len flag[] 56
|
||||
#
|
||||
subr initvars
|
||||
state = 0
|
||||
ticks = 0
|
||||
indx = -1
|
||||
no_time = 0
|
||||
.
|
||||
proc getind r c . ind .
|
||||
ind = -1
|
||||
if r >= 0 and r <= 6 and c >= 0 and c <= 7
|
||||
ind = r * 8 + c + 1
|
||||
.
|
||||
.
|
||||
proc draw_cell ind h . .
|
||||
ind -= 1
|
||||
r = ind div 8
|
||||
c = ind mod 8
|
||||
x = c * 12 + 2.5
|
||||
y = r * 12 + 2.5
|
||||
move x y
|
||||
rect 11 11
|
||||
if h > 0
|
||||
# count
|
||||
move x + 3 y + 3
|
||||
color 000
|
||||
text h
|
||||
elif h = -3
|
||||
# flag
|
||||
x += 4
|
||||
color 000
|
||||
linewidth 0.8
|
||||
move x y + 3
|
||||
line x y + 8
|
||||
color 600
|
||||
linewidth 2
|
||||
move x + 0.5 y + 7
|
||||
line x + 2 y + 7
|
||||
elif h <> 0
|
||||
# mine
|
||||
color 333
|
||||
if h = -2
|
||||
color 800
|
||||
.
|
||||
move x + 5 y + 5
|
||||
circle 3
|
||||
line x + 8 y + 9
|
||||
.
|
||||
.
|
||||
proc open ind . .
|
||||
if ind <> -1 and cell[ind] = 0
|
||||
cell[ind] = 2
|
||||
flag[ind] = 0
|
||||
color 686
|
||||
call draw_cell ind cnt[ind]
|
||||
if cnt[ind] = 0
|
||||
ind -= 1
|
||||
r0 = ind div 8
|
||||
c0 = ind mod 8
|
||||
for r = r0 - 1 to r0 + 1
|
||||
for c = c0 - 1 to c0 + 1
|
||||
if r <> r0 or c <> c0
|
||||
call getind r c ind
|
||||
call open ind
|
||||
.
|
||||
.
|
||||
.
|
||||
.
|
||||
.
|
||||
.
|
||||
proc show_mines m . .
|
||||
for ind to 56
|
||||
if cell[ind] = 1
|
||||
color 686
|
||||
if m = -1
|
||||
color 353
|
||||
.
|
||||
call draw_cell ind m
|
||||
.
|
||||
.
|
||||
.
|
||||
proc outp col s$ . .
|
||||
move 2.5 87
|
||||
color col
|
||||
rect 59 11
|
||||
color 000
|
||||
move 5 90
|
||||
text s$
|
||||
.
|
||||
proc upd_info . .
|
||||
for i to 56
|
||||
nm += flag[i]
|
||||
if cell[i] < 2
|
||||
nc += 1
|
||||
.
|
||||
.
|
||||
if nc = 8
|
||||
call outp 484 "Well done"
|
||||
call show_mines -1
|
||||
state = 1
|
||||
else
|
||||
call outp 464 8 - nm & " mines left"
|
||||
.
|
||||
.
|
||||
proc test ind . .
|
||||
if cell[ind] < 2 and flag[ind] = 0
|
||||
if cell[ind] = 1
|
||||
call show_mines -1
|
||||
color 686
|
||||
call draw_cell ind -2
|
||||
call outp 844 "B O O M !"
|
||||
state = 1
|
||||
else
|
||||
call open ind
|
||||
call upd_info
|
||||
.
|
||||
.
|
||||
.
|
||||
background 676
|
||||
proc start . .
|
||||
clear
|
||||
color 353
|
||||
for ind to 56
|
||||
cnt[ind] = 0
|
||||
cell[ind] = 0
|
||||
flag[ind] = 0
|
||||
call draw_cell ind 0
|
||||
.
|
||||
n = 8
|
||||
while n > 0
|
||||
c = random 8 - 1
|
||||
r = random 7 - 1
|
||||
ind = r * 8 + c + 1
|
||||
if cell[ind] = 0
|
||||
n -= 1
|
||||
cell[ind] = 1
|
||||
for rx = r - 1 to r + 1
|
||||
for cx = c - 1 to c + 1
|
||||
call getind rx cx ind
|
||||
if ind > -1
|
||||
cnt[ind] += 1
|
||||
.
|
||||
.
|
||||
.
|
||||
.
|
||||
.
|
||||
call initvars
|
||||
call outp 464 ""
|
||||
textsize 4
|
||||
move 5 93
|
||||
text "Minesweeper - 8 mines"
|
||||
move 5 88.2
|
||||
text "Long-press for flagging"
|
||||
textsize 6
|
||||
timer 0
|
||||
.
|
||||
on mouse_down
|
||||
if state = 0
|
||||
if mouse_y > 86 and mouse_x > 60
|
||||
no_time = 1
|
||||
move 64.5 87
|
||||
color 464
|
||||
rect 33 11
|
||||
.
|
||||
call getind (mouse_y - 2) div 12 (mouse_x - 2) div 12 indx
|
||||
ticks0 = ticks
|
||||
elif state = 3
|
||||
call start
|
||||
.
|
||||
.
|
||||
on mouse_up
|
||||
if state = 0 and indx <> -1
|
||||
call test indx
|
||||
.
|
||||
indx = -1
|
||||
.
|
||||
on timer
|
||||
if state = 1
|
||||
state = 2
|
||||
timer 1
|
||||
elif state = 2
|
||||
state = 3
|
||||
elif no_time = 0 and ticks > 3000
|
||||
call outp 844 "B O O M !"
|
||||
call show_mines -2
|
||||
state = 2
|
||||
timer 1
|
||||
else
|
||||
if indx > 0 and ticks = ticks0 + 2
|
||||
if cell[indx] < 2
|
||||
color 353
|
||||
flag[indx] = 1 - flag[indx]
|
||||
opt = 0
|
||||
if flag[indx] = 1
|
||||
opt = -3
|
||||
.
|
||||
call draw_cell indx opt
|
||||
call upd_info
|
||||
.
|
||||
indx = -1
|
||||
.
|
||||
if no_time = 0 and ticks mod 10 = 0
|
||||
move 64.5 87
|
||||
color 464
|
||||
if ticks >= 2500
|
||||
color 844
|
||||
.
|
||||
rect 33 11
|
||||
color 000
|
||||
move 66 90
|
||||
text "Time:" & 300 - ticks / 10
|
||||
.
|
||||
ticks += 1
|
||||
timer 0.1
|
||||
.
|
||||
.
|
||||
call start
|
||||
256
Task/Minesweeper-game/FreeBASIC/minesweeper-game.basic
Normal file
256
Task/Minesweeper-game/FreeBASIC/minesweeper-game.basic
Normal file
|
|
@ -0,0 +1,256 @@
|
|||
'--- Declaration of global variables ---
|
||||
Type mina
|
||||
Dim mina As Byte
|
||||
Dim flag As Byte
|
||||
Dim ok As Byte
|
||||
Dim numero As Byte
|
||||
End Type
|
||||
|
||||
Dim Shared As Integer size = 16, NX = 20, NY = 20
|
||||
Dim Shared As Double mina = 0.10
|
||||
|
||||
Dim Shared tablero(NX+1,NY+1) As mina
|
||||
Dim Shared As Integer GameOver, ddx, ddy, kolor, nbDESCANSO
|
||||
Dim Shared As Double temps
|
||||
Dim As String tecla
|
||||
|
||||
'--- SUBroutines and FUNCtions ---
|
||||
Sub VerTodo
|
||||
Dim As Integer x, y
|
||||
For x = 1 To NX
|
||||
For y = 1 To NY
|
||||
With tablero(x,y)
|
||||
If .mina = 1 Or .flag > 0 Then .ok = 1
|
||||
End With
|
||||
Next y
|
||||
Next x
|
||||
End Sub
|
||||
|
||||
Sub ShowGrid
|
||||
Dim As Integer x, y
|
||||
Line(ddx-1,ddy-1)-(1+ddx+size*NX,1+ddy+size*NY),&hFF0000,B
|
||||
For x = 1 To NX
|
||||
For y = 1 To NY
|
||||
With tablero(x,y)
|
||||
'Si la casilla no se hace click
|
||||
If .ok = 0 Then
|
||||
Line(ddx+x*size,ddy+y*size)-(ddx+(x-1)*size,ddy+(y-1)*size),&h888888,BF
|
||||
Line(ddx+x*size,ddy+y*size)-(ddx+(x-1)*size,ddy+(y-1)*size),&h444444,B
|
||||
'bandera verde
|
||||
If .flag = 1 Then
|
||||
Circle (ddx+x*size-size/2,ddy+y*size-size/2),size/4,&h00FF00,,,,F
|
||||
Circle (ddx+x*size-size/2,ddy+y*size-size/2),size/4,&h0
|
||||
End If
|
||||
'bandera azul
|
||||
If .flag = 2 Then
|
||||
Circle (ddx+x*size-size/2,ddy+y*size-size/2),size/4,&h0000FF,,,,F
|
||||
Circle (ddx+x*size-size/2,ddy+y*size-size/2),size/4,&h0
|
||||
End If
|
||||
'Si se hace clic
|
||||
Else
|
||||
If .mina = 0 Then
|
||||
If .numero > 0 Then
|
||||
Select Case .numero
|
||||
Case 1: kolor = &h3333FF
|
||||
Case 2: kolor = &h33FF33
|
||||
Case 3: kolor = &hFF3333
|
||||
Case 4: kolor = &hFFFF33
|
||||
Case 5: kolor = &h33FFFF
|
||||
Case 6: kolor = &hFF33FF
|
||||
Case 7: kolor = &h999999
|
||||
Case 8: kolor = &hFFFFFF
|
||||
End Select
|
||||
Draw String(ddx+x*size-size/1.5,ddy+y*size-size/1.5),Str(.numero),kolor
|
||||
End If
|
||||
If GameOver = 1 Then
|
||||
'Si no hay Mina y una bandera verde >> rojo completo
|
||||
If .flag = 1 Then
|
||||
Circle (ddx+x*size-size/2,ddy+y*size-size/2),size/4,&h330000,,,,F
|
||||
Circle (ddx+x*size-size/2,ddy+y*size-size/2),size/4,&h555555
|
||||
End If
|
||||
'Si no hay Mina y una bandera azul >> azul oscuro
|
||||
If .flag = 2 Then
|
||||
Circle (ddx+x*size-size/2,ddy+y*size-size/2),size/4,&h000033,,,,F
|
||||
Circle (ddx+x*size-size/2,ddy+y*size-size/2),size/4,&h555555
|
||||
End If
|
||||
End If
|
||||
Else
|
||||
'Si hay una Mina sin bandera >> rojo
|
||||
If .flag = 0 Then
|
||||
Circle (ddx+x*size-size/2,ddy+y*size-size/2),size/4,&hFF0000,,,,F
|
||||
Circle (ddx+x*size-size/2,ddy+y*size-size/2),size/4,&hFFFF00
|
||||
Else
|
||||
'Si hay una Mina con bandera verde >>> verde
|
||||
If .flag = 1 Then
|
||||
Circle (ddx+x*size-size/2,ddy+y*size-size/2),size/4,&h00FF00,,,,F
|
||||
Circle (ddx+x*size-size/2,ddy+y*size-size/2),size/4,&hFFFF00
|
||||
End If
|
||||
If .flag = 2 Then
|
||||
'Si hay una Mina con bandera azul >>>> verde oscuro
|
||||
Circle (ddx+x*size-size/2,ddy+y*size-size/2),size/4,&h003300,,,,F
|
||||
Circle (ddx+x*size-size/2,ddy+y*size-size/2),size/4,&hFFFF00
|
||||
End If
|
||||
End If
|
||||
End If
|
||||
End If
|
||||
End With
|
||||
Next y
|
||||
Next x
|
||||
End Sub
|
||||
|
||||
Sub Calcul
|
||||
Dim As Integer x, y
|
||||
For x = 1 To NX
|
||||
For y = 1 To NY
|
||||
tablero(x,y).numero = _
|
||||
Iif(tablero(x+1,y).mina=1,1,0) + Iif(tablero(x-1,y).mina=1,1,0) + _
|
||||
Iif(tablero(x,y+1).mina=1,1,0) + Iif(tablero(x,y-1).mina=1,1,0) + _
|
||||
Iif(tablero(x+1,y-1).mina=1,1,0) + Iif(tablero(x+1,y+1).mina=1,1,0) + _
|
||||
Iif(tablero(x-1,y-1).mina=1,1,0) + Iif(tablero(x-1,y+1).mina=1,1,0)
|
||||
Next y
|
||||
Next x
|
||||
End Sub
|
||||
|
||||
Sub Inicio
|
||||
size = 20
|
||||
If NX > 720/size Then size = 720/NX
|
||||
If NY > 520/size Then size = 520/NY
|
||||
|
||||
Redim tablero(NX+1,NY+1) As mina
|
||||
Dim As Integer x, y
|
||||
For x = 1 To NX
|
||||
For y = 1 To NY
|
||||
With tablero(x,y)
|
||||
.mina = Iif(Rnd > (1-mina), 1, 0)
|
||||
.ok = 0
|
||||
.flag = 0
|
||||
.numero = 0
|
||||
End With
|
||||
Next y
|
||||
Next x
|
||||
ddx = (((800/size)-NX)/2)*size
|
||||
ddy = (((600/size)-NY)/2)*size
|
||||
Calcul
|
||||
End Sub
|
||||
|
||||
Function isGameOver As Integer
|
||||
Dim As Integer x, y, nbMINA, nbOK, nbAZUL, nbVERT
|
||||
For x = 1 To NX
|
||||
For y = 1 To NY
|
||||
If tablero(x,y).ok = 1 And tablero(X,y).mina = 1 Then
|
||||
Return -1
|
||||
End If
|
||||
If tablero(x,y).ok = 0 And tablero(x,y).flag = 1 And tablero(X,y).mina = 1 Then
|
||||
nbOK += 1
|
||||
End If
|
||||
If tablero(X,y).mina = 1 Then
|
||||
nbMINA + =1
|
||||
End If
|
||||
If tablero(X,y).flag = 2 Then
|
||||
nbAZUL += 1
|
||||
'End If
|
||||
Elseif tablero(X,y).flag = 1 Then
|
||||
nbVERT += 1
|
||||
End If
|
||||
Next y
|
||||
Next x
|
||||
|
||||
If nbMINA = nbOK And nbAZUL = 0 Then Return 1
|
||||
nbDESCANSO = nbMINA - nbVERT
|
||||
End Function
|
||||
|
||||
Sub ClicRecursivo(ZX As Integer, ZY As Integer)
|
||||
If tablero(ZX,ZY).ok = 1 Then Exit Sub
|
||||
If tablero(ZX,ZY).flag > 0 Then Exit Sub
|
||||
'CLICK
|
||||
tablero(ZX,ZY).ok = 1
|
||||
|
||||
If tablero(ZX,ZY).mina = 1 Then Exit Sub
|
||||
If tablero(ZX,ZY).numero > 0 Then Exit Sub
|
||||
|
||||
If ZX > 0 And ZX <= NX And ZY > 0 And ZY <= NY Then
|
||||
ClicRecursivo(ZX+1,ZY)
|
||||
ClicRecursivo(ZX-1,ZY)
|
||||
ClicRecursivo(ZX,ZY+1)
|
||||
ClicRecursivo(ZX,ZY-1)
|
||||
ClicRecursivo(ZX+1,ZY+1)
|
||||
ClicRecursivo(ZX+1,ZY-1)
|
||||
ClicRecursivo(ZX-1,ZY+1)
|
||||
ClicRecursivo(ZX-1,ZY-1)
|
||||
End If
|
||||
End Sub
|
||||
|
||||
|
||||
'--- Main Program ---
|
||||
Screenres 800,600,24
|
||||
Windowtitle"Minesweeper game"
|
||||
Randomize Timer
|
||||
Cls
|
||||
Dim As Integer mx, my, mb, fmb, ZX, ZY, r, tt
|
||||
Dim As Double t
|
||||
Inicio
|
||||
GameOver = 1
|
||||
Do
|
||||
tecla = Inkey
|
||||
If GameOver = 1 Then
|
||||
Select Case Ucase(tecla)
|
||||
Case Chr(Asc("X"))
|
||||
NX += 5
|
||||
If NX > 80 Then NX = 10
|
||||
Inicio
|
||||
Case Chr(Asc("Y"))
|
||||
NY += 5
|
||||
If NY > 60 Then NY = 10
|
||||
Inicio
|
||||
Case Chr(Asc("M"))
|
||||
mina += 0.01
|
||||
If mina > 0.26 Then mina = 0.05
|
||||
Inicio
|
||||
Case Chr(Asc("S"))
|
||||
Inicio
|
||||
GameOver = 0
|
||||
temps = Timer
|
||||
End Select
|
||||
End If
|
||||
|
||||
Getmouse mx,my,,mb
|
||||
mx -= ddx-size
|
||||
my -= ddy-size
|
||||
ZX = (MX-size/2)/size
|
||||
ZY = (MY-size/2)/size
|
||||
|
||||
If GameOver = 0 And zx > 0 And zx <= nx And zy > 0 And zy <= ny Then
|
||||
If MB=1 And fmb=0 Then ClicRecursivo(ZX,ZY)
|
||||
If MB=2 And fmb=0 Then
|
||||
tablero(ZX,ZY).flag += 1
|
||||
If tablero(ZX,ZY).flag > 2 Then tablero(ZX,ZY).flag = 0
|
||||
End If
|
||||
fmb = mb
|
||||
End If
|
||||
|
||||
r = isGameOver
|
||||
If r = -1 And GameOver = 0 Then
|
||||
VerTodo
|
||||
GameOver = 1
|
||||
End If
|
||||
If r = 1 And GameOver = 0 Then GameOver = 1
|
||||
If GameOver = 0 Then tt = Timer-temps
|
||||
|
||||
Screenlock
|
||||
Cls
|
||||
ShowGrid
|
||||
If GameOver = 0 Then
|
||||
Draw String (210,4), "X:" & NX & " Y:" & NY & " MINA:" & Int(mina*100) & "% TIMER : " & Int(TT) & " S REMAINING:" & nbDESCANSO,&hFFFF00
|
||||
Else
|
||||
Draw String (260,4), "PRESS: 'S' TO START X,Y,M TO SIZE" ,&hFFFF00
|
||||
Draw String (330,17), "X:" & NX & " Y:" & NY & " MINA:" & Int(mina*100) & "%" ,&hFFFF00
|
||||
If r = 1 Then
|
||||
t += 0.01
|
||||
If t > 1000 Then t = 0
|
||||
Draw String (320,280+Cos(t)*100),"!! CONGRATULATION !!",&hFFFF00
|
||||
End If
|
||||
End If
|
||||
Screenunlock
|
||||
Loop Until tecla = Chr(27)
|
||||
Bsave "Minesweeper.bmp",0
|
||||
End
|
||||
253
Task/Minesweeper-game/Go/minesweeper-game.go
Normal file
253
Task/Minesweeper-game/Go/minesweeper-game.go
Normal file
|
|
@ -0,0 +1,253 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"fmt"
|
||||
"math"
|
||||
"math/rand"
|
||||
"os"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
)
|
||||
|
||||
type cell struct {
|
||||
isMine bool
|
||||
display byte // display character for cell
|
||||
}
|
||||
|
||||
const lMargin = 4
|
||||
|
||||
var (
|
||||
grid [][]cell
|
||||
mineCount int
|
||||
minesMarked int
|
||||
isGameOver bool
|
||||
)
|
||||
|
||||
var scanner = bufio.NewScanner(os.Stdin)
|
||||
|
||||
func makeGrid(n, m int) {
|
||||
if n <= 0 || m <= 0 {
|
||||
panic("Grid dimensions must be positive.")
|
||||
}
|
||||
grid = make([][]cell, n)
|
||||
for i := 0; i < n; i++ {
|
||||
grid[i] = make([]cell, m)
|
||||
for j := 0; j < m; j++ {
|
||||
grid[i][j].display = '.'
|
||||
}
|
||||
}
|
||||
min := int(math.Round(float64(n*m) * 0.1)) // 10% of tiles
|
||||
max := int(math.Round(float64(n*m) * 0.2)) // 20% of tiles
|
||||
mineCount = min + rand.Intn(max-min+1)
|
||||
rm := mineCount
|
||||
for rm > 0 {
|
||||
x, y := rand.Intn(n), rand.Intn(m)
|
||||
if !grid[x][y].isMine {
|
||||
rm--
|
||||
grid[x][y].isMine = true
|
||||
}
|
||||
}
|
||||
minesMarked = 0
|
||||
isGameOver = false
|
||||
}
|
||||
|
||||
func displayGrid(isEndOfGame bool) {
|
||||
if !isEndOfGame {
|
||||
fmt.Println("Grid has", mineCount, "mine(s),", minesMarked, "mine(s) marked.")
|
||||
}
|
||||
margin := strings.Repeat(" ", lMargin)
|
||||
fmt.Print(margin, " ")
|
||||
for i := 1; i <= len(grid); i++ {
|
||||
fmt.Print(i)
|
||||
}
|
||||
fmt.Println()
|
||||
fmt.Println(margin, strings.Repeat("-", len(grid)))
|
||||
for y := 0; y < len(grid[0]); y++ {
|
||||
fmt.Printf("%*d:", lMargin, y+1)
|
||||
for x := 0; x < len(grid); x++ {
|
||||
fmt.Printf("%c", grid[x][y].display)
|
||||
}
|
||||
fmt.Println()
|
||||
}
|
||||
}
|
||||
|
||||
func endGame(msg string) {
|
||||
isGameOver = true
|
||||
fmt.Println(msg)
|
||||
ans := ""
|
||||
for ans != "y" && ans != "n" {
|
||||
fmt.Print("Another game (y/n)? : ")
|
||||
scanner.Scan()
|
||||
ans = strings.ToLower(scanner.Text())
|
||||
}
|
||||
if scanner.Err() != nil || ans == "n" {
|
||||
return
|
||||
}
|
||||
makeGrid(6, 4)
|
||||
displayGrid(false)
|
||||
}
|
||||
|
||||
func resign() {
|
||||
found := 0
|
||||
for y := 0; y < len(grid[0]); y++ {
|
||||
for x := 0; x < len(grid); x++ {
|
||||
if grid[x][y].isMine {
|
||||
if grid[x][y].display == '?' {
|
||||
grid[x][y].display = 'Y'
|
||||
found++
|
||||
} else if grid[x][y].display != 'x' {
|
||||
grid[x][y].display = 'N'
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
displayGrid(true)
|
||||
msg := fmt.Sprint("You found ", found, " out of ", mineCount, " mine(s).")
|
||||
endGame(msg)
|
||||
}
|
||||
|
||||
func usage() {
|
||||
fmt.Println("h or ? - this help,")
|
||||
fmt.Println("c x y - clear cell (x,y),")
|
||||
fmt.Println("m x y - marks (toggles) cell (x,y),")
|
||||
fmt.Println("n - start a new game,")
|
||||
fmt.Println("q - quit/resign the game,")
|
||||
fmt.Println("where x is the (horizontal) column number and y is the (vertical) row number.\n")
|
||||
}
|
||||
|
||||
func markCell(x, y int) {
|
||||
if grid[x][y].display == '?' {
|
||||
minesMarked--
|
||||
grid[x][y].display = '.'
|
||||
} else if grid[x][y].display == '.' {
|
||||
minesMarked++
|
||||
grid[x][y].display = '?'
|
||||
}
|
||||
}
|
||||
|
||||
func countAdjMines(x, y int) int {
|
||||
count := 0
|
||||
for j := y - 1; j <= y+1; j++ {
|
||||
if j >= 0 && j < len(grid[0]) {
|
||||
for i := x - 1; i <= x+1; i++ {
|
||||
if i >= 0 && i < len(grid) {
|
||||
if grid[i][j].isMine {
|
||||
count++
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return count
|
||||
}
|
||||
|
||||
func clearCell(x, y int) bool {
|
||||
if x >= 0 && x < len(grid) && y >= 0 && y < len(grid[0]) {
|
||||
if grid[x][y].display == '.' {
|
||||
if !grid[x][y].isMine {
|
||||
count := countAdjMines(x, y)
|
||||
if count > 0 {
|
||||
grid[x][y].display = string(48 + count)[0]
|
||||
} else {
|
||||
grid[x][y].display = ' '
|
||||
clearCell(x+1, y)
|
||||
clearCell(x+1, y+1)
|
||||
clearCell(x, y+1)
|
||||
clearCell(x-1, y+1)
|
||||
clearCell(x-1, y)
|
||||
clearCell(x-1, y-1)
|
||||
clearCell(x, y-1)
|
||||
clearCell(x+1, y-1)
|
||||
}
|
||||
} else {
|
||||
grid[x][y].display = 'x'
|
||||
fmt.Println("Kaboom! You lost!")
|
||||
return false
|
||||
}
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
func testForWin() bool {
|
||||
isCleared := false
|
||||
if minesMarked == mineCount {
|
||||
isCleared = true
|
||||
for x := 0; x < len(grid); x++ {
|
||||
for y := 0; y < len(grid[0]); y++ {
|
||||
if grid[x][y].display == '.' {
|
||||
isCleared = false
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if isCleared {
|
||||
fmt.Println("You won!")
|
||||
}
|
||||
return isCleared
|
||||
}
|
||||
|
||||
func splitAction(action string) (int, int, bool) {
|
||||
fields := strings.Fields(action)
|
||||
if len(fields) != 3 {
|
||||
return 0, 0, false
|
||||
}
|
||||
x, err := strconv.Atoi(fields[1])
|
||||
if err != nil || x < 1 || x > len(grid) {
|
||||
return 0, 0, false
|
||||
}
|
||||
y, err := strconv.Atoi(fields[2])
|
||||
if err != nil || y < 1 || y > len(grid[0]) {
|
||||
return 0, 0, false
|
||||
}
|
||||
return x, y, true
|
||||
}
|
||||
|
||||
func main() {
|
||||
rand.Seed(time.Now().UnixNano())
|
||||
usage()
|
||||
makeGrid(6, 4)
|
||||
displayGrid(false)
|
||||
for !isGameOver {
|
||||
fmt.Print("\n>")
|
||||
scanner.Scan()
|
||||
action := strings.ToLower(scanner.Text())
|
||||
if scanner.Err() != nil || len(action) == 0 {
|
||||
continue
|
||||
}
|
||||
switch action[0] {
|
||||
case 'h', '?':
|
||||
usage()
|
||||
case 'n':
|
||||
makeGrid(6, 4)
|
||||
displayGrid(false)
|
||||
case 'c':
|
||||
x, y, ok := splitAction(action)
|
||||
if !ok {
|
||||
continue
|
||||
}
|
||||
if clearCell(x-1, y-1) {
|
||||
displayGrid(false)
|
||||
if testForWin() {
|
||||
resign()
|
||||
}
|
||||
} else {
|
||||
resign()
|
||||
}
|
||||
case 'm':
|
||||
x, y, ok := splitAction(action)
|
||||
if !ok {
|
||||
continue
|
||||
}
|
||||
markCell(x-1, y-1)
|
||||
displayGrid(false)
|
||||
if testForWin() {
|
||||
resign()
|
||||
}
|
||||
case 'q':
|
||||
resign()
|
||||
}
|
||||
}
|
||||
}
|
||||
192
Task/Minesweeper-game/Haskell/minesweeper-game-1.hs
Normal file
192
Task/Minesweeper-game/Haskell/minesweeper-game-1.hs
Normal file
|
|
@ -0,0 +1,192 @@
|
|||
{-# LANGUAGE TemplateHaskell #-}
|
||||
|
||||
module MineSweeper
|
||||
( Board
|
||||
, Cell(..)
|
||||
, CellState(..)
|
||||
, Pos
|
||||
-- lenses / prisms
|
||||
, pos
|
||||
, coveredLens
|
||||
, coveredFlaggedLens
|
||||
, coveredMinedLens
|
||||
, xCoordLens
|
||||
, yCoordLens
|
||||
-- Functions
|
||||
, emptyBoard
|
||||
, groupedByRows
|
||||
, displayCell
|
||||
, isLoss
|
||||
, isWin
|
||||
, exposeMines
|
||||
, openCell
|
||||
, flagCell
|
||||
, mineBoard
|
||||
, totalRows
|
||||
, totalCols )
|
||||
where
|
||||
|
||||
import Control.Lens ((%~), (&), (.~), (^.), (^?), Lens', Traversal', _1, _2,
|
||||
anyOf, filtered, folded, lengthOf, makeLenses, makePrisms,
|
||||
preview, to, view)
|
||||
import Data.List (find, groupBy, nub, delete, sortBy)
|
||||
import Data.Maybe (isJust)
|
||||
import System.Random (getStdGen, getStdRandom, randomR, randomRs)
|
||||
|
||||
type Pos = (Int, Int)
|
||||
type Board = [Cell]
|
||||
|
||||
data CellState = Covered { _mined :: Bool, _flagged :: Bool }
|
||||
| UnCovered { _mined :: Bool }
|
||||
deriving (Show, Eq)
|
||||
|
||||
data Cell = Cell
|
||||
{ _pos :: Pos
|
||||
, _state :: CellState
|
||||
, _cellId :: Int
|
||||
, _adjacentMines :: Int }
|
||||
deriving (Show, Eq)
|
||||
|
||||
makePrisms ''CellState
|
||||
makeLenses ''CellState
|
||||
makeLenses ''Cell
|
||||
|
||||
-- Re-useable lens.
|
||||
coveredLens :: Traversal' Cell (Bool, Bool) --'
|
||||
coveredLens = state . _Covered
|
||||
|
||||
coveredMinedLens, coveredFlaggedLens, unCoveredLens :: Traversal' Cell Bool --'
|
||||
coveredMinedLens = coveredLens . _1
|
||||
coveredFlaggedLens = coveredLens . _2
|
||||
unCoveredLens = state . _UnCovered
|
||||
|
||||
xCoordLens, yCoordLens :: Lens' Cell Int --'
|
||||
xCoordLens = pos . _1
|
||||
yCoordLens = pos . _2
|
||||
|
||||
-- Adjust row and column size to your preference.
|
||||
totalRows, totalCols :: Int
|
||||
totalRows = 4
|
||||
totalCols = 6
|
||||
|
||||
emptyBoard :: Board
|
||||
emptyBoard = (\(n, p) -> Cell { _pos = p
|
||||
, _state = Covered False False
|
||||
, _adjacentMines = 0
|
||||
, _cellId = n }) <$> zip [1..] positions
|
||||
where
|
||||
positions = (,) <$> [1..totalCols] <*> [1..totalRows]
|
||||
|
||||
updateCell :: Cell -> Board -> Board
|
||||
updateCell cell = fmap (\c -> if cell ^. cellId == c ^. cellId then cell else c)
|
||||
|
||||
updateBoard :: Board -> [Cell] -> Board
|
||||
updateBoard = foldr updateCell
|
||||
|
||||
okToOpen :: [Cell] -> [Cell]
|
||||
okToOpen = filter (\c -> c ^? coveredLens == Just (False, False))
|
||||
|
||||
openUnMined :: Cell -> Cell
|
||||
openUnMined = state .~ UnCovered False
|
||||
|
||||
openCell :: Pos -> Board -> Board
|
||||
openCell p b = f $ find (\c -> c ^. pos == p) b
|
||||
where
|
||||
f (Just c)
|
||||
| c ^? coveredFlaggedLens == Just True = b
|
||||
| c ^? coveredMinedLens == Just True = updateCell
|
||||
(c & state .~ UnCovered True)
|
||||
b
|
||||
| isCovered c = if c ^. adjacentMines == 0 && not (isFirstMove b)
|
||||
then updateCell (openUnMined c) $ expandEmptyCells b c
|
||||
else updateCell (openUnMined c) b
|
||||
| otherwise = b
|
||||
f Nothing = b
|
||||
isCovered = isJust . preview coveredLens
|
||||
|
||||
expandEmptyCells :: Board -> Cell -> Board
|
||||
expandEmptyCells board cell
|
||||
| null openedCells = board
|
||||
| otherwise = foldr (flip expandEmptyCells) updatedBoard (zeroAdjacent openedCells)
|
||||
where
|
||||
findMore _ [] = []
|
||||
findMore exclude (c : xs)
|
||||
| c `elem` exclude = findMore exclude xs
|
||||
| c ^. adjacentMines == 0 = c : adjacent c <>
|
||||
findMore (c : exclude <> adjacent c) xs
|
||||
| otherwise = c : findMore (c : exclude) xs
|
||||
adjacent = okToOpen . flip adjacentCells board
|
||||
openedCells = openUnMined <$> nub (findMore [cell] (adjacent cell))
|
||||
zeroAdjacent = filter (view (adjacentMines . to (== 0)))
|
||||
updatedBoard = updateBoard board openedCells
|
||||
|
||||
flagCell :: Pos -> Board -> Board
|
||||
flagCell p board = case find ((== p) . view pos) board of
|
||||
Just c -> updateCell (c & state . flagged %~ not) board
|
||||
Nothing -> board
|
||||
|
||||
adjacentCells :: Cell -> Board -> [Cell]
|
||||
adjacentCells Cell {_pos = c@(x1, y1)} = filter (\c -> c ^. pos `elem` positions)
|
||||
where
|
||||
f n = [pred n, n, succ n]
|
||||
positions = delete c $ [(x, y) | x <- f x1, x > 0, y <- f y1, y > 0]
|
||||
|
||||
isLoss, isWin, allUnMinedOpen, allMinesFlagged, isFirstMove :: Board -> Bool
|
||||
isLoss = anyOf (traverse . unCoveredLens) (== True)
|
||||
isWin b = allUnMinedOpen b || allMinesFlagged b
|
||||
|
||||
allUnMinedOpen = (== 0) . lengthOf (traverse . coveredMinedLens . filtered (== False))
|
||||
allMinesFlagged b = minedCount b == flaggedMineCount b
|
||||
where
|
||||
minedCount = lengthOf (traverse . coveredMinedLens . filtered (== True))
|
||||
flaggedMineCount = lengthOf (traverse . coveredLens . filtered (== (True, True)))
|
||||
|
||||
isFirstMove = (== totalCols * totalRows) . lengthOf (folded . coveredFlaggedLens . filtered (== False))
|
||||
|
||||
groupedByRows :: Board -> [Board]
|
||||
groupedByRows = groupBy (\c1 c2 -> yAxis c1 == yAxis c2)
|
||||
. sortBy (\c1 c2 -> yAxis c1 `compare` yAxis c2)
|
||||
where
|
||||
yAxis = view yCoordLens
|
||||
|
||||
displayCell :: Cell -> String
|
||||
displayCell c
|
||||
| c ^? unCoveredLens == Just True = "X"
|
||||
| c ^? coveredFlaggedLens == Just True = "?"
|
||||
| c ^? (unCoveredLens . to not) == Just True =
|
||||
if c ^. adjacentMines > 0 then show $ c ^. adjacentMines else "▢"
|
||||
| otherwise = "."
|
||||
|
||||
exposeMines :: Board -> Board
|
||||
exposeMines = fmap (\c -> c & state . filtered (\s -> s ^? _Covered . _1 == Just True) .~ UnCovered True)
|
||||
|
||||
updateMineCount :: Board -> Board
|
||||
updateMineCount b = go b
|
||||
where
|
||||
go [] = []
|
||||
go (x : xs) = (x & adjacentMines .~ totalAdjacentMines b) : go xs
|
||||
where
|
||||
totalAdjacentMines =
|
||||
foldr (\c acc -> if c ^. (state . mined) then succ acc else acc) 0 . adjacentCells x
|
||||
|
||||
-- IO
|
||||
mineBoard :: Pos -> Board -> IO Board
|
||||
mineBoard p board = do
|
||||
totalMines <- randomMinedCount
|
||||
minedBoard totalMines >>= \mb -> pure $ updateMineCount mb
|
||||
where
|
||||
mines n = take n <$> randomCellIds
|
||||
minedBoard n = (\m ->
|
||||
fmap (\c -> if c ^. cellId `elem` m then c & state . mined .~ True else c)
|
||||
board) . filter (\c -> openedCell ^. cellId /= c)
|
||||
<$> mines n
|
||||
openedCell = head $ filter (\c -> c ^. pos == p) board
|
||||
|
||||
randomCellIds :: IO [Int]
|
||||
randomCellIds = randomRs (1, totalCols * totalRows) <$> getStdGen
|
||||
|
||||
randomMinedCount :: IO Int
|
||||
randomMinedCount = getStdRandom $ randomR (minMinedCells, maxMinedCells)
|
||||
where
|
||||
maxMinedCells = floor $ realToFrac (totalCols * totalRows) * 0.2
|
||||
minMinedCells = floor $ realToFrac (totalCols * totalRows) * 0.1
|
||||
80
Task/Minesweeper-game/Haskell/minesweeper-game-2.hs
Normal file
80
Task/Minesweeper-game/Haskell/minesweeper-game-2.hs
Normal file
|
|
@ -0,0 +1,80 @@
|
|||
module Main
|
||||
|
||||
where
|
||||
|
||||
import MineSweeper (Board, Cell (..), Pos, coveredLens, coveredMinedLens,
|
||||
coveredFlaggedLens, xCoordLens, yCoordLens, pos, emptyBoard,
|
||||
groupedByRows, displayCell, isLoss, isWin, exposeMines,
|
||||
openCell, flagCell, mineBoard, totalRows, totalCols)
|
||||
import Text.Printf (printf)
|
||||
import Text.Read (readMaybe)
|
||||
import System.IO (hSetBuffering, stdout, BufferMode(..))
|
||||
import Control.Monad (join, guard)
|
||||
import Control.Lens (lengthOf, filtered, view, preview)
|
||||
|
||||
data Command = Open Pos | Flag Pos | Invalid
|
||||
|
||||
parseInput :: String -> Command
|
||||
parseInput s | length input /= 3 = Invalid
|
||||
| otherwise = maybe Invalid command parsedPos
|
||||
where
|
||||
input = words s
|
||||
parsedPos = do
|
||||
x <- readMaybe (input !! 1)
|
||||
y <- readMaybe (input !! 2)
|
||||
guard (x <= totalCols && y <= totalRows)
|
||||
pure (x, y)
|
||||
command p = case head input of
|
||||
"o" -> Open p
|
||||
"f" -> Flag p
|
||||
_ -> Invalid
|
||||
|
||||
cheat :: Board -> String
|
||||
cheat = show . fmap (view pos) . filter ((== Just True) . preview coveredMinedLens)
|
||||
|
||||
totalMines, totalFlagged, totalCovered :: Board -> Int
|
||||
totalMines = lengthOf (traverse . coveredMinedLens . filtered (==True))
|
||||
totalFlagged = lengthOf (traverse . coveredFlaggedLens . filtered (==True))
|
||||
totalCovered = lengthOf (traverse . coveredLens)
|
||||
|
||||
-- IO
|
||||
drawBoard :: Board -> IO ()
|
||||
drawBoard b = do
|
||||
-- printf "Cheat: %s\n" $ cheat b
|
||||
printf " Mines: %d Covered: %d Flagged: %d\n\n"
|
||||
(totalMines b) (totalCovered b) (totalFlagged b)
|
||||
printf "%3s" ""
|
||||
mapM_ (printf "%3d") $ view xCoordLens <$> head rows
|
||||
printf "\n"
|
||||
mapM_ (\row -> do
|
||||
printf "%3d" $ yCoord row
|
||||
mapM_ (printf "%3s" . displayCell) row
|
||||
printf "\n" ) rows
|
||||
where
|
||||
rows = groupedByRows b
|
||||
yCoord = view yCoordLens . head
|
||||
|
||||
gameLoop :: Board -> IO ()
|
||||
gameLoop b
|
||||
| isLoss b = drawBoard (exposeMines b) >> printf "\nYou Lose.\n"
|
||||
| isWin b = drawBoard b >> printf "\nYou Win.\n"
|
||||
| otherwise = do
|
||||
drawBoard b
|
||||
putStr "\nPick a cell: "
|
||||
c <- getLine
|
||||
case parseInput c of
|
||||
Open p -> gameLoop $ openCell p b
|
||||
Flag p -> gameLoop $ flagCell p b
|
||||
Invalid -> gameLoop b
|
||||
|
||||
main :: IO ()
|
||||
main = do
|
||||
hSetBuffering stdout NoBuffering
|
||||
drawBoard emptyBoard
|
||||
putStr "\nPick a cell: "
|
||||
c <- getLine
|
||||
case parseInput c of
|
||||
Open p -> join $ startGame p emptyBoard
|
||||
_ -> main
|
||||
where
|
||||
startGame p b = gameLoop . openCell p <$> mineBoard p b
|
||||
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
|
||||
103
Task/Minesweeper-game/J/minesweeper-game-1.j
Normal file
103
Task/Minesweeper-game/J/minesweeper-game-1.j
Normal file
|
|
@ -0,0 +1,103 @@
|
|||
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=: verb define
|
||||
smoutput Instructions
|
||||
startgame y
|
||||
)
|
||||
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?
|
||||
632
Task/Minesweeper-game/Java/minesweeper-game.java
Normal file
632
Task/Minesweeper-game/Java/minesweeper-game.java
Normal file
|
|
@ -0,0 +1,632 @@
|
|||
--------------------------------- START of Main.java ---------------------------------
|
||||
//By xykmz. Enjoy!
|
||||
|
||||
import java.util.Scanner;
|
||||
|
||||
public class Main {
|
||||
|
||||
static int intErrorTrap (int x, int y){
|
||||
|
||||
int max, min;
|
||||
|
||||
if (x < y) {
|
||||
min = x;
|
||||
max = y;
|
||||
} else {
|
||||
min = y;
|
||||
max = x;
|
||||
}
|
||||
|
||||
int input;
|
||||
boolean loopEnd;
|
||||
|
||||
do {
|
||||
|
||||
System.out.println("Please enter an integer between " + min + " to " + max + ".");
|
||||
Scanner userInput = new Scanner(System.in); //Player inputs a guess
|
||||
|
||||
try
|
||||
{
|
||||
input = userInput.nextInt();
|
||||
|
||||
if(input > max) //Input is too high
|
||||
{
|
||||
loopEnd = false;
|
||||
System.out.println("Input is invalid.");
|
||||
return -1;
|
||||
}
|
||||
|
||||
else if(input < min) //Input is too low
|
||||
{
|
||||
loopEnd = false;
|
||||
System.out.println("Input is invalid.");
|
||||
return -1;
|
||||
}
|
||||
|
||||
else //Input is within acceptable range
|
||||
{
|
||||
loopEnd = true;
|
||||
System.out.println(input + " is a valid input.");
|
||||
return input;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
catch (Exception e)
|
||||
{
|
||||
loopEnd = false;
|
||||
userInput.next();
|
||||
System.out.println("Input is invalid.");
|
||||
return 0;
|
||||
}
|
||||
|
||||
} while (loopEnd == false);
|
||||
}
|
||||
|
||||
|
||||
public static void main(String[] args) {
|
||||
|
||||
System.out.println ("Enter width.");
|
||||
int x = intErrorTrap (0,60);
|
||||
|
||||
System.out.println ("Enter height.");
|
||||
int y = intErrorTrap (0,30);
|
||||
|
||||
System.out.println ("Enter difficulty.");
|
||||
int d = intErrorTrap (0,100);
|
||||
|
||||
new Minesweeper(x, y, d); //Suggested: (60, 30, 15)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
//--------------------------------- END of Main.java ---------------------------------
|
||||
|
||||
//--------------------------------- START of Cell.java ---------------------------------
|
||||
|
||||
|
||||
|
||||
public class Cell{ //This entire class is quite self-explanatory. All we're really doing is setting booleans.
|
||||
|
||||
private boolean isMine, isFlagged, isCovered;
|
||||
private int number;
|
||||
|
||||
public Cell(){
|
||||
isMine = false;
|
||||
isFlagged = false;
|
||||
isCovered = true;
|
||||
number = 0;
|
||||
}
|
||||
|
||||
public void flag(){
|
||||
isFlagged = true;
|
||||
}
|
||||
|
||||
public void unflag(){
|
||||
isFlagged = false;
|
||||
}
|
||||
|
||||
public void setMine(){
|
||||
isMine = true;
|
||||
}
|
||||
|
||||
public boolean isMine(){
|
||||
return isMine;
|
||||
}
|
||||
|
||||
public void reveal(){
|
||||
isCovered = false;
|
||||
}
|
||||
|
||||
public void setNumber(int i){ //Set the number of the cell
|
||||
number = i;
|
||||
}
|
||||
|
||||
public int getNumber(){ //Request the program for the number of the cell
|
||||
return number;
|
||||
}
|
||||
|
||||
public boolean isFlagged(){
|
||||
return isFlagged;
|
||||
}
|
||||
|
||||
public boolean isCovered(){
|
||||
return isCovered;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
//--------------------------------- END of Cell.java ---------------------------------
|
||||
|
||||
//--------------------------------- START of Board.java ---------------------------------
|
||||
|
||||
import java.awt.Color;
|
||||
import java.awt.Dimension;
|
||||
import java.awt.Graphics;
|
||||
import javax.swing.JPanel;
|
||||
|
||||
public class Board extends JPanel{
|
||||
|
||||
private static final long serialVersionUID = 1L; //Guarantees consistent serialVersionUID value across different java compiler implementations,
|
||||
//Auto-generated value might screw things up
|
||||
|
||||
private Minesweeper mine;
|
||||
private Cell[][] cells;
|
||||
|
||||
|
||||
public void paintComponent(Graphics g){
|
||||
|
||||
cells = mine.getCells();
|
||||
|
||||
for (int i = 0; i < mine.getx(); i++){
|
||||
|
||||
for (int j = 0; j < mine.gety(); j++){
|
||||
|
||||
Cell current = cells[i][j];
|
||||
|
||||
|
||||
//Flagged cells
|
||||
if (current.isFlagged()){
|
||||
|
||||
if (current.isMine() && mine.isFinished()){
|
||||
|
||||
g.setColor(Color.ORANGE); //Let's the player know which mines they got right when the game is finished.
|
||||
g.fillRect(i * 20, j * 20, i * 20 + 20, j * 20 + 20);
|
||||
g.setColor(Color.BLACK);
|
||||
|
||||
g.drawLine(i * 20, j * 20, i * 20 + 20, j * 20 + 20);
|
||||
g.drawLine(i * 20, j * 20 + 20, i * 20 + 20, j * 20);
|
||||
}
|
||||
else if (mine.isFinished()){ //Shows cells that the player incorrectly identified as mines.
|
||||
g.setColor(Color.YELLOW);
|
||||
g.fillRect(i * 20, j * 20, i * 20 + 20, j * 20 + 20);
|
||||
g.setColor(Color.BLACK);
|
||||
}
|
||||
else{
|
||||
g.setColor(Color.GREEN); //Flagging a mine.
|
||||
g.fillRect(i * 20, j * 20, i * 20 + 20, j * 20 + 20);
|
||||
g.setColor(Color.BLACK);
|
||||
}
|
||||
}
|
||||
|
||||
//Unflagged cells
|
||||
else if (current.isCovered()){ //Covered cells
|
||||
g.setColor(Color.DARK_GRAY);
|
||||
g.fillRect(i * 20, j * 20, i * 20 + 20, j * 20 + 20);
|
||||
g.setColor(Color.BLACK);
|
||||
}
|
||||
else if (current.isMine()){ //Incorrect cells are shown when the game is over.=
|
||||
g.setColor(Color.RED);
|
||||
g.fillRect(i * 20, j * 20, i * 20 + 20, j * 20 + 20);
|
||||
g.setColor(Color.BLACK);
|
||||
g.drawLine(i * 20, j * 20, i * 20 + 20, j * 20 + 20);
|
||||
g.drawLine(i * 20, j * 20 + 20, i * 20 + 20, j * 20);
|
||||
}
|
||||
else{ //Empty cells or numbered cells
|
||||
g.setColor(Color.LIGHT_GRAY);
|
||||
g.fillRect(i * 20, j * 20, i * 20 + 20, j * 20 + 20);
|
||||
g.setColor(Color.BLACK);
|
||||
}
|
||||
|
||||
//The following part is very self explanatory - drawing the numbers.
|
||||
//Not very interesting work.
|
||||
//Not a fun time.
|
||||
//Rating: 0/10. Would not recommend.
|
||||
|
||||
if (!current.isCovered()){
|
||||
if (current.getNumber() == 1){
|
||||
g.drawLine(i * 20 + 13, j * 20 + 5, i * 20 + 13, j * 20 + 9); //3
|
||||
g.drawLine(i * 20 + 13, j * 20 + 11, i * 20 + 13, j * 20 + 15); //6
|
||||
}
|
||||
else if (current.getNumber() == 2){
|
||||
g.drawLine(i * 20 + 8, j * 20 + 4, i * 20 + 12, j * 20 + 4); //2
|
||||
g.drawLine(i * 20 + 13, j * 20 + 5, i * 20 + 13, j * 20 + 9); //3
|
||||
g.drawLine(i * 20 + 8, j * 20 + 10, i * 20 + 12, j * 20 + 10); //4
|
||||
g.drawLine(i * 20 + 7, j * 20 + 11, i * 20 + 7, j * 20 + 15); //5
|
||||
g.drawLine(i * 20 + 8, j * 20 + 16, i * 20 + 12, j * 20 + 16); //7
|
||||
}
|
||||
else if (current.getNumber() == 3){
|
||||
g.drawLine(i * 20 + 8, j * 20 + 4, i * 20 + 12, j * 20 + 4); //2
|
||||
g.drawLine(i * 20 + 13, j * 20 + 5, i * 20 + 13, j * 20 + 9); //3
|
||||
g.drawLine(i * 20 + 8, j * 20 + 10, i * 20 + 12, j * 20 + 10); //4
|
||||
g.drawLine(i * 20 + 13, j * 20 + 11, i * 20 + 13, j * 20 + 15); //6
|
||||
g.drawLine(i * 20 + 8, j * 20 + 16, i * 20 + 12, j * 20 + 16); //7
|
||||
}
|
||||
else if (current.getNumber() == 4){
|
||||
g.drawLine(i * 20 + 7, j * 20 + 5, i * 20 + 7, j * 20 + 9); //1
|
||||
g.drawLine(i * 20 + 13, j * 20 + 5, i * 20 + 13, j * 20 + 9); //3
|
||||
g.drawLine(i * 20 + 8, j * 20 + 10, i * 20 + 12, j * 20 + 10); //4
|
||||
g.drawLine(i * 20 + 13, j * 20 + 11, i * 20 + 13, j * 20 + 15); //6
|
||||
}
|
||||
else if (current.getNumber() == 5){
|
||||
g.drawLine(i * 20 + 7, j * 20 + 5, i * 20 + 7, j * 20 + 9); //1
|
||||
g.drawLine(i * 20 + 8, j * 20 + 4, i * 20 + 12, j * 20 + 4); //2
|
||||
g.drawLine(i * 20 + 8, j * 20 + 10, i * 20 + 12, j * 20 + 10); //4
|
||||
g.drawLine(i * 20 + 13, j * 20 + 11, i * 20 + 13, j * 20 + 15); //6
|
||||
g.drawLine(i * 20 + 8, j * 20 + 16, i * 20 + 12, j * 20 + 16); //7
|
||||
}
|
||||
else if (current.getNumber() == 6){
|
||||
g.drawLine(i * 20 + 7, j * 20 + 5, i * 20 + 7, j * 20 + 9); //1
|
||||
g.drawLine(i * 20 + 8, j * 20 + 4, i * 20 + 12, j * 20 + 4); //2
|
||||
g.drawLine(i * 20 + 8, j * 20 + 10, i * 20 + 12, j * 20 + 10); //4
|
||||
g.drawLine(i * 20 + 7, j * 20 + 11, i * 20 + 7, j * 20 + 15); //5
|
||||
g.drawLine(i * 20 + 13, j * 20 + 11, i * 20 + 13, j * 20 + 15); //6
|
||||
g.drawLine(i * 20 + 8, j * 20 + 16, i * 20 + 12, j * 20 + 16); //7
|
||||
}
|
||||
else if (current.getNumber() == 7){
|
||||
g.drawLine(i * 20 + 8, j * 20 + 4, i * 20 + 12, j * 20 + 4); //2
|
||||
g.drawLine(i * 20 + 13, j * 20 + 5, i * 20 + 13, j * 20 + 9); //3
|
||||
g.drawLine(i * 20 + 13, j * 20 + 11, i * 20 + 13, j * 20 + 15); //6
|
||||
}
|
||||
else if (current.getNumber() == 8){
|
||||
g.drawLine(i * 20 + 7, j * 20 + 5, i * 20 + 7, j * 20 + 9); //1
|
||||
g.drawLine(i * 20 + 8, j * 20 + 4, i * 20 + 12, j * 20 + 4); //2
|
||||
g.drawLine(i * 20 + 13, j * 20 + 5, i * 20 + 13, j * 20 + 9); //3
|
||||
g.drawLine(i * 20 + 8, j * 20 + 10, i * 20 + 12, j * 20 + 10); //4
|
||||
g.drawLine(i * 20 + 7, j * 20 + 11, i * 20 + 7, j * 20 + 15); //5
|
||||
g.drawLine(i * 20 + 13, j * 20 + 11, i * 20 + 13, j * 20 + 15); //6
|
||||
g.drawLine(i * 20 + 8, j * 20 + 16, i * 20 + 12, j * 20 + 16); //7
|
||||
}
|
||||
}
|
||||
g.setColor(Color.BLACK);
|
||||
g.drawRect(i * 20, j * 20, i * 20 + 20, j * 20 + 20);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public Board(Minesweeper m){ //Creating a new game so we can draw a board for it
|
||||
mine = m;
|
||||
cells = mine.getCells();
|
||||
|
||||
addMouseListener(new Actions(mine));
|
||||
|
||||
setPreferredSize(new Dimension(mine.getx() * 20, mine.gety() * 20));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
//--------------------------------- END of Board.java ---------------------------------
|
||||
|
||||
//--------------------------------- START of Actions.java ---------------------------------
|
||||
|
||||
import java.awt.event.ActionEvent;
|
||||
import java.awt.event.ActionListener;
|
||||
import java.awt.event.MouseEvent;
|
||||
import java.awt.event.MouseListener;
|
||||
|
||||
public class Actions implements ActionListener, MouseListener{
|
||||
|
||||
private Minesweeper mine;
|
||||
|
||||
//These following four are not important. We simply tell the machine to pay no mind when mouse is pressed, released, etc.
|
||||
//If these weren't here the computer would freak out and panic over what to do because no instructions were given.
|
||||
|
||||
public void mouseEntered(MouseEvent e){
|
||||
|
||||
}
|
||||
|
||||
public void mouseExited(MouseEvent e){
|
||||
|
||||
}
|
||||
|
||||
public void mousePressed(MouseEvent e){
|
||||
|
||||
}
|
||||
|
||||
public void mouseReleased(MouseEvent e){
|
||||
|
||||
}
|
||||
|
||||
//Where the fun begins
|
||||
|
||||
public Actions(Minesweeper m){
|
||||
|
||||
mine = m;
|
||||
}
|
||||
|
||||
//Any time an action is performed, redraw the board and keep it up to date.
|
||||
public void actionPerformed(ActionEvent e){
|
||||
|
||||
mine.reset();
|
||||
|
||||
mine.refresh();
|
||||
}
|
||||
|
||||
//Mouse clicky clicky
|
||||
public void mouseClicked(MouseEvent e){
|
||||
|
||||
//Left click - opens mine
|
||||
if (e.getButton() == 1)
|
||||
{
|
||||
int x = e.getX() / 20;
|
||||
int y = e.getY() / 20;
|
||||
|
||||
mine.select(x, y);
|
||||
}
|
||||
|
||||
//Right click - marks mine
|
||||
if (e.getButton() == 3)
|
||||
{
|
||||
int x = e.getX() / 20;
|
||||
int y = e.getY() / 20;
|
||||
|
||||
mine.mark(x, y);
|
||||
}
|
||||
|
||||
|
||||
mine.refresh(); //Gotta keep it fresh
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
//--------------------------------- END of Actions.java ---------------------------------
|
||||
|
||||
//--------------------------------- START of Minesweeper.java ---------------------------------
|
||||
|
||||
import java.awt.BorderLayout;
|
||||
import java.util.Random;
|
||||
import javax.swing.JButton;
|
||||
import javax.swing.JFrame;
|
||||
import javax.swing.JOptionPane;
|
||||
|
||||
public class Minesweeper extends JFrame
|
||||
{
|
||||
private static final long serialVersionUID = 1L;
|
||||
private int width, height;
|
||||
private int difficulty;
|
||||
private Cell[][] cells;
|
||||
private Board board;
|
||||
private JButton reset;
|
||||
private boolean finished;
|
||||
|
||||
|
||||
public void select(int x, int y){ //Select a mine on the board
|
||||
|
||||
if (cells[x][y].isFlagged()) //Is the mine flagged?
|
||||
return;
|
||||
|
||||
cells[x][y].reveal(); //Reveal the cell
|
||||
resetMarks(); //Reset marks and redraw board
|
||||
refresh();
|
||||
|
||||
if (cells[x][y].isMine()) //If a mine is revealed, you lose.
|
||||
{
|
||||
lose();
|
||||
}
|
||||
else if (won()) //If the game has been won, you win. Hahahahahaha.
|
||||
{
|
||||
win();
|
||||
}
|
||||
}
|
||||
|
||||
private void setNumbers(){ //For each cell, count the amount of mines in surrounding squares.
|
||||
//Because the board is modeled as a 2D array, this is relatively easy - simply check the surrounding addresses for mines.
|
||||
//If there's a mine, add to the count.
|
||||
|
||||
for (int i = 0; i < width; i++){
|
||||
|
||||
for (int j = 0; j < height; j++){
|
||||
|
||||
int count = 0;
|
||||
|
||||
if (i > 0 && j > 0 && cells[i - 1][j - 1].isMine())
|
||||
count++;
|
||||
|
||||
if (j > 0 && cells[i][j - 1].isMine())
|
||||
count++;
|
||||
|
||||
if (i < width - 1 && j > 0 && cells[i + 1][j - 1].isMine())
|
||||
count++;
|
||||
|
||||
if (i > 0 && cells[i - 1][j].isMine())
|
||||
count++;
|
||||
|
||||
if (i < width - 1 && cells[i + 1][j].isMine())
|
||||
count++;
|
||||
|
||||
if (i > 0 && j < height - 1 && cells[i - 1][j + 1].isMine())
|
||||
count++;
|
||||
|
||||
if (j < height - 1 && cells[i] [j + 1].isMine())
|
||||
count++;
|
||||
|
||||
if (i < width - 1 && j < height - 1 && cells[i + 1][j + 1].isMine())
|
||||
count++;
|
||||
|
||||
cells[i][j].setNumber(count);
|
||||
|
||||
|
||||
if (cells[i][j].isMine())
|
||||
cells[i][j].setNumber(-1);
|
||||
|
||||
|
||||
if (cells[i][j].getNumber() == 0)
|
||||
cells[i][j].reveal();
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
for (int i = 0; i < width; i++){ //This is for the beginning of the game.
|
||||
//If the 8 cells around certain cell have no mines beside them (hence getNumber() = 0) beside them, this cell is empty.
|
||||
|
||||
for (int j = 0; j < height; j++){
|
||||
|
||||
if (i > 0 && j > 0 && cells[i - 1][j - 1].getNumber() == 0)
|
||||
cells[i][j].reveal();
|
||||
|
||||
if (j > 0 && cells[i][j - 1].getNumber() == 0)
|
||||
cells[i][j].reveal();
|
||||
|
||||
if (i < width - 1 && j > 0 && cells[i + 1][j - 1].getNumber() == 0)
|
||||
cells[i][j].reveal();
|
||||
|
||||
if (i > 0 && cells[i - 1][j].getNumber() == 0)
|
||||
cells[i][j].reveal();
|
||||
|
||||
if (i < width - 1 && cells[i + 1][j].getNumber() == 0)
|
||||
cells[i][j].reveal();
|
||||
|
||||
if (i > 0 && j < height - 1 && cells[i - 1][j + 1].getNumber() == 0)
|
||||
cells[i][j].reveal();
|
||||
|
||||
if (j < height - 1 && cells[i][j + 1].getNumber() == 0)
|
||||
cells[i][j].reveal();
|
||||
|
||||
if (i < width - 1 && j < height - 1 && cells[i + 1][j + 1].getNumber() == 0)
|
||||
cells[i][j].reveal();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void mark(int x, int y){ //When a player wants to flag/unflag a cell
|
||||
|
||||
if (cells[x][y].isFlagged()) //If the cell is already flagged, unflag it.
|
||||
cells[x][y].unflag();
|
||||
|
||||
else if (cells[x][y].isCovered()) //If the cell has nothing on it and is covered, flag it.
|
||||
cells[x][y].flag();
|
||||
|
||||
resetMarks();
|
||||
}
|
||||
|
||||
private void resetMarks(){ //If a cell is not covered, then it cannot be flagged.
|
||||
//Every time a player does something, this should be called to redraw the board.
|
||||
|
||||
for (int i = 0; i < width; i++){
|
||||
for (int j = 0; j < height; j++){
|
||||
|
||||
if (!cells[i][j].isCovered())
|
||||
cells[i][j].unflag();
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void reset(){ //Reset the positions of the mines on the board
|
||||
//If randomly generated number from 0 to 100 is less than the chosen difficulty, a mine is placed down.
|
||||
//This will somewhat accurately reflect the mine percentage that the user requested - the more cells, the more accurate.
|
||||
|
||||
Random random = new Random();
|
||||
finished = false;
|
||||
|
||||
for (int i = 0; i < width; i++) {
|
||||
for (int j = 0; j < height; j++) {
|
||||
|
||||
Cell c = new Cell();
|
||||
cells[i][j] = c;
|
||||
int r = random.nextInt(100);
|
||||
|
||||
if (r < difficulty)
|
||||
{
|
||||
cells[i][j].setMine(); //Put down a mine.
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
setNumbers(); //Set the numbers after mines have been put down.
|
||||
}
|
||||
|
||||
public int getx() {
|
||||
return width;
|
||||
}
|
||||
|
||||
public int gety() {
|
||||
return height;
|
||||
}
|
||||
|
||||
public Cell[][] getCells() {
|
||||
return cells;
|
||||
}
|
||||
|
||||
|
||||
public void refresh(){ //Refresh the drawing of the board
|
||||
board.repaint();
|
||||
}
|
||||
|
||||
private void win(){ //Winning a game
|
||||
finished = true;
|
||||
for (int i = 0; i < width; i++)
|
||||
{
|
||||
for (int j = 0; j < height; j++)
|
||||
{
|
||||
cells[i][j].reveal();//Reveal all cells
|
||||
|
||||
if (!cells[i][j].isMine())
|
||||
cells[i][j].unflag();
|
||||
}
|
||||
}
|
||||
|
||||
refresh();
|
||||
JOptionPane.showMessageDialog(null, "Congratulations! You won!"); //Tell the user they won. They probably deserve to know.
|
||||
reset();
|
||||
}
|
||||
|
||||
private void lose(){ //Losing a game...basically the same as above.
|
||||
finished = true;
|
||||
for (int i = 0; i < width; i++)
|
||||
{
|
||||
for (int j = 0; j < height; j++)
|
||||
{
|
||||
if (!cells[i][j].isCovered())
|
||||
cells[i][j].unflag();
|
||||
|
||||
cells[i][j].reveal();
|
||||
}
|
||||
}
|
||||
refresh();
|
||||
JOptionPane.showMessageDialog(null, "GAME OVER."); //Dialogue window letting the user know that they lost.
|
||||
reset();
|
||||
}
|
||||
|
||||
|
||||
private boolean won(){ //Check if the game has been won
|
||||
for (int i = 0; i < width; i++){
|
||||
for (int j = 0; j < height; j++){
|
||||
|
||||
if (cells[i][j].isCovered() && !cells[i][j].isMine())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
public boolean isFinished(){ //Extremely self-explanatory.
|
||||
return finished;
|
||||
}
|
||||
|
||||
public Minesweeper(int x, int y, int d){
|
||||
|
||||
width = x; //Width of the board
|
||||
height = y; //Height of the board
|
||||
difficulty = d; //Percentage of mines in the board
|
||||
cells = new Cell[width][height];
|
||||
|
||||
reset(); //Set mines on the board
|
||||
|
||||
board = new Board(this); //Create new board
|
||||
reset = new JButton("Reset"); //Reset button
|
||||
|
||||
add(board, BorderLayout.CENTER); //Put board in the center
|
||||
add(reset, BorderLayout.SOUTH); //IT'S A BUTTON! AND IT WORKS! VERY COOL
|
||||
|
||||
reset.addActionListener(new Actions(this)); //ActionListener to watch for mouse actions
|
||||
|
||||
//GUI window settings
|
||||
setTitle("Minesweeper");
|
||||
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
|
||||
setResizable(false);
|
||||
pack();
|
||||
setVisible(true);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
//--------------------------------- END of Minesweeper.java ---------------------------------
|
||||
118
Task/Minesweeper-game/Julia/minesweeper-game-1.julia
Normal file
118
Task/Minesweeper-game/Julia/minesweeper-game-1.julia
Normal file
|
|
@ -0,0 +1,118 @@
|
|||
# Minesweeper:
|
||||
|
||||
mutable struct Field
|
||||
size::Tuple{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::String)
|
||||
input = split(chomp(str), " ")
|
||||
mode = input[1]
|
||||
println(str)
|
||||
coords = length(input) > 1 ? (parse(Int,input[2]), parse(Int,input[3])) : (0, 0)
|
||||
return mode, coords
|
||||
end
|
||||
|
||||
function eval_input(f::Field, str::String)
|
||||
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(parse.(Int,s)...)
|
||||
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()
|
||||
83
Task/Minesweeper-game/Julia/minesweeper-game-2.julia
Normal file
83
Task/Minesweeper-game/Julia/minesweeper-game-2.julia
Normal 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.
|
||||
114
Task/Minesweeper-game/Locomotive-Basic/minesweeper-game.basic
Normal file
114
Task/Minesweeper-game/Locomotive-Basic/minesweeper-game.basic
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
|
||||
267
Task/Minesweeper-game/M2000-Interpreter/minesweeper-game.m2000
Normal file
267
Task/Minesweeper-game/M2000-Interpreter/minesweeper-game.m2000
Normal file
|
|
@ -0,0 +1,267 @@
|
|||
Module Minesweeper {
|
||||
Font "Arial Black"
|
||||
Bold 0
|
||||
Form 60,40
|
||||
Refresh 1000
|
||||
Def com$, com_label$
|
||||
Def x, b_row, b_col, where, top_where
|
||||
Def rows=4, columns=6, swap_first%
|
||||
Def boolean skiptest, end_game, cheat
|
||||
Dim Board$(0 to rows+1, 0 to columns+1)="? "
|
||||
Def mines%, i%, j%, used%, acc%, n%, m%
|
||||
mines%=max.data(random(int(columns*rows*.1),int(columns*rows*.2)-1), 1)
|
||||
For i%=1 to rows:For j%=1 to columns
|
||||
Board$(i%,j%)=". "
|
||||
Next j%:Next i%
|
||||
used%=mines%
|
||||
While used%
|
||||
used%--
|
||||
Do
|
||||
i%=random(1,rows)
|
||||
j%=random(1, columns)
|
||||
Until right$(Board$(i%,j%),1)=" "
|
||||
Board$(i%,j%)=".*"
|
||||
End While
|
||||
used%=rows*columns-mines%
|
||||
\\ remove rem so to never loose from first open
|
||||
Rem :
|
||||
swap_first%=used%
|
||||
\\ when mines%=0 or used%=0 then player win
|
||||
Report {Minesweeper - rosettacode task
|
||||
Commands:
|
||||
- ? 1 2 flag/unflag 1 2
|
||||
- 1 2 open 1 2
|
||||
- q to quit
|
||||
You can pass multiple commands in a line, but q erase all before execute
|
||||
}
|
||||
top_where=Row
|
||||
While not End_Game {GameLoop()}
|
||||
End
|
||||
Sub PrintBoard()
|
||||
Cls, top_where
|
||||
Print
|
||||
Print " X ";
|
||||
For j%=1 to columns {
|
||||
Print format$("{0::-3} ", j%);
|
||||
}
|
||||
Print
|
||||
For i%=1 to rows {
|
||||
Print format$(" {0::-3} ", i%);
|
||||
For j%=1 to columns {
|
||||
Print " ";Left$(Board$(i%,j%),1);" ";
|
||||
\\ rem above and unrem follow line to display mines
|
||||
Rem: Print " ";Board$(i%,j%)+" ";
|
||||
}
|
||||
Print
|
||||
}
|
||||
End Sub
|
||||
Sub PrintMines()
|
||||
Cls, top_where
|
||||
Print
|
||||
Print " X ";
|
||||
For j%=1 to columns {
|
||||
Print format$("{0::-3} ", j%);
|
||||
}
|
||||
Print
|
||||
For i%=1 to rows {
|
||||
Print format$(" {0::-3} ", i%);
|
||||
For j%=1 to columns {
|
||||
Print " ";Right$(Board$(i%,j%),1);" ";
|
||||
}
|
||||
Print
|
||||
}
|
||||
End Sub
|
||||
Sub GameLoop()
|
||||
Local com$, loopagain as boolean
|
||||
PrintBoard()
|
||||
InputCommand()
|
||||
do
|
||||
loopagain=true
|
||||
while not empty
|
||||
\\ process game command
|
||||
Read com$
|
||||
if com$="q " Then
|
||||
Print "Quit" : end_game=True : exit
|
||||
Else.if com$="o " Then
|
||||
OpenCell()
|
||||
Else.if com$="n " Then
|
||||
OpenCell2()
|
||||
Else.if com$="? " Then
|
||||
SwapCell()
|
||||
Else.if com$="c " Then
|
||||
Exit Sub
|
||||
End if
|
||||
End While
|
||||
If mines%=0 or used%=0 then
|
||||
PrintBoard(): Print "Player Win": end_game=True: Exit Sub
|
||||
End if
|
||||
If mines%=-1 then
|
||||
if swap_first%=used% then
|
||||
mines%=rows*columns-used%
|
||||
Local n%, m%
|
||||
While mines%
|
||||
Let n%=random(1,rows), m%=random(1, columns)
|
||||
If Board$(n%, m%)=". " then Board$(n%, m%)=".*" : mines%=0
|
||||
End While
|
||||
Board$(i%, j%)=". "
|
||||
mines%=rows*columns-used%
|
||||
swap_first%=-100
|
||||
Push i%, j%, "o "
|
||||
loopagain=false
|
||||
else
|
||||
PrintMines(): Print "Player Loose": end_game=True : Exit Sub
|
||||
end if
|
||||
End If
|
||||
Until loopagain
|
||||
Flush
|
||||
Refresh if(End_Game->10,1000)
|
||||
End Sub
|
||||
Sub InputCommand()
|
||||
where=row
|
||||
While com$=""
|
||||
cls, where
|
||||
Print "x x | ? x x | q >";
|
||||
Refresh 10
|
||||
Try {
|
||||
Input "", com$
|
||||
}
|
||||
End While
|
||||
x=1
|
||||
Flush
|
||||
While com$<>""
|
||||
com_label$=""
|
||||
ParseCommand()
|
||||
if len(com_label$)<>2 then
|
||||
com$="" : Print com_label$ : Flush
|
||||
Refresh 10
|
||||
push key$ : drop
|
||||
else
|
||||
Data com_label$, b_col, b_row
|
||||
End if
|
||||
End While
|
||||
Refresh 1000
|
||||
End Sub
|
||||
Sub ParseCommand()
|
||||
com_label$="o "
|
||||
skiptest=true
|
||||
ReadColumn()
|
||||
if len(com_label$)<>2 then
|
||||
com$=""
|
||||
Else.if x=-1 then
|
||||
com_label$=lcase$(Left$(com$,1))+" "
|
||||
com$=mid$(com$, 2)
|
||||
x=1
|
||||
if len(com_label$)<>2 then
|
||||
com_label$="no command found"
|
||||
else.if com_label$="? " then
|
||||
ReadColumn()
|
||||
if x>-1 then ReadRow()
|
||||
else.if com_label$="c " then
|
||||
cheat=true
|
||||
else.if com_label$="q " then
|
||||
flush
|
||||
com$=""
|
||||
else
|
||||
com_label$="Use q or ? for commands"
|
||||
com$=""
|
||||
End if
|
||||
else
|
||||
ReadRow()
|
||||
if x>-1 then com_label$="o "
|
||||
End if
|
||||
End Sub
|
||||
Sub ReadRow()
|
||||
com$=mid$(com$,x)
|
||||
b_row=val(com$, "??", x)
|
||||
if x=-1 then
|
||||
com_label$="Need a row"
|
||||
else.if b_row<1 or b_row>rows then
|
||||
com_label$="Need a row from 1 to "+str$(rows)
|
||||
x=-1
|
||||
else
|
||||
com$=mid$(com$,x+1)
|
||||
x=1
|
||||
End if
|
||||
End Sub
|
||||
Sub ReadColumn()
|
||||
com$=mid$(com$,x)
|
||||
b_col=val(com$, "??", x)
|
||||
if x=-1 then
|
||||
if not skiptest then com_label$="Need a column"
|
||||
else.if b_col<1 or b_col>columns then
|
||||
com_label$="Need a column from 1 to"+str$(columns)
|
||||
else
|
||||
com$=mid$(com$,x+1)
|
||||
x=1
|
||||
End if
|
||||
skiptest=false
|
||||
End Sub
|
||||
Sub SwapCell()
|
||||
Read j%, i%
|
||||
If left$(Board$(i%,j%),1)="?" then
|
||||
Board$(i%,j%) ="."+Right$(Board$(i%,j%),1)
|
||||
If cheat Then if Right$(Board$(i%,j%),1)="*" then mines%++
|
||||
Else.If left$(Board$(i%,j%),1)="." then
|
||||
Board$(i%,j%) ="?"+Right$(Board$(i%,j%),1)
|
||||
If cheat Then if Right$(Board$(i%,j%),1)="*" then mines%--
|
||||
End if
|
||||
End Sub
|
||||
Sub OpenCell()
|
||||
Read j%, i%
|
||||
If left$(Board$(i%,j%),1)="." then {
|
||||
if Right$(Board$(i%,j%),1)="*" then mines%=-1 : flush : exit
|
||||
acc%=0
|
||||
used%--
|
||||
Local n%, m%
|
||||
For n%=i%-1 to i%+1 {
|
||||
For m%=j%-1 to j%+1 {
|
||||
If Right$(Board$(n%,m%),1)="*" then acc%++
|
||||
}
|
||||
}
|
||||
For n%=i%-1 to i%+1 {
|
||||
For m%=j%-1 to j%+1 {
|
||||
if not (n%=i% and m%=j%) then
|
||||
if not Right$(Board$(n%,m%),1)="*" then
|
||||
If left$(Board$(n%,m%),1)="." then
|
||||
Push n%, m%, "n " ' reverse to stack
|
||||
Rem : Print stack.size : Refresh
|
||||
End If
|
||||
End If
|
||||
End If
|
||||
}
|
||||
}
|
||||
Board$(i%,j%)=if$(acc%=0->" ",str$(acc%, "# "))
|
||||
}
|
||||
End Sub
|
||||
Sub OpenCell2()
|
||||
Read J%, i%
|
||||
If left$(Board$(i%,j%),1)="." then {
|
||||
if Right$(Board$(i%,j%),1)="*" then exit
|
||||
acc%=0
|
||||
used%--
|
||||
For n%=i%-1 to i%+1 {
|
||||
For m%=j%-1 to j%+1 {
|
||||
If Right$(Board$(n%,m%),1)="*" then acc%++
|
||||
}
|
||||
}
|
||||
\\ if cell has no mines around then we check all
|
||||
if acc%=0 then
|
||||
Local n%, m%
|
||||
For n%=i%-1 to i%+1
|
||||
For m%=j%-1 to j%+1
|
||||
if not (n%=i% and m%=j%) then
|
||||
if not Right$(Board$(n%,m%),1)="*" then
|
||||
If left$(Board$(n%,m%),1)="." then
|
||||
Push n%, m%, "o " ' reverse to stack
|
||||
Rem : Print stack.size : Refresh
|
||||
End If
|
||||
End If
|
||||
End If
|
||||
Next m%
|
||||
Next n%
|
||||
End If
|
||||
Board$(i%,j%)=if$(acc%=0->" ",str$(acc%, "# "))
|
||||
}
|
||||
End Sub
|
||||
}
|
||||
Minesweeper
|
||||
1
Task/Minesweeper-game/MATLAB/minesweeper-game-1.m
Normal file
1
Task/Minesweeper-game/MATLAB/minesweeper-game-1.m
Normal file
|
|
@ -0,0 +1 @@
|
|||
xpbombs
|
||||
243
Task/Minesweeper-game/MATLAB/minesweeper-game-2.m
Normal file
243
Task/Minesweeper-game/MATLAB/minesweeper-game-2.m
Normal 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
|
||||
46
Task/Minesweeper-game/Mathematica/minesweeper-game.math
Normal file
46
Task/Minesweeper-game/Mathematica/minesweeper-game.math
Normal file
|
|
@ -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]}]
|
||||
188
Task/Minesweeper-game/Nim/minesweeper-game.nim
Normal file
188
Task/Minesweeper-game/Nim/minesweeper-game.nim
Normal file
|
|
@ -0,0 +1,188 @@
|
|||
import random, sequtils, strformat, strscans, strutils
|
||||
|
||||
const LMargin = 4
|
||||
|
||||
type
|
||||
|
||||
Cell = object
|
||||
isMine: bool
|
||||
display: char
|
||||
|
||||
Grid = seq[seq[Cell]]
|
||||
|
||||
Game = object
|
||||
grid: Grid
|
||||
mineCount: Natural
|
||||
minesMarked: Natural
|
||||
isOver: bool
|
||||
|
||||
|
||||
proc initGame(m, n: Positive): Game =
|
||||
result.grid = newSeqWith(m, repeat(Cell(isMine: false, display: '.'), n))
|
||||
let min = (float(m * n) * 0.1).toInt
|
||||
let max = (float(m * n) * 0.2).toInt
|
||||
result.mineCount = min + rand(max - min)
|
||||
var rm = result.mineCount
|
||||
while rm > 0:
|
||||
let x = rand(m - 1)
|
||||
let y = rand(n - 1)
|
||||
if not result.grid[x][y].isMine:
|
||||
dec rm
|
||||
result.grid[x][y].isMine = true
|
||||
result.minesMarked = 0
|
||||
|
||||
|
||||
template `[]`(grid: Grid; x, y: int): Cell = grid[x][y]
|
||||
|
||||
|
||||
iterator cells(grid: var Grid): var Cell =
|
||||
for y in 0..grid[0].high:
|
||||
for x in 0..grid.high:
|
||||
yield grid[x, y]
|
||||
|
||||
|
||||
proc display(game: Game; endOfGame: bool) =
|
||||
if not endOfGame:
|
||||
echo &"Grid has {game.mineCount} mine(s), {game.minesMarked} mine(s) marked."
|
||||
let margin = repeat(' ', LMargin)
|
||||
echo margin, toSeq(1..game.grid.len).join()
|
||||
echo margin, repeat('-', game.grid.len)
|
||||
for y in 0..game.grid[0].high:
|
||||
stdout.write align($(y + 1), LMargin)
|
||||
for x in 0..game.grid.high:
|
||||
stdout.write game.grid[x][y].display
|
||||
stdout.write '\n'
|
||||
|
||||
|
||||
proc terminate(game: var Game; msg: string) =
|
||||
game.isOver = true
|
||||
echo msg
|
||||
var answer = ""
|
||||
while answer notin ["y", "n"]:
|
||||
stdout.write "Another game (y/n)? "
|
||||
answer = try: stdin.readLine().toLowerAscii
|
||||
except EOFError: "n"
|
||||
if answer == "y":
|
||||
game = initGame(6, 4)
|
||||
game.display(false)
|
||||
|
||||
|
||||
proc resign(game: var Game) =
|
||||
var found = 0
|
||||
for cell in game.grid.cells:
|
||||
if cell.isMine:
|
||||
if cell.display == '?':
|
||||
cell.display = 'Y'
|
||||
inc found
|
||||
elif cell.display == 'x':
|
||||
cell.display = 'N'
|
||||
game.display(true)
|
||||
let msg = &"You found {found} out of {game.mineCount} mine(s)."
|
||||
game.terminate(msg)
|
||||
|
||||
|
||||
proc markCell(game: var Game; x, y: int) =
|
||||
if game.grid[x, y].display == '?':
|
||||
dec game.minesMarked
|
||||
game.grid[x, y].display = '.'
|
||||
elif game.grid[x, y].display == '.':
|
||||
inc game.minesMarked
|
||||
game.grid[x, y].display = '?'
|
||||
|
||||
|
||||
proc countAdjMines(game: Game; x, y: Natural): int =
|
||||
for j in (y - 1)..(y + 1):
|
||||
if j in 0..game.grid[0].high:
|
||||
for i in (x - 1)..(x + 1):
|
||||
if i in 0..game.grid.high:
|
||||
if game.grid[i, j].isMine:
|
||||
inc result
|
||||
|
||||
|
||||
proc clearCell(game: var Game; x, y: int): bool =
|
||||
|
||||
if x in 0..game.grid.high and y in 0..game.grid[0].high:
|
||||
if game.grid[x, y].display == '.':
|
||||
|
||||
if game.grid[x, y].isMine:
|
||||
game.grid[x][y].display = 'x'
|
||||
echo "Kaboom! You lost!"
|
||||
return false
|
||||
|
||||
let count = game.countAdjMines(x, y)
|
||||
if count > 0:
|
||||
game.grid[x][y].display = chr(ord('0') + count)
|
||||
else:
|
||||
game.grid[x][y].display = ' '
|
||||
for dx in -1..1:
|
||||
for dy in -1..1:
|
||||
if dx != 0 or dy != 0:
|
||||
discard game.clearCell(x + dx, y + dy)
|
||||
|
||||
result = true
|
||||
|
||||
|
||||
proc testForWin(game: var Game): bool =
|
||||
if game.minesMarked != game.mineCount: return false
|
||||
for cell in game.grid.cells:
|
||||
if cell.display == '.': return false
|
||||
result = true
|
||||
echo "You won!"
|
||||
|
||||
|
||||
proc splitAction(game: Game; action: string): tuple[x, y: int; ok: bool] =
|
||||
var command: string
|
||||
if not action.scanf("$w $s$i $s$i$s$.", command, result.x, result.y): return
|
||||
if command.len != 1: return
|
||||
if result.x notin 1..game.grid.len or result.y notin 1..game.grid.len: return
|
||||
result.ok = true
|
||||
|
||||
|
||||
proc printUsage() =
|
||||
echo "h or ? - this help,"
|
||||
echo "c x y - clear cell (x,y),"
|
||||
echo "m x y - marks (toggles) cell (x,y),"
|
||||
echo "n - start a new game,"
|
||||
echo "q - quit/resign the game,"
|
||||
echo "where 'x' is the (horizontal) column number and 'y' is the (vertical) row number.\n"
|
||||
|
||||
|
||||
randomize()
|
||||
printUsage()
|
||||
var game = initGame(6, 4)
|
||||
game.display(false)
|
||||
|
||||
while not game.isOver:
|
||||
stdout.write "\n>"
|
||||
let action = try: stdin.readLine().toLowerAscii
|
||||
except EOFError: "q"
|
||||
case action[0]
|
||||
|
||||
of 'h', '?':
|
||||
printUsage()
|
||||
|
||||
of 'n':
|
||||
game = initGame(6, 4)
|
||||
game.display(false)
|
||||
|
||||
of 'c':
|
||||
let (x, y, ok) = game.splitAction(action)
|
||||
if not ok: continue
|
||||
if game.clearCell(x - 1, y - 1):
|
||||
game.display(false)
|
||||
if game.testForwin(): game.resign()
|
||||
else:
|
||||
game.resign()
|
||||
|
||||
of 'm':
|
||||
let (x, y, ok) = game.splitAction(action)
|
||||
if not ok: continue
|
||||
game.markCell(x - 1, y - 1)
|
||||
game.display(false)
|
||||
if game.testForWin(): game.resign()
|
||||
|
||||
of 'q':
|
||||
game.resign()
|
||||
|
||||
else:
|
||||
continue
|
||||
145
Task/Minesweeper-game/OCaml/minesweeper-game.ocaml
Normal file
145
Task/Minesweeper-game/OCaml/minesweeper-game.ocaml
Normal file
|
|
@ -0,0 +1,145 @@
|
|||
exception Lost
|
||||
exception Won
|
||||
|
||||
let put_mines g m n mines_number =
|
||||
let rec aux i =
|
||||
if i < mines_number then
|
||||
begin
|
||||
let x = Random.int n
|
||||
and y = Random.int m in
|
||||
if g.(y).(x)
|
||||
then aux i
|
||||
else begin
|
||||
g.(y).(x) <- true;
|
||||
aux (succ i)
|
||||
end
|
||||
end
|
||||
in
|
||||
aux 0
|
||||
|
||||
let print_abscissas n =
|
||||
print_string "\n "; for x = 1 to n do print_int (x mod 10) done;
|
||||
print_string "\n "; for x = 1 to n do print_char '|' done;
|
||||
print_newline()
|
||||
|
||||
let print_display d n =
|
||||
print_abscissas n;
|
||||
Array.iteri (fun y line ->
|
||||
Printf.printf " %2d - " (y+1); (* print ordinates *)
|
||||
Array.iter print_char line;
|
||||
print_newline()
|
||||
) d;
|
||||
print_newline()
|
||||
|
||||
let reveal d g n =
|
||||
print_abscissas n;
|
||||
Array.iteri (fun y line ->
|
||||
Printf.printf " %2d - " (y+1); (* print ordinates *)
|
||||
Array.iteri (fun x c ->
|
||||
print_char (
|
||||
match c, g.(y).(x) with
|
||||
| '0'..'9', _ -> c
|
||||
| '.', true -> 'x'
|
||||
| '?', true -> 'X'
|
||||
| '?', false -> 'N'
|
||||
| '.', false -> '.'
|
||||
| _ -> c)
|
||||
) line;
|
||||
print_newline()
|
||||
) d;
|
||||
print_newline()
|
||||
|
||||
let toggle_mark d x y =
|
||||
match d.(y).(x) with
|
||||
| '.' -> d.(y).(x) <- '?'
|
||||
| '?' -> d.(y).(x) <- '.'
|
||||
| _ -> ()
|
||||
|
||||
let rec feedback g d x y =
|
||||
if d.(y).(x) = '.' then
|
||||
begin
|
||||
let n = ref 0 in (* the number of mines around *)
|
||||
for i = (pred y) to (succ y) do
|
||||
for j = (pred x) to (succ x) do
|
||||
try if g.(i).(j) then incr n
|
||||
with _ -> ()
|
||||
done;
|
||||
done;
|
||||
match !n with
|
||||
| 0 ->
|
||||
(* recursive feedback when no mines are around *)
|
||||
d.(y).(x) <- ' ';
|
||||
for j = (pred y) to (succ y) do
|
||||
for i = (pred x) to (succ x) do
|
||||
try feedback g d i j
|
||||
with _ -> ()
|
||||
done
|
||||
done
|
||||
| _ ->
|
||||
d.(y).(x) <- (string_of_int !n).[0]
|
||||
end
|
||||
|
||||
let clear_cell g d x y =
|
||||
if g.(y).(x)
|
||||
then (d.(y).(x) <- '!'; raise Lost)
|
||||
else feedback g d x y
|
||||
|
||||
let rec user_input g d =
|
||||
try
|
||||
let s = read_line() in
|
||||
match Scanf.sscanf s "%c %d %d" (fun c x y -> c,x,y) with
|
||||
| 'm', x, y -> toggle_mark d (x-1) (y-1)
|
||||
| 'c', x, y -> clear_cell g d (x-1) (y-1)
|
||||
| _ -> raise Exit
|
||||
with Exit | Scanf.Scan_failure _
|
||||
| Invalid_argument "index out of bounds" ->
|
||||
print_string "# wrong input, try again\n> ";
|
||||
user_input g d
|
||||
|
||||
let check_won g d =
|
||||
let won = ref true in
|
||||
Array.iteri (fun y line ->
|
||||
Array.iteri (fun x c ->
|
||||
match c, g.(y).(x) with
|
||||
| '.', _ -> won := false
|
||||
| '?', false -> won := false
|
||||
| _ -> ()
|
||||
) line
|
||||
) d;
|
||||
if !won then raise Won
|
||||
|
||||
let minesweeper n m percent =
|
||||
let round x = int_of_float (floor (x +. 0.5)) in
|
||||
let mines_number = round ((float (n * m)) *. percent) in
|
||||
(* the ground containing the mines *)
|
||||
let g = Array.make_matrix m n false in
|
||||
put_mines g m n mines_number;
|
||||
Printf.printf "# You have to find %d mines\n" mines_number;
|
||||
(* what's displayed to the user *)
|
||||
let d = Array.make_matrix m n '.' in
|
||||
try
|
||||
while true do
|
||||
print_display d n;
|
||||
print_string "> ";
|
||||
user_input g d;
|
||||
check_won g d;
|
||||
done
|
||||
with
|
||||
| Lost ->
|
||||
print_endline "# You lost!";
|
||||
reveal d g n
|
||||
| Won ->
|
||||
print_endline "# You won!";
|
||||
reveal d g n
|
||||
|
||||
let () =
|
||||
Random.self_init();
|
||||
let ios, fos = int_of_string, float_of_string in
|
||||
let n, m, percent =
|
||||
try ios Sys.argv.(1), ios Sys.argv.(2), fos Sys.argv.(3)
|
||||
with _ ->
|
||||
try ios Sys.argv.(1), ios Sys.argv.(2), 0.2
|
||||
with _ -> (6, 4, 0.2)
|
||||
in
|
||||
minesweeper n m percent;
|
||||
;;
|
||||
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 :).';
|
||||
}
|
||||
166
Task/Minesweeper-game/Perl/minesweeper-game.pl
Normal file
166
Task/Minesweeper-game/Perl/minesweeper-game.pl
Normal file
|
|
@ -0,0 +1,166 @@
|
|||
#!/usr/bin/perl
|
||||
use warnings;
|
||||
use strict;
|
||||
|
||||
{ package Local::Field;
|
||||
|
||||
use constant {
|
||||
REAL => 0,
|
||||
SHOW => 1,
|
||||
COUNT => 2,
|
||||
};
|
||||
|
||||
sub new {
|
||||
my ($class, $width, $height, $percent) = @_;
|
||||
my $field;
|
||||
for my $x (1 .. $width) {
|
||||
for my $y (1 .. $height) {
|
||||
$field->[$x - 1][$y - 1][REAL] = ' ';
|
||||
$field->[$x - 1][$y - 1][SHOW] = '.';
|
||||
}
|
||||
}
|
||||
for (1 .. $percent / 100 * $width * $height) {
|
||||
my ($x, $y) = map int rand $_, $width, $height;
|
||||
redo if 'm' eq $field->[$x][$y][REAL];
|
||||
$field->[$x][$y][REAL] = 'm';
|
||||
for my $i ($x - 1 .. $x + 1) {
|
||||
for my $j ($y - 1 .. $y + 1) {
|
||||
$field->[$i][$j][COUNT]++
|
||||
if $i >= 0 and $j >= 0
|
||||
and $i <= $#$field and $j <= $#{ $field->[0] };
|
||||
}
|
||||
}
|
||||
}
|
||||
bless $field, $class;
|
||||
}
|
||||
|
||||
|
||||
sub show {
|
||||
my ($self) = @_;
|
||||
print "\n ";
|
||||
printf '%2d ', $_ + 1 for 0 .. $#$self;
|
||||
print "\n";
|
||||
|
||||
for my $row (0 .. $#{ $self->[0] }) {
|
||||
printf '%2d ', 1 + $row;
|
||||
for my $column (0 .. $#$self) {
|
||||
print $self->[$column][$row][SHOW], ' ';
|
||||
}
|
||||
print "\n";
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
sub mark {
|
||||
my ($self, $x, $y) = @_;
|
||||
$_-- for $x, $y;
|
||||
|
||||
if ('.' eq $self->[$x][$y][SHOW]) {
|
||||
$self->[$x][$y][SHOW] = '?';
|
||||
|
||||
} elsif ('?' eq $self->[$x][$y][SHOW]) {
|
||||
$self->[$x][$y][SHOW] = '.';
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
sub end {
|
||||
my $self = shift;
|
||||
for my $y (0 .. $#{ $self->[0] }) {
|
||||
for my $x (0 .. $#$self) {
|
||||
$self->[$x][$y][SHOW] = '!' if '.' eq $self->[$x][$y][SHOW]
|
||||
and 'm' eq $self->[$x][$y][REAL];
|
||||
$self->[$x][$y][SHOW] = 'x' if '?' eq $self->[$x][$y][SHOW]
|
||||
and 'm' ne $self->[$x][$y][REAL];
|
||||
}
|
||||
}
|
||||
$self->show;
|
||||
exit;
|
||||
}
|
||||
|
||||
sub _declassify {
|
||||
my ($self, $x, $y) = @_;
|
||||
return if '.' ne $self->[$x][$y][SHOW];
|
||||
if (' ' eq $self->[$x][$y][REAL] and '.' eq $self->[$x][$y][SHOW]) {
|
||||
$self->[$x][$y][SHOW] = $self->[$x][$y][COUNT] || ' ';
|
||||
}
|
||||
return if ' ' ne $self->[$x][$y][SHOW];
|
||||
|
||||
for my $i ($x - 1 .. $x + 1) {
|
||||
next if $i < 0 or $i > $#$self;
|
||||
for my $j ($y - 1 .. $y + 1) {
|
||||
next if $j < 0 or $j > $#{ $self->[0] };
|
||||
no warnings 'recursion';
|
||||
$self->_declassify($i, $j);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
sub clear {
|
||||
my ($self, $x, $y) = @_;
|
||||
$_-- for $x, $y;
|
||||
return unless '.' eq $self->[$x][$y][SHOW];
|
||||
|
||||
print "You lost.\n" and $self->end if 'm' eq $self->[$x][$y][REAL];
|
||||
|
||||
$self->_declassify($x, $y);
|
||||
}
|
||||
|
||||
|
||||
sub remain {
|
||||
my $self = shift;
|
||||
my $unclear = 0;
|
||||
for my $column (@$self) {
|
||||
for my $cell (@$column) {
|
||||
$unclear++ if '.' eq $cell->[SHOW];
|
||||
}
|
||||
}
|
||||
return $unclear;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
sub help {
|
||||
print << '__HELP__';
|
||||
Commands:
|
||||
h ... help
|
||||
q ... quit
|
||||
m X Y ... mark/unmark X Y
|
||||
c X Y ... clear X Y
|
||||
__HELP__
|
||||
}
|
||||
|
||||
|
||||
my ($width, $height, $percent) = @ARGV;
|
||||
$width ||= 6;
|
||||
$height ||= 4;
|
||||
$percent ||= 15;
|
||||
|
||||
my $field = 'Local::Field'->new($width, $height, $percent);
|
||||
|
||||
my $help = 1;
|
||||
while (1) {
|
||||
$field->show;
|
||||
help() if $help;
|
||||
$help = 0;
|
||||
my $remain = $field->remain;
|
||||
last if 0 == $remain;
|
||||
print "Cells remaining: $remain.\n";
|
||||
my $command = <STDIN>;
|
||||
exit if $command =~ /^q/i;
|
||||
|
||||
if ($command =~ /^m.*?([0-9]+).*?([0-9]+)/i) {
|
||||
$field->mark($1, $2);
|
||||
|
||||
} elsif ($command =~ /^c.*?([0-9]+).*?([0-9]+)/i) {
|
||||
$field->clear($1, $2);
|
||||
|
||||
} elsif ($command =~ /^h/i) {
|
||||
$help = 1;
|
||||
|
||||
} else {
|
||||
print "Huh?\n";
|
||||
}
|
||||
}
|
||||
print "You won!\n";
|
||||
172
Task/Minesweeper-game/Phix/minesweeper-game.phix
Normal file
172
Task/Minesweeper-game/Phix/minesweeper-game.phix
Normal file
|
|
@ -0,0 +1,172 @@
|
|||
constant help = """
|
||||
|
||||
Minesweeper
|
||||
===========
|
||||
|
||||
Enter eg A1 to open a cell, FA1 to flag a cell, Q to quit.
|
||||
|
||||
The board is initially displayed with 10-20% of cells mined, as follows:
|
||||
|
||||
. - an unknown cell (unopened and not flagged)
|
||||
_ - an empty cell, with no surrounding mines
|
||||
1..8 - an empty cell, with some nearby mines
|
||||
? - a cell you have flagged as a mine
|
||||
(a flag can only be cleared by opening)
|
||||
|
||||
On completion:
|
||||
X - the mine you detonated (if any)
|
||||
* - a mine which was not flagged
|
||||
+ - a mine which was correctly flagged
|
||||
"""
|
||||
|
||||
string board = """
|
||||
|
||||
123456
|
||||
A......
|
||||
B......
|
||||
C......
|
||||
D......
|
||||
"""
|
||||
|
||||
sequence data = repeat(repeat(0,6),4)
|
||||
-- 0: empty, no nearby mines
|
||||
-- 1-8: empty, with surrounding mines
|
||||
-- 9: a mine
|
||||
|
||||
-- data[row][col] maps to board[row*8+4+col], lets quickly verify that:
|
||||
if find('.',board)!=13 then ?9/0 end if
|
||||
if rfind('.',board)!=42 then ?9/0 end if
|
||||
-- (above may trigger if copy/paste/dowload etc messed up whitespace)
|
||||
|
||||
constant prompt = "\nEnter eg A1 to open a cell, FA1 to flag a cell, Q to quit, or ? for help:"
|
||||
|
||||
integer mines = round((6*4)*0.10+rand(6*4)*0.10), -- 10-20%
|
||||
cleared = 0,
|
||||
flagged = 0,
|
||||
flag = false,
|
||||
row = 0,
|
||||
col
|
||||
|
||||
procedure plant_mines()
|
||||
for i=1 to mines do
|
||||
while 1 do
|
||||
row = rand(4)
|
||||
col = rand(6)
|
||||
if data[row][col]!=9 then
|
||||
data[row][col] = 9
|
||||
for rx=row-1 to row+1 do
|
||||
if rx>=1 and rx<=4 then
|
||||
for cx=col-1 to col+1 do
|
||||
if cx>=1 and cx<=6 then
|
||||
if data[rx][cx]!=9 then
|
||||
data[rx][cx] += 1
|
||||
end if
|
||||
end if
|
||||
end for
|
||||
end if
|
||||
end for
|
||||
exit
|
||||
end if
|
||||
end while
|
||||
end for
|
||||
printf(1,"%d mines planted\n",mines)
|
||||
row = 0
|
||||
end procedure
|
||||
|
||||
procedure clear_cell(integer row, col, drc)
|
||||
board[row*8+4+col] = iff(drc?drc+'0':' ')
|
||||
cleared += 1
|
||||
if drc=0 then
|
||||
for rx=row-1 to row+1 do
|
||||
if rx>=1 and rx<=4 then
|
||||
for cx=col-1 to col+1 do
|
||||
if cx>=1 and cx<=6 then
|
||||
drc = data[rx][cx]
|
||||
if drc!=9
|
||||
and board[rx*8+4+cx]='.' then
|
||||
clear_cell(rx,cx,drc)
|
||||
end if
|
||||
end if
|
||||
end for
|
||||
end if
|
||||
end for
|
||||
end if
|
||||
end procedure
|
||||
|
||||
function make_move()
|
||||
integer brc = row*8+4+col
|
||||
if flag then
|
||||
if board[brc]='.' then
|
||||
board[brc] = '?'
|
||||
flagged += 1
|
||||
end if
|
||||
else
|
||||
integer drc = data[row][col]
|
||||
if drc=9 then
|
||||
board[brc] = 'X'
|
||||
puts(1,"\n\n***BOOM!***")
|
||||
return true
|
||||
end if
|
||||
if find(board[brc],".?") then
|
||||
clear_cell(row,col,drc)
|
||||
end if
|
||||
end if
|
||||
row = 0
|
||||
flag = false
|
||||
-- nb: flagged and cleared may be wrong following incorrect input.
|
||||
if flagged=mines
|
||||
or cleared=6*4-mines then
|
||||
puts(1,"\n\n***You Win!***")
|
||||
return true
|
||||
end if
|
||||
return false -- no "BOOM" yet!
|
||||
end function
|
||||
|
||||
procedure disclose()
|
||||
for row=1 to 4 do
|
||||
for col=1 to 6 do
|
||||
if data[row][col]=9 then
|
||||
integer bdx = row*8+4+col,
|
||||
bch = board[bdx]
|
||||
if bch='.' then
|
||||
bch = '*'
|
||||
elsif bch='?' then
|
||||
bch = '+'
|
||||
elsif bch!='X' then
|
||||
?9/0
|
||||
end if
|
||||
board[bdx] = bch
|
||||
end if
|
||||
end for
|
||||
end for
|
||||
end procedure
|
||||
|
||||
plant_mines()
|
||||
while 1 do
|
||||
if not flag and row=0 then
|
||||
puts(1,board)
|
||||
puts(1,prompt)
|
||||
end if
|
||||
integer ch = upper(getc(0))
|
||||
puts(1,ch)
|
||||
if ch='Q' then exit end if
|
||||
if ch='?' then
|
||||
puts(1,help)
|
||||
elsif ch='F' then
|
||||
flag = true
|
||||
elsif ch>='A'
|
||||
and ch<='D' then
|
||||
row = ch-'@'
|
||||
elsif ch>='1'
|
||||
and ch<='6' then
|
||||
col = ch-'0'
|
||||
if make_move() then exit end if
|
||||
else
|
||||
printf(1,"\n\nunrecognised:%c\n\n",ch)
|
||||
flag = false
|
||||
row = 0
|
||||
end if
|
||||
end while
|
||||
disclose()
|
||||
puts(1,board&"game over\n\n")
|
||||
{} = wait_key()
|
||||
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!!" ) )
|
||||
207
Task/Minesweeper-game/Prolog/minesweeper-game.pro
Normal file
207
Task/Minesweeper-game/Prolog/minesweeper-game.pro
Normal file
|
|
@ -0,0 +1,207 @@
|
|||
:- use_module(library(clpfd)).
|
||||
|
||||
% Play - run the minesweeper game with a specified width and height
|
||||
play(W,H) :-
|
||||
format('
|
||||
Welcome to prolog minesweeper!
|
||||
: o X Y exposes a cell of the grid
|
||||
: m X Y marks bombs
|
||||
|
||||
Any else to quit.
|
||||
'),
|
||||
|
||||
make_grid(W, H, Grid),
|
||||
!,
|
||||
play(Grid),
|
||||
!.
|
||||
|
||||
play(Grid) :- % win condition is true
|
||||
map_grid(won, Grid),
|
||||
map_grid(print_cell, Grid),
|
||||
writeln('you won!').
|
||||
|
||||
play(Grid) :- % lose condition is true
|
||||
\+ map_grid(still_playing, Grid),
|
||||
map_grid(print_cell, Grid),
|
||||
writeln('you hit a bomb!').
|
||||
|
||||
play(Grid) :- % stil playing
|
||||
map_grid(print_cell, Grid),
|
||||
parse_input(Op, X, Y),
|
||||
do_op(Op, p(X,Y), Grid, Grid2),
|
||||
!,
|
||||
play(Grid2).
|
||||
|
||||
/* Create a new Grid
|
||||
*
|
||||
* The grid is created initially as a flat list, and after everything
|
||||
* has been populated is converted into a 2 dimensional array.
|
||||
*/
|
||||
make_grid(W, H, grid(W,H,MappedCells)) :-
|
||||
% create a flat list
|
||||
Len is W * H,
|
||||
length(Cells, Len),
|
||||
|
||||
% create a list of bombs that is 20% of the grid list
|
||||
NBombs is W * H / 5,
|
||||
floor(NBombs, NBint),
|
||||
format('There are ~w bombs on the grid~n', NBint),
|
||||
length(AllBombs, NBint),
|
||||
maplist(=('?'), AllBombs),
|
||||
% add the bombs to the start of the grid list
|
||||
map_bombs_to_cells(Cells, AllBombs, NewC),
|
||||
|
||||
% randomise and convert to a 2D array
|
||||
random_permutation(NewC, RCells),
|
||||
convert_col(RCells, W, H, CreatedCells),
|
||||
|
||||
% populate the hidden part of the grid with number of bombs next to each cell
|
||||
map_grid(adj_bomb(grid(W,H,CreatedCells)), grid(W,H,CreatedCells), grid(W,H,MappedCells)).
|
||||
|
||||
% puts the bombs at the start of the flat list before shuffling.
|
||||
map_bombs_to_cells(C, [], C).
|
||||
map_bombs_to_cells([_|Ct], [B|Bt], [B|R]) :- map_bombs_to_cells(Ct, Bt, R).
|
||||
|
||||
convert_row(T, 0, [], T).
|
||||
convert_row([H|T], W, [H|R], Rem) :-
|
||||
dif(W, 0), succ(W1, W),
|
||||
convert_row(T, W1, R, Rem).
|
||||
|
||||
convert_col([], _, 0, []).
|
||||
convert_col(C, W, H, [Row|MoreCells]) :- dif(H, 0), succ(H1, H),
|
||||
convert_row(C, W, Row, Rem),
|
||||
convert_col(Rem, W, H1, MoreCells).
|
||||
|
||||
% determine the number of bombs next to a cell (use mapgrid)
|
||||
adj_bomb(_, _, _, C, cell('.',C)) :- C =@= '?'.
|
||||
adj_bomb(Grid, p(X,Y), D, Cell, cell('.',NBombs)) :-
|
||||
dif(Cell, '?'),
|
||||
findall(p(Ax,Ay), (
|
||||
adj(p(X,Y), D, p(Ax,Ay)),
|
||||
indomain(Ax), indomain(Ay),
|
||||
grid_val_xy(Grid, p(Ax,Ay), Val),
|
||||
Val =@= '?'
|
||||
), Bombs),
|
||||
length(Bombs, NBombs).
|
||||
|
||||
% Print the grid (use mapgrid)
|
||||
print_cell(p(X,_), dim(X,_), cell(C,A), cell(C,A)) :- format("~w~n", C).
|
||||
print_cell(p(X,_), dim(W,_), cell(C,A), cell(C,A)) :- dif(X,W), format("~w ", C).
|
||||
|
||||
% determine if we have lost yet or not (use mapgrid).
|
||||
still_playing(_,_,cell(A,_),_) :- A \= '*'.
|
||||
|
||||
% determine if we have won yet or not (use mapgrid).
|
||||
won(_,_,cell(N,N),_) :- integer(N).
|
||||
won(_,_,cell('?','?'),_).
|
||||
|
||||
% Operate on all cells in a grid, this is a meta predicate that is
|
||||
% applied several times throughout the code
|
||||
map_grid(Goal, G) :- map_grid(Goal, G, G).
|
||||
|
||||
map_grid(Goal, grid(W,H,Cells), grid(W,H,OutCells)) :-
|
||||
map_grid_col(Cells, 1, dim(W,H), Goal, OutCells).
|
||||
|
||||
map_grid_col([], _, _, _, []).
|
||||
map_grid_col([H|T], Y, D, Goal, [NRow|NCol]) :-
|
||||
map_grid_row(H, p(1, Y), D, Goal, NRow),
|
||||
succ(Y, Y1),
|
||||
map_grid_col(T, Y1, D, Goal, NCol).
|
||||
|
||||
map_grid_row([], _, _, _, []).
|
||||
map_grid_row([H|T], p(X, Y), D, Goal, [Cell|R]) :-
|
||||
call(Goal, p(X, Y), D, H, Cell),
|
||||
succ(X, X1),
|
||||
map_grid_row(T, p(X1, Y), D, Goal, R).
|
||||
|
||||
% Get a value from the grid by X Y
|
||||
grid_val_xy(grid(_,_,Cells), p(X,Y), Val) :-
|
||||
nth1(Y, Cells, Row),
|
||||
nth1(X, Row, Val).
|
||||
|
||||
% Set a value on the grid by X Y
|
||||
grid_set_xy(grid(W,H,Cells), p(X,Y), Val, grid(W,H,NewCells)) :- grid_set_col(Cells, X, Y, Val, NewCells).
|
||||
grid_set_col([H|T], X, 1, Val, [Row|T]) :- grid_set_row(H, X, Val, Row).
|
||||
grid_set_col([H|T], X, Y, Val, [H|New]) :- dif(Y, 0), succ(Y1, Y), grid_set_col(T, X, Y1, Val, New).
|
||||
grid_set_row([_|T], 1, Val, [Val|T]).
|
||||
grid_set_row([H|T], X, Val, [H|New]) :- dif(X, 0), succ(X1, X), grid_set_row(T, X1, Val, New).
|
||||
|
||||
% All coordinates adjacent to an x,y position
|
||||
adj(p(X,Y), dim(W,H), p(Ax,Ay)) :-
|
||||
|
||||
dif(p(X,Y),p(Ax,Ay)),
|
||||
|
||||
% adjacent X
|
||||
Ax in 1..W,
|
||||
Xmin #= X-1, Xmax #= X+1,
|
||||
Ax in Xmin..Xmax,
|
||||
|
||||
% adjacent Y
|
||||
Ay in 1..H,
|
||||
Ymin #= Y-1, Ymax #= Y+1,
|
||||
Ay in Ymin..Ymax.
|
||||
|
||||
% get user operation from input
|
||||
parse_input(Op, X, Y) :-
|
||||
read_line_to_codes(user_input, In),
|
||||
maplist(char_code, InChars, In),
|
||||
phrase(mine_op(Op, X, Y), InChars, []).
|
||||
|
||||
mine_op(mark, X, Y) --> [m], [' '], coords(X, Y).
|
||||
mine_op(open, X, Y) --> [o], [' '], coords(X, Y).
|
||||
coords(Xi, Yi) --> number_(X), { number_chars(Xi, X) }, [' '], number_(Y), { number_chars(Yi, Y) }.
|
||||
|
||||
number_([D|T]) --> digit(D), number_(T).
|
||||
number_([D]) --> digit(D).
|
||||
digit(D) --> [D], { char_type(D, digit) }.
|
||||
|
||||
|
||||
% Do mark operation
|
||||
do_op(mark, P, G, Ng) :-
|
||||
grid_val_xy(G, P, cell(_,A)),
|
||||
grid_set_xy(G, P, cell('?',A), Ng).
|
||||
|
||||
% Do open operation, opening a bomb
|
||||
do_op(open, P, G, Ng) :-
|
||||
grid_val_xy(G, P, cell(_,'?')),
|
||||
grid_set_xy(G, P, cell('*','?'), Ng).
|
||||
|
||||
% Do open operation, not a bomb
|
||||
do_op(open, P, G, Ng) :-
|
||||
grid_val_xy(G, P, cell(_,A)),
|
||||
dif(A, '?'),
|
||||
grid_set_xy(G, P, cell(A,A), Ng1),
|
||||
expose_grid(P, Ng1, Ng).
|
||||
|
||||
% expose the grid by checking all the adjacent cells and operating
|
||||
% appropriately
|
||||
expose_grid(p(X,Y), grid(W,H,Cells), Ng2) :-
|
||||
findall(p(Ax,Ay), (
|
||||
adj(p(X,Y), dim(W,H), p(Ax,Ay)),
|
||||
indomain(Ax), indomain(Ay)
|
||||
), Coords),
|
||||
expose_grid_(Coords, grid(W,H,Cells), Ng2).
|
||||
|
||||
expose_grid_([], G, G).
|
||||
|
||||
expose_grid_([H|T], G, Ng) :- % this cell has already been exposed, continue
|
||||
grid_val_xy(G, H, cell(A,B)),
|
||||
member(A, [B,'?']),
|
||||
expose_grid_(T, G, Ng).
|
||||
|
||||
expose_grid_([H|T], G, Ng) :- % ignore bombs
|
||||
grid_val_xy(G, H, cell(_,'?')),
|
||||
expose_grid_(T, G, Ng).
|
||||
|
||||
expose_grid_([H|T], G, Ng) :- % is an integer, expose and continue
|
||||
grid_val_xy(G, H, cell(_,N)),
|
||||
integer(N),
|
||||
N #> 0,
|
||||
grid_set_xy(G, H, cell(N,N), Ng1),
|
||||
expose_grid_(T, Ng1, Ng).
|
||||
|
||||
expose_grid_([H|T], G, Ng) :- % is a space, recurse
|
||||
grid_val_xy(G, H, cell('.',0)),
|
||||
grid_set_xy(G, H, cell(0,0), Ng1),
|
||||
expose_grid(H, Ng1, Ng2),
|
||||
expose_grid_(T, Ng2, Ng).
|
||||
178
Task/Minesweeper-game/PureBasic/minesweeper-game.basic
Normal file
178
Task/Minesweeper-game/PureBasic/minesweeper-game.basic
Normal file
|
|
@ -0,0 +1,178 @@
|
|||
Structure cell
|
||||
isMine.i
|
||||
display.c ;character to displays for cell, one of these {'.', '?', ' ', #)
|
||||
EndStructure
|
||||
|
||||
Global Dim grid.cell(0,0)
|
||||
Global mineCount, minesMarked, isGameOver
|
||||
|
||||
Procedure makeGrid(n, m)
|
||||
Protected rm, x, y
|
||||
Dim grid.cell(n - 1, m - 1)
|
||||
mineCount = n * m * (Random(4) + 2) / 10
|
||||
If mineCount < 0: mineCount = 1: EndIf
|
||||
|
||||
For x = 0 To n - 1
|
||||
For y = 0 To m - 1
|
||||
grid(x, y)\display = '.'
|
||||
Next
|
||||
Next
|
||||
|
||||
rm = mineCount
|
||||
While rm
|
||||
x = Random(n - 1)
|
||||
y = Random(m - 1)
|
||||
If Not grid(x, y)\isMine
|
||||
rm - 1: grid(x, y)\isMine = #True
|
||||
EndIf
|
||||
Wend
|
||||
minesMarked = 0
|
||||
isGameOver = #False
|
||||
EndProcedure
|
||||
|
||||
Procedure displayGrid(isEndOfGame = #False)
|
||||
#lMargin = 4
|
||||
Protected x, y, display.s
|
||||
If Not isEndOfGame
|
||||
PrintN("Grid has " + Str(mineCount) + " mines, " + Str(minesMarked) + " mines marked.")
|
||||
EndIf
|
||||
PrintN(Space(#lMargin + 1) + ReplaceString(Space(ArraySize(grid(), 1) + 1), " ", "-"))
|
||||
For y = 0 To ArraySize(grid(), 2)
|
||||
Print(RSet(Str(y + 1), #lMargin, " ") + ":")
|
||||
For x = 0 To ArraySize(grid(), 1)
|
||||
Print(Chr(grid(x,y)\display))
|
||||
Next
|
||||
PrintN("")
|
||||
Next
|
||||
EndProcedure
|
||||
|
||||
Procedure endGame(msg.s)
|
||||
Protected ans.s
|
||||
isGameOver = #True
|
||||
PrintN(msg): Print("Another game (y/n)?"): ans = Input()
|
||||
If LCase(Left(Trim(ans),1)) = "y"
|
||||
makeGrid(6, 4)
|
||||
EndIf
|
||||
EndProcedure
|
||||
|
||||
Procedure resign()
|
||||
Protected x, y, found
|
||||
For y = 0 To ArraySize(grid(), 2)
|
||||
For x = 0 To ArraySize(grid(), 1)
|
||||
With grid(x,y)
|
||||
If \isMine
|
||||
If \display = '?'
|
||||
\display = 'Y'
|
||||
found + 1
|
||||
ElseIf \display <> 'x'
|
||||
\display = 'N'
|
||||
EndIf
|
||||
EndIf
|
||||
EndWith
|
||||
Next
|
||||
Next
|
||||
displayGrid(#True)
|
||||
endGame("You found " + Str(found) + " out of " + Str(mineCount) + " mines.")
|
||||
EndProcedure
|
||||
|
||||
Procedure usage()
|
||||
PrintN("h or ? - this help,")
|
||||
PrintN("c x y - clear cell (x,y),")
|
||||
PrintN("m x y - marks (toggles) cell (x,y),")
|
||||
PrintN("n - start a new game,")
|
||||
PrintN("q - quit/resign the game,")
|
||||
PrintN("where x is the (horizontal) column number and y is the (vertical) row number." + #CRLF$)
|
||||
EndProcedure
|
||||
|
||||
Procedure markCell(x, y)
|
||||
If grid(x, y)\display = '?'
|
||||
minesMarked - 1: grid(x, y)\display = '.'
|
||||
ElseIf grid(x, y)\display = '.'
|
||||
minesMarked + 1: grid(x, y)\display = '?'
|
||||
EndIf
|
||||
EndProcedure
|
||||
|
||||
Procedure countAdjMines(x, y)
|
||||
Protected count, i, j
|
||||
For j = y - 1 To y + 1
|
||||
If j >= 0 And j <= ArraySize(grid(), 2)
|
||||
For i = x - 1 To x + 1
|
||||
If i >= 0 And i <= ArraySize(grid(), 1)
|
||||
If grid(i, j)\isMine
|
||||
count + 1
|
||||
EndIf
|
||||
EndIf
|
||||
Next
|
||||
EndIf
|
||||
Next
|
||||
|
||||
ProcedureReturn count
|
||||
EndProcedure
|
||||
|
||||
Procedure clearCell(x, y)
|
||||
Protected count
|
||||
If x >= 0 And x <= ArraySize(grid(), 1) And y >= 0 And y <= ArraySize(grid(), 2)
|
||||
If grid(x, y)\display = '.'
|
||||
If Not grid(x,y)\isMine
|
||||
count = countAdjMines(x, y)
|
||||
If count
|
||||
grid(x, y)\display = Asc(Str(count))
|
||||
Else
|
||||
grid(x, y)\display = ' '
|
||||
clearCell(x + 1, y)
|
||||
clearCell(x + 1, y + 1)
|
||||
clearCell(x , y + 1)
|
||||
clearCell(x - 1, y + 1)
|
||||
clearCell(x - 1, y)
|
||||
clearCell(x - 1, y - 1)
|
||||
clearCell(x , y - 1)
|
||||
clearCell(x + 1, y - 1)
|
||||
EndIf
|
||||
Else
|
||||
grid(x, y)\display = 'x'
|
||||
PrintN("Kaboom! You lost!")
|
||||
resign()
|
||||
EndIf
|
||||
EndIf
|
||||
EndIf
|
||||
EndProcedure
|
||||
|
||||
Procedure testforwin()
|
||||
Protected x, y, isCleared
|
||||
If minesMarked = mineCount
|
||||
isCleared = #True
|
||||
For x = 0 To ArraySize(grid(), 1)
|
||||
For y = 0 To ArraySize(grid(), 2)
|
||||
If grid(x, y)\display = '.': isCleared = #False: EndIf
|
||||
Next
|
||||
Next
|
||||
EndIf
|
||||
If isCleared: endGame("You won!"): EndIf
|
||||
EndProcedure
|
||||
|
||||
If OpenConsole()
|
||||
Define action.s
|
||||
usage()
|
||||
makeGrid(6, 4): displayGrid()
|
||||
Repeat
|
||||
PrintN(""): Print(">"): action = Input()
|
||||
Select Asc(LCase(Left(action, 1)))
|
||||
Case 'h', '?'
|
||||
usage()
|
||||
Case 'n'
|
||||
makeGrid(6, 4): displayGrid()
|
||||
Case 'c'
|
||||
clearCell(Val(StringField(action, 2, " ")) - 1, Val(StringField(action, 3, " ")) - 1)
|
||||
If Not isGameOver: displayGrid(): Else: testforwin(): EndIf
|
||||
Case 'm'
|
||||
markCell(Val(StringField(action, 2, " ")) - 1, Val(StringField(action, 3, " ")) - 1)
|
||||
displayGrid()
|
||||
testforwin()
|
||||
Case 'q'
|
||||
resign()
|
||||
EndSelect
|
||||
Until isGameOver
|
||||
|
||||
Print(#CRLF$ + #CRLF$ + "Press ENTER to exit"): Input()
|
||||
CloseConsole()
|
||||
EndIf
|
||||
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)) )
|
||||
144
Task/Minesweeper-game/Racket/minesweeper-game.rkt
Normal file
144
Task/Minesweeper-game/Racket/minesweeper-game.rkt
Normal file
|
|
@ -0,0 +1,144 @@
|
|||
#lang racket
|
||||
(require math/array)
|
||||
;board uses arrays directly, but maintaining an abstraction is nice
|
||||
(define (board-ref b row col) (array-ref b (vector row col)))
|
||||
(define (board-rows b) (vector-ref (array-shape b) 0))
|
||||
(define (board-cols b) (vector-ref (array-shape b) 1))
|
||||
(define (on-board? b row col)
|
||||
(and (<= 0 row (sub1 (board-rows b)))
|
||||
(<= 0 col (sub1 (board-cols b)))))
|
||||
(define (board->lists b) (array->list* b))
|
||||
;run on adjacent board positions
|
||||
(define-syntax (for-adj stx)
|
||||
(syntax-case stx ()
|
||||
[(_ b (r row) (c col) diag? body ...)
|
||||
(with-syntax ([is (if (syntax->datum #'diag?) #''(0 0 1 1 1 -1 -1 -1) #''(0 0 1 -1))]
|
||||
[js (if (syntax->datum #'diag?) #''(1 -1 0 -1 1 0 -1 1) #''(1 -1 0 0))])
|
||||
#'(for ([i is] [j js])
|
||||
(let ([r (+ row i)]
|
||||
[c (+ col j)])
|
||||
(when (on-board? b r c)
|
||||
body ...))))]))
|
||||
;mark is either hidden, assume-mine, or clear
|
||||
;n is int equal to # adj mines or -1 for mine
|
||||
(struct pos ([mark #:mutable] n) #:transparent)
|
||||
(define (mine? p) (= (pos-n p) -1))
|
||||
(define (mine-count b) (apply + (array->list (array-map (λ (p) (if (mine? p) 1 0)) b))))
|
||||
;hidden0? is needed because only spaces with no mines in them and no mines adjacent
|
||||
;to them are cleared recursively
|
||||
(define (hidden0? p)
|
||||
(and (symbol=? (pos-mark p) 'hidden)
|
||||
(zero? (pos-n p))))
|
||||
(define (show-pos p)
|
||||
(match-let ([(pos m n) p])
|
||||
(case m
|
||||
[(hidden) "."]
|
||||
[(assume-mine) "?"]
|
||||
[(clear) (if (zero? n) " " (number->string n))]
|
||||
[else (error "illegal mark" m)])))
|
||||
;put "|" around positions
|
||||
(define (show-board b)
|
||||
(for ([row (board->lists b)])
|
||||
(displayln (format "|~a|" (string-join (map show-pos row) "|")))))
|
||||
|
||||
;winning = every position is either cleared or a hidden mine
|
||||
(define (win? b)
|
||||
(for*/and ([r (range 0 (board-rows b))]
|
||||
[c (range 0 (board-cols b))])
|
||||
(let ([p (board-ref b r c)])
|
||||
(or (symbol=? (pos-mark p) 'clear)
|
||||
(mine? p)))))
|
||||
|
||||
(define (init-board rows cols)
|
||||
(let ([chance (+ (/ (random) 10) 0.1)]
|
||||
;empty board
|
||||
[b (array->mutable-array (build-array (vector rows cols)
|
||||
(λ (x) (pos 'hidden 0))))])
|
||||
;loop whole board
|
||||
(for* ([row (range 0 rows)]
|
||||
[col (range 0 cols)])
|
||||
(when (< (random) chance)
|
||||
;put a mine
|
||||
(array-set! b (vector row col) (pos 'hidden -1))
|
||||
;increment adjacent mine counts unless that adjacent position is a mine
|
||||
(for-adj b (r row) (c col) #t
|
||||
(let ([p (board-ref b r c)])
|
||||
(unless (mine? p)
|
||||
(array-set! b (vector r c) (pos 'hidden (add1 (pos-n p)))))))))
|
||||
b))
|
||||
|
||||
;only clear position if it's not a mine
|
||||
;only continue recursing when it's a hidden0?
|
||||
(define (try-clear! p)
|
||||
(cond [(mine? p) #f]
|
||||
[(hidden0? p) (set-pos-mark! p 'clear) #t]
|
||||
[else (set-pos-mark! p 'clear) #f]))
|
||||
|
||||
;the following player move functions return boolean where #f = lose, #t = still going
|
||||
;assuming can never directly lose ((void) == #t from the set!)
|
||||
;make sure to not allow overwriting an already cleared position
|
||||
(define (toggle-assume! b row col)
|
||||
(let ([p (board-ref b row col)])
|
||||
(set-pos-mark! p (case (pos-mark p)
|
||||
[(assume-mine) 'hidden]
|
||||
[(hidden) 'assume-mine]
|
||||
[(clear) 'clear]
|
||||
[else (error "invalid mark" (pos-mark p))]))))
|
||||
|
||||
;clearing loses when the chosen position is a mine
|
||||
;void = #t as far as if works, so no need to return #t
|
||||
(define (clear! b row col)
|
||||
(let ([p (board-ref b row col)])
|
||||
(and (not (mine? p))
|
||||
;not a mine, so recursively check adjacents, and maintain list of visited positions
|
||||
;to avoid infinite loops
|
||||
(let ([seen '()])
|
||||
;clear the chosen position first, only continuing if it's a 0
|
||||
(when (try-clear! p)
|
||||
(let clear-adj ([row row] [col col])
|
||||
(for-adj b (r row) (c col) #f
|
||||
;make sure its not seen
|
||||
(when (and (not (member (list r c) seen))
|
||||
(try-clear! (board-ref b r c)))
|
||||
;it was cleared, so loop after saving this position as being seen
|
||||
(set! seen (cons (list r c) seen))
|
||||
(clear-adj r c)))))))))
|
||||
|
||||
(define assume-string "a")
|
||||
(define clear-string "c")
|
||||
;validates input...returns either #f for an error or the move to execute
|
||||
(define (parse-and-create-move! b s)
|
||||
(match (string-split s)
|
||||
[(list type row col)
|
||||
(let ([row (string->number row)]
|
||||
[col (string->number col)])
|
||||
(and (number? row)
|
||||
(number? col)
|
||||
(let ([row (sub1 row)]
|
||||
[col (sub1 col)])
|
||||
(and (on-board? b row col)
|
||||
(or (and (string=? type assume-string) (λ () (toggle-assume! b row col)))
|
||||
(and (string=? type clear-string) (λ () (clear! b row col))))))))]
|
||||
[else #f]))
|
||||
(define (run)
|
||||
(displayln (string-append "--- Enter one of:\n"
|
||||
(format "--- \"~a <row> <col>\" to clear at (row,col), or~n" clear-string)
|
||||
(format (string-append "--- \"~a <row> <col>\" to flag a possible mine "
|
||||
"(or clear a flag) at (row,col).~n")
|
||||
assume-string)))
|
||||
(let ([b (init-board 4 6)])
|
||||
(displayln (format "There are ~a mines.~n" (mine-count b)))
|
||||
(let run ()
|
||||
(show-board b)
|
||||
(display "enter move: ")
|
||||
;parse either failed or gave the procedure to execute
|
||||
(let ([proc? (parse-and-create-move! b (read-line))])
|
||||
;was the parse successful?
|
||||
(if proc?
|
||||
;then run it
|
||||
(if (proc?)
|
||||
;didn't lose, so either we won or we're not done
|
||||
(if (win? b) (displayln "CLEAR!") (run))
|
||||
(displayln "BOOM!"))
|
||||
;parse failed
|
||||
(run))))))
|
||||
111
Task/Minesweeper-game/Raku/minesweeper-game.raku
Normal file
111
Task/Minesweeper-game/Raku/minesweeper-game.raku
Normal file
|
|
@ -0,0 +1,111 @@
|
|||
enum Tile-Type <Empty Mine>;
|
||||
|
||||
class Tile {
|
||||
has Tile-Type $.type;
|
||||
has $.face is rw;
|
||||
method Str { with $!face { ~$!face } else { '.' } }
|
||||
}
|
||||
|
||||
class Field {
|
||||
has @.grid;
|
||||
has Int $.width;
|
||||
has Int $.height;
|
||||
has Int $.mine-spots;
|
||||
has Int $.empty-spots;
|
||||
|
||||
method new (Int $height, Int $width, Rat $mines-ratio=0.1) {
|
||||
|
||||
my $mine-spots = round $width*$height*$mines-ratio;
|
||||
my $empty-spots = $width*$height - $mine-spots;
|
||||
|
||||
my @grid;
|
||||
for ^$height X ^$width -> ($y, $x) {
|
||||
@grid[$y][$x] = Tile.new(type => Empty);
|
||||
}
|
||||
for (^$height).pick($mine-spots) Z (^$width).pick($mine-spots) -> ($y, $x) {
|
||||
@grid[$y][$x] = Tile.new( type => Mine);
|
||||
}
|
||||
self.bless(:$height, :$width, :@grid, :$mine-spots, :$empty-spots);
|
||||
}
|
||||
|
||||
method open( $y, $x) {
|
||||
return if @!grid[$y][$x].face.defined;
|
||||
|
||||
self.end-game("KaBoom") if @!grid[$y][$x].type ~~ Mine;
|
||||
|
||||
my @neighbors = gather do
|
||||
take [$y+.[0],$x+.[1]]
|
||||
if 0 <= $y + .[0] < $!height && 0 <= $x + .[1] < $!width
|
||||
for [-1,-1],[+0,-1],[+1,-1],
|
||||
[-1,+0], [+1,+0],
|
||||
[-1,+1],[+0,+1],[+1,+1];
|
||||
|
||||
my $mines = +@neighbors.grep: { @!grid[.[0]][.[1]].type ~~ Mine };
|
||||
|
||||
$!empty-spots--;
|
||||
@!grid[$y][$x].face = $mines || ' ';
|
||||
|
||||
if $mines == 0 {
|
||||
self.open(.[0], .[1]) for @neighbors;
|
||||
}
|
||||
self.end-game("You won") if $!empty-spots == 0;
|
||||
}
|
||||
|
||||
method end-game(Str $msg ) {
|
||||
for ^$!height X ^$!width -> ($y, $x) {
|
||||
@!grid[$y][$x].face = '*' if @!grid[$y][$x].type ~~ Mine
|
||||
}
|
||||
die $msg;
|
||||
}
|
||||
|
||||
method mark ( $y, $x) {
|
||||
if !@!grid[$y][$x].face.defined {
|
||||
@!grid[$y][$x].face = "⚐";
|
||||
$!mine-spots-- if @!grid[$y][$x].type ~~ Mine;
|
||||
}
|
||||
elsif !@!grid[$y][$x].face eq "⚐" {
|
||||
undefine @!grid[$y][$x].face;
|
||||
$!mine-spots++ if @!grid[$y][$x].type ~~ Mine;
|
||||
}
|
||||
self.end-game("You won") if $!mine-spots == 0;
|
||||
}
|
||||
|
||||
constant @digs = |('a'..'z') xx *;
|
||||
|
||||
method Str {
|
||||
[~] flat ' ', @digs[^$!width], "\n",
|
||||
' ┌', '─' xx $!width, "┐\n",
|
||||
join '', do for ^$!height -> $y {
|
||||
$y, '│', @!grid[$y][*], "│\n"; },
|
||||
' └', '─' xx $!width, '┘';
|
||||
}
|
||||
|
||||
method valid ($y, $x) {
|
||||
0 <= $y < $!height && 0 <= $x < $!width
|
||||
}
|
||||
}
|
||||
|
||||
sub a2n($a) { $a.ord > 64 ?? $a.ord % 32 - 1 !! +$a }
|
||||
|
||||
my $f = Field.new(6,10);
|
||||
|
||||
loop {
|
||||
say ~$f;
|
||||
my @w = prompt("[open loc|mark loc|loc]: ").words;
|
||||
last unless @w;
|
||||
unshift @w, 'open' if @w < 2;
|
||||
my ($x,$y) = $0, $1 if @w[1] ~~ /(<alpha>)(<digit>)|$1=<digit>$0=<alpha>/;
|
||||
$x = a2n($x);
|
||||
given @w[0] {
|
||||
when !$f.valid($y,$x) { say "invalid coordinates" }
|
||||
when /^o/ { $f.open($y,$x) }
|
||||
when /^m/ { $f.mark($y,$x) }
|
||||
default { say "invalid cmd" }
|
||||
}
|
||||
CATCH {
|
||||
say "$_: end of game.";
|
||||
last;
|
||||
}
|
||||
}
|
||||
|
||||
say ~$f;
|
||||
165
Task/Minesweeper-game/Ruby/minesweeper-game.rb
Normal file
165
Task/Minesweeper-game/Ruby/minesweeper-game.rb
Normal file
|
|
@ -0,0 +1,165 @@
|
|||
puts <<EOS
|
||||
Minesweeper game.
|
||||
|
||||
There is an n by m grid that has a random number of between 20% to 60%
|
||||
of randomly hidden mines that need to be found.
|
||||
|
||||
Positions in the grid are modified by entering their coordinates
|
||||
where the first coordinate is horizontal in the grid and the second
|
||||
vertical. The top left of the grid is position 1,1; the bottom right is
|
||||
at n,m.
|
||||
|
||||
* The total number of mines to be found is shown at the beginning of the
|
||||
game.
|
||||
* Each mine occupies a single grid point, and its position is initially
|
||||
unknown to the player
|
||||
* The grid is shown as a rectangle of characters between moves.
|
||||
* You are initially shown all grids as obscured, by a single dot '.'
|
||||
* You may mark what you think is the position of a mine which will show
|
||||
as a '?'
|
||||
* You can mark what you think is free space by entering its coordinates.
|
||||
:* If the point is free space then it is cleared, as are any adjacent
|
||||
points that are also free space- this is repeated recursively for
|
||||
subsequent adjacent free points unless that point is marked as a mine
|
||||
or is a mine.
|
||||
::* Points marked as a mine show as a '?'.
|
||||
::* Other free points show as an integer count of the number of adjacent
|
||||
true mines in its immediate neighbourhood, or as a single space ' ' if the
|
||||
free point is not adjacent to any true mines.
|
||||
* Of course you loose if you try to clear space that starts on a mine.
|
||||
* You win when you have correctly identified all mines.
|
||||
|
||||
|
||||
When prompted you may:
|
||||
Toggle where you think a mine is at position x, y:
|
||||
m <x> <y>
|
||||
Clear the grid starting at position x, y (and print the result):
|
||||
c <x> <y>
|
||||
Print the grid so far:
|
||||
p
|
||||
Quit
|
||||
q
|
||||
Resigning will first show the grid with an 'N' for unfound true mines, a
|
||||
'Y' for found true mines and a '?' for where you marked clear space as a
|
||||
mine
|
||||
EOS
|
||||
|
||||
WIDTH, HEIGHT = 6, 4
|
||||
PCT = 0.15
|
||||
NUM_MINES = (WIDTH * HEIGHT * PCT).round
|
||||
|
||||
def create_mines sx, sy
|
||||
arr = Array.new(WIDTH) { Array.new(HEIGHT, false) }
|
||||
NUM_MINES.times do
|
||||
x, y = rand(WIDTH), rand(HEIGHT)
|
||||
# place it if it isn't at (sx, sy) and we haven't already placed a mine
|
||||
redo if arr[x][y] or (x == sx and y == sy)
|
||||
arr[x][y] = true
|
||||
end
|
||||
arr
|
||||
end
|
||||
|
||||
def num_marks
|
||||
$screen.inject(0) { |sum, row| sum + row.count("?") }
|
||||
end
|
||||
|
||||
def show_grid revealed = false
|
||||
if revealed
|
||||
puts $mines.transpose.map { |row| row.map { |cell| cell ? "*" : " " }.join(" ") }
|
||||
else
|
||||
puts "Grid has #{NUM_MINES} mines, #{num_marks} marked."
|
||||
puts $screen.transpose.map{ |row| row.join(" ") }
|
||||
end
|
||||
end
|
||||
|
||||
SURROUND = [-1,0,1].product([-1,0,1]) - [[0,0]] # surround 8
|
||||
def surrounding x, y
|
||||
# apply the passed block to each spot around (x, y)
|
||||
SURROUND.each do |dx, dy|
|
||||
# don't check if we're out of bounds, or at (0,0)
|
||||
yield(x+dx, y+dy) if (0...WIDTH).cover?(x+dx) and (0...HEIGHT).cover?(y+dy)
|
||||
end
|
||||
end
|
||||
|
||||
def clear_space x, y
|
||||
return unless $screen[x][y] == "."
|
||||
# check nearby spaces
|
||||
count = 0
|
||||
surrounding(x, y) { |px, py| count += 1 if $mines[px][py] }
|
||||
if count == 0
|
||||
$screen[x][y] = " "
|
||||
surrounding(x, y) { |px, py| clear_space px, py }
|
||||
else
|
||||
$screen[x][y] = count.to_s
|
||||
end
|
||||
end
|
||||
|
||||
def victory?
|
||||
return false if $mines.nil? # first one, don't need to check
|
||||
return false if num_marks != NUM_MINES
|
||||
mines_left = NUM_MINES
|
||||
WIDTH.times do |x|
|
||||
HEIGHT.times do |y|
|
||||
mines_left -= 1 if $mines[x][y] and $screen[x][y] == "?"
|
||||
end
|
||||
end
|
||||
|
||||
mines_left == 0
|
||||
end
|
||||
|
||||
def check_input x, y
|
||||
x, y = x.to_i - 1, y.to_i - 1
|
||||
[x, y] if (0...WIDTH).cover?(x) and (0...HEIGHT).cover?(y)
|
||||
end
|
||||
|
||||
$mines = nil
|
||||
$screen = Array.new(WIDTH) { Array.new(HEIGHT, ".") }
|
||||
|
||||
puts "Welcome to Minesweeper!"
|
||||
show_grid
|
||||
|
||||
loop do
|
||||
print "> "
|
||||
action = gets.chomp.downcase
|
||||
|
||||
case action
|
||||
when "quit", "exit", "x", "q"
|
||||
puts "Bye!"
|
||||
break
|
||||
when /^m (\d+) (\d+)$/
|
||||
# mark this cell
|
||||
x, y = check_input $1, $2
|
||||
next unless x
|
||||
if $screen[x][y] == "."
|
||||
# mark it
|
||||
$screen[x][y] = "?"
|
||||
if victory?
|
||||
show_grid
|
||||
puts "You win!"
|
||||
break
|
||||
end
|
||||
elsif $screen[x][y] == "?"
|
||||
# unmark it
|
||||
$screen[x][y] = "."
|
||||
end
|
||||
show_grid
|
||||
when /^c (\d+) (\d+)$/
|
||||
x, y = check_input $1, $2
|
||||
next unless x
|
||||
$mines ||= create_mines(x, y)
|
||||
if $mines[x][y]
|
||||
puts "You hit a mine!"
|
||||
show_grid true
|
||||
break
|
||||
else
|
||||
clear_space x, y
|
||||
show_grid
|
||||
if victory?
|
||||
puts "You win!"
|
||||
break
|
||||
end
|
||||
end
|
||||
when "p"
|
||||
show_grid
|
||||
end
|
||||
end
|
||||
316
Task/Minesweeper-game/Rust/minesweeper-game.rust
Normal file
316
Task/Minesweeper-game/Rust/minesweeper-game.rust
Normal file
|
|
@ -0,0 +1,316 @@
|
|||
extern crate rand;
|
||||
|
||||
use std::io;
|
||||
use std::io::Write;
|
||||
|
||||
fn main() {
|
||||
|
||||
use minesweeper::{MineSweeper, GameStatus};
|
||||
|
||||
let mut width = 6;
|
||||
let mut height = 4;
|
||||
let mut mine_perctg = 10;
|
||||
let mut game = MineSweeper::new(width, height, mine_perctg);
|
||||
|
||||
loop {
|
||||
let mut command = String::new();
|
||||
|
||||
println!(
|
||||
"\n\
|
||||
M I N E S W E E P E R\n\
|
||||
\n\
|
||||
Commands: \n\
|
||||
line col - reveal line,col \n\
|
||||
m line col - mark line,col \n\
|
||||
q - quit\n\
|
||||
n - new game\n\
|
||||
n width height perc - new game size and mine percentage\n"
|
||||
);
|
||||
|
||||
game.print();
|
||||
print!("> ");
|
||||
io::stdout().flush().unwrap();
|
||||
while let Ok(_) = io::stdin().read_line(&mut command) {
|
||||
let mut command_ok = false;
|
||||
{
|
||||
let values: Vec<&str> = command.trim().split(' ').collect();
|
||||
if values.len() == 1 {
|
||||
if values[0] == "q" {
|
||||
println!("Goodbye");
|
||||
return;
|
||||
} else if values[0] == "n" {
|
||||
println!("New game");
|
||||
game = MineSweeper::new(width, height, mine_perctg);
|
||||
command_ok = true;
|
||||
}
|
||||
} else if values.len() == 2 {
|
||||
if let (Ok(x), Ok(y)) = (
|
||||
values[0].parse::<usize>(),
|
||||
values[1].parse::<usize>(),
|
||||
)
|
||||
{
|
||||
game.play(x - 1, y - 1);
|
||||
|
||||
match game.game_status {
|
||||
GameStatus::Won => println!("You won!"),
|
||||
GameStatus::Lost => println!("You lost!"),
|
||||
_ => (),
|
||||
}
|
||||
command_ok = true;
|
||||
}
|
||||
} else if values.len() == 3 {
|
||||
if values[0] == "m" {
|
||||
if let (Ok(x), Ok(y)) = (
|
||||
values[1].parse::<usize>(),
|
||||
values[2].parse::<usize>(),
|
||||
)
|
||||
{
|
||||
game.mark(x - 1, y - 1);
|
||||
command_ok = true;
|
||||
}
|
||||
}
|
||||
} else if values.len() == 4 {
|
||||
if values[0] == "n" {
|
||||
if let (Ok(new_width), Ok(new_height), Ok(new_mines_perctg)) =
|
||||
(
|
||||
values[1].parse::<usize>(),
|
||||
values[2].parse::<usize>(),
|
||||
values[3].parse::<usize>(),
|
||||
)
|
||||
{
|
||||
width = new_width;
|
||||
height = new_height;
|
||||
mine_perctg = new_mines_perctg;
|
||||
game = MineSweeper::new(width, height, mine_perctg);
|
||||
command_ok = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if command_ok {
|
||||
game.print();
|
||||
} else {
|
||||
println!("Invalid command");
|
||||
}
|
||||
|
||||
print!("> ");
|
||||
io::stdout().flush().unwrap();
|
||||
command.clear();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub mod minesweeper {
|
||||
|
||||
pub struct MineSweeper {
|
||||
cell: [[Cell; 100]; 100],
|
||||
pub game_status: GameStatus,
|
||||
mines: usize,
|
||||
width: usize,
|
||||
height: usize,
|
||||
revealed_count: usize,
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone)]
|
||||
struct Cell {
|
||||
content: CellContent,
|
||||
mark: Mark,
|
||||
revealed: bool,
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone)]
|
||||
enum CellContent {
|
||||
Empty,
|
||||
Mine,
|
||||
MineNeighbour { count: u8 },
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone)]
|
||||
enum Mark {
|
||||
None,
|
||||
Mine,
|
||||
}
|
||||
|
||||
pub enum GameStatus {
|
||||
InGame,
|
||||
Won,
|
||||
Lost,
|
||||
}
|
||||
|
||||
extern crate rand;
|
||||
|
||||
use std::cmp::max;
|
||||
use std::cmp::min;
|
||||
use self::rand::Rng;
|
||||
use self::CellContent::*;
|
||||
use self::GameStatus::*;
|
||||
|
||||
impl MineSweeper {
|
||||
pub fn new(width: usize, height: usize, percentage_of_mines: usize) -> MineSweeper {
|
||||
let mut game = MineSweeper {
|
||||
cell: [[Cell {
|
||||
content: Empty,
|
||||
mark: Mark::None,
|
||||
revealed: false,
|
||||
}; 100]; 100],
|
||||
game_status: InGame,
|
||||
mines: (width * height * percentage_of_mines) / 100,
|
||||
width: width,
|
||||
height: height,
|
||||
revealed_count: 0,
|
||||
};
|
||||
game.put_mines();
|
||||
game.calc_neighbours();
|
||||
game
|
||||
}
|
||||
|
||||
pub fn play(&mut self, x: usize, y: usize) {
|
||||
match self.game_status {
|
||||
InGame => {
|
||||
if !self.cell[x][y].revealed {
|
||||
match self.cell[x][y].content {
|
||||
Mine => {
|
||||
self.cell[x][y].revealed = true;
|
||||
self.revealed_count += 1;
|
||||
self.game_status = Lost;
|
||||
}
|
||||
Empty => {
|
||||
self.flood_fill_reveal(x, y);
|
||||
if self.revealed_count + self.mines == self.width * self.height {
|
||||
self.game_status = Won;
|
||||
}
|
||||
}
|
||||
MineNeighbour { .. } => {
|
||||
self.cell[x][y].revealed = true;
|
||||
self.revealed_count += 1;
|
||||
if self.revealed_count + self.mines == self.width * self.height {
|
||||
self.game_status = Won;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
_ => println!("Game has ended"),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn mark(&mut self, x: usize, y: usize) {
|
||||
self.cell[x][y].mark = match self.cell[x][y].mark {
|
||||
Mark::None => Mark::Mine,
|
||||
Mark::Mine => Mark::None,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn print(&self) {
|
||||
print!("┌");
|
||||
for _ in 0..self.width {
|
||||
print!("─");
|
||||
}
|
||||
println!("┐");
|
||||
for y in 0..self.height {
|
||||
print!("│");
|
||||
for x in 0..self.width {
|
||||
self.cell[x][y].print();
|
||||
}
|
||||
println!("│");
|
||||
}
|
||||
print!("└");
|
||||
for _ in 0..self.width {
|
||||
print!("─");
|
||||
}
|
||||
println!("┘");
|
||||
}
|
||||
|
||||
fn put_mines(&mut self) {
|
||||
let mut rng = rand::thread_rng();
|
||||
for _ in 0..self.mines {
|
||||
while let (x, y, true) = (
|
||||
rng.gen::<usize>() % self.width,
|
||||
rng.gen::<usize>() % self.height,
|
||||
true,
|
||||
)
|
||||
{
|
||||
match self.cell[x][y].content {
|
||||
Mine => continue,
|
||||
_ => {
|
||||
self.cell[x][y].content = Mine;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn calc_neighbours(&mut self) {
|
||||
for x in 0..self.width {
|
||||
for y in 0..self.height {
|
||||
if !self.cell[x][y].is_bomb() {
|
||||
let mut adjacent_bombs = 0;
|
||||
|
||||
for i in max(x as isize - 1, 0) as usize..min(x + 2, self.width) {
|
||||
for j in max(y as isize - 1, 0) as usize..min(y + 2, self.height) {
|
||||
adjacent_bombs += if self.cell[i][j].is_bomb() { 1 } else { 0 };
|
||||
}
|
||||
}
|
||||
|
||||
if adjacent_bombs == 0 {
|
||||
self.cell[x][y].content = Empty;
|
||||
} else {
|
||||
self.cell[x][y].content = MineNeighbour { count: adjacent_bombs };
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn flood_fill_reveal(&mut self, x: usize, y: usize) {
|
||||
let mut stack = Vec::<(usize, usize)>::new();
|
||||
stack.push((x, y));
|
||||
|
||||
while let Some((i, j)) = stack.pop() {
|
||||
if self.cell[i][j].revealed {
|
||||
continue;
|
||||
}
|
||||
self.cell[i][j].revealed = true;
|
||||
self.revealed_count += 1;
|
||||
if let Empty = self.cell[i][j].content {
|
||||
for m in max(i as isize - 1, 0) as usize..min(i + 2, self.width) {
|
||||
for n in max(j as isize - 1, 0) as usize..min(j + 2, self.height) {
|
||||
if !self.cell[m][n].is_bomb() && !self.cell[m][n].revealed {
|
||||
stack.push((m, n));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Cell {
|
||||
pub fn print(&self) {
|
||||
print!(
|
||||
"{}",
|
||||
if self.revealed {
|
||||
match self.content {
|
||||
Empty => ' ',
|
||||
Mine => '*',
|
||||
MineNeighbour { count } => char::from(count + b'0'),
|
||||
}
|
||||
} else {
|
||||
match self.mark {
|
||||
Mark::Mine => '?',
|
||||
Mark::None => '.',
|
||||
}
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
pub fn is_bomb(&self) -> bool {
|
||||
match self.content {
|
||||
Mine => true,
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
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
|
||||
12
Task/Minesweeper-game/VBA/minesweeper-game-1.vba
Normal file
12
Task/Minesweeper-game/VBA/minesweeper-game-1.vba
Normal file
|
|
@ -0,0 +1,12 @@
|
|||
Option Explicit
|
||||
|
||||
Public vTime As Single
|
||||
Public PlaysCount As Long
|
||||
|
||||
Sub Main_MineSweeper()
|
||||
Dim Userf As New cMinesweeper
|
||||
'Arguments :
|
||||
'First arg is level : 0 = easy, 1 = middle, 2 = difficult
|
||||
'Second arg is Cheat Mode : True if you want to cheat...
|
||||
Userf.Show 0, True
|
||||
End Sub
|
||||
241
Task/Minesweeper-game/VBA/minesweeper-game-2.vba
Normal file
241
Task/Minesweeper-game/VBA/minesweeper-game-2.vba
Normal file
|
|
@ -0,0 +1,241 @@
|
|||
Option Explicit
|
||||
|
||||
Public myForm As Object
|
||||
Public Fram As MSForms.Frame
|
||||
Public Dico As Object
|
||||
Public DicoParent As Object
|
||||
Public TypeObjet As String
|
||||
Public Mine As Boolean
|
||||
Public boolFind As Boolean
|
||||
Private strName As String
|
||||
Private cNeighbours() As cMinesweeper
|
||||
Public WithEvents myButton As MSForms.CommandButton
|
||||
Private Const WIDTH_BUTT As Byte = 18
|
||||
Private Const MIN_OF_LINES As Byte = 7
|
||||
Private Const MAX_OF_LINES As Byte = 30 - MIN_OF_LINES
|
||||
Private Const MIN_COL As Byte = 7
|
||||
Private Const MAX_COL As Byte = 40 - MIN_COL
|
||||
Private Const POURCENT_SIMPLE As Byte = 10
|
||||
Private Const POURCENT_MEDIUM As Byte = 2 * POURCENT_SIMPLE
|
||||
Private Const POURCENT_HARD As Byte = 3 * POURCENT_SIMPLE
|
||||
Private Const COLOR_MINE As Long = &H188B0
|
||||
Private Const COLOR_BOUTON As Long = &H8000000F
|
||||
Private Const COLOR_MINE_POSSIBLE As Long = &H80FF&
|
||||
Private Const COLOR_MINE_PROB As Long = &H8080FF
|
||||
|
||||
Property Get Neighbours() As cMinesweeper()
|
||||
Neighbours = cNeighbours
|
||||
End Property
|
||||
|
||||
Property Let Neighbours(ByRef nouvNeighbours() As cMinesweeper)
|
||||
cNeighbours = nouvNeighbours
|
||||
End Property
|
||||
|
||||
Private Sub Class_Initialize()
|
||||
Set Dico = CreateObject("Scripting.dictionary")
|
||||
End Sub
|
||||
|
||||
Public Sub Show(ByRef Difficult As Long, Optional CheatMode As Boolean = False)
|
||||
On Error GoTo ErrorParametresMacros
|
||||
With ThisWorkbook.VBProject: End With
|
||||
|
||||
Dim Lin As Long, Col As Long, NbLines As Long, NbColumns As Long
|
||||
Dim NbMines As Long, MineAdress() As String, CptMine As Long
|
||||
Randomize Timer
|
||||
NbLines = Int(MAX_OF_LINES * Rnd) + MIN_OF_LINES
|
||||
NbColumns = Int(MAX_COL * Rnd) + MIN_COL
|
||||
Select Case Difficult
|
||||
Case 0: Difficult = POURCENT_SIMPLE
|
||||
Case 1: Difficult = POURCENT_MEDIUM
|
||||
Case 2: Difficult = POURCENT_HARD
|
||||
End Select
|
||||
PlaysCount = 0
|
||||
NbMines = (NbLines * NbColumns) * Difficult \ 100
|
||||
ReDim MineAdress(NbMines)
|
||||
For CptMine = 1 To NbMines
|
||||
MineAdress(CptMine) = Int(NbColumns * Rnd) + 1 & "-" & Int(NbLines * Rnd) + 1
|
||||
Next
|
||||
Call Create_Usf("Minesweeper", (NbColumns * WIDTH_BUTT) + 5, (NbLines * WIDTH_BUTT) + 22)
|
||||
Call New_Frame("Fram1", "", NbColumns * WIDTH_BUTT, NbLines * WIDTH_BUTT)
|
||||
For Lin = 1 To NbLines
|
||||
For Col = 1 To NbColumns
|
||||
Call Dico("Fram1").New_Button(Col & "-" & Lin, "", WIDTH_BUTT * (Col - 1), WIDTH_BUTT * (Lin - 1), IsIn(Col & "-" & Lin, MineAdress), CheatMode)
|
||||
Set Dico("Fram1").Dico(Col & "-" & Lin).DicoParent = Dico("Fram1").Dico
|
||||
Next Col
|
||||
Next Lin
|
||||
MsgBox "Start With " & NbMines & " mines." & vbCrLf & "Good luck !"
|
||||
myForm.Show
|
||||
Exit Sub
|
||||
ErrorParametresMacros:
|
||||
MsgBox "Programmatic Access to Visual Basic Project is not trusted. See it in Macro's security!"
|
||||
End Sub
|
||||
|
||||
Private Sub Create_Usf(strTitle As String, dblWidth As Double, dblHeight As Double)
|
||||
TypeObjet = "UserForm"
|
||||
Set myForm = ThisWorkbook.VBProject.VBComponents.Add(3)
|
||||
strName = myForm.Name
|
||||
VBA.UserForms.Add (strName)
|
||||
Set myForm = UserForms(UserForms.Count - 1)
|
||||
With myForm
|
||||
.Caption = strTitle
|
||||
.Width = dblWidth
|
||||
.Height = dblHeight
|
||||
End With
|
||||
End Sub
|
||||
|
||||
Public Sub New_Frame(myStringName As String, strTitle As String, dblWidth As Double, dblHeight As Double)
|
||||
If Dico.Exists(myStringName) = True Then Exit Sub
|
||||
Dim myClass As New cMinesweeper
|
||||
Select Case TypeObjet
|
||||
Case "UserForm": Set myClass.Fram = myForm.Controls.Add("forms.frame.1")
|
||||
Case "Frame": Set myClass.Fram = Fram.Controls.Add("forms.frm.1")
|
||||
End Select
|
||||
myClass.TypeObjet = "Frame"
|
||||
Set myClass.myForm = myForm
|
||||
With myClass.Fram
|
||||
.Name = myStringName
|
||||
.Caption = strTitle
|
||||
.Move 0, 0, dblWidth, dblHeight
|
||||
End With
|
||||
Dico.Add myStringName, myClass
|
||||
Set myClass = Nothing
|
||||
End Sub
|
||||
|
||||
Public Sub New_Button(myStringName As String, strTitle As String, dblLeft As Double, dblTop As Double, boolMine As Boolean, Optional CheatMode As Boolean)
|
||||
If Dico.Exists(myStringName) = True Then Exit Sub
|
||||
Dim myClass As New cMinesweeper
|
||||
Select Case TypeObjet
|
||||
Case "UserForm": Set myClass.myButton = myForm.Controls.Add("forms.CommandButton.1")
|
||||
Case "Frame": Set myClass.myButton = Fram.Controls.Add("forms.CommandButton.1")
|
||||
End Select
|
||||
Set myClass.myForm = myForm
|
||||
myClass.Mine = boolMine
|
||||
With myClass.myButton
|
||||
.Name = myStringName
|
||||
.Caption = strTitle
|
||||
.Move dblLeft, dblTop, WIDTH_BUTT, WIDTH_BUTT
|
||||
If CheatMode Then
|
||||
If boolMine Then .BackColor = COLOR_MINE Else .BackColor = COLOR_BOUTON
|
||||
Else
|
||||
.BackColor = COLOR_BOUTON
|
||||
End If
|
||||
End With
|
||||
Dico.Add myStringName, myClass
|
||||
Set myClass = Nothing
|
||||
End Sub
|
||||
|
||||
Private Function IsIn(strAddress As String, Tb) As Boolean
|
||||
Dim i As Long
|
||||
For i = 0 To UBound(Tb)
|
||||
If Tb(i) = strAddress Then IsIn = True: Exit Function
|
||||
Next i
|
||||
End Function
|
||||
|
||||
Private Sub myButton_MouseDown(ByVal Button As Integer, ByVal Shift As Integer, ByVal x As Single, ByVal y As Single)
|
||||
If Button = XlMouseButton.xlSecondaryButton Then
|
||||
Select Case myButton.Caption
|
||||
Case "": myButton.Caption = "!": myButton.BackColor = COLOR_MINE_PROB
|
||||
Case "!": myButton.Caption = "?": myButton.BackColor = COLOR_MINE_POSSIBLE
|
||||
Case "?": myButton.Caption = "": myButton.BackColor = COLOR_BOUTON
|
||||
Case Else:
|
||||
End Select
|
||||
ElseIf Button = XlMouseButton.xlPrimaryButton Then
|
||||
PlaysCount = PlaysCount + 1
|
||||
If PlaysCount = 1 Then vTime = Timer
|
||||
If DicoParent.Item(myButton.Name).Mine Then
|
||||
Call Show_Mines
|
||||
MsgBox "Game over!"
|
||||
myForm.Hide
|
||||
Else
|
||||
myButton.BackColor = COLOR_BOUTON
|
||||
Dim myClass As cMinesweeper
|
||||
Set myClass = DicoParent.Item(myButton.Name)
|
||||
Call Demine(myClass)
|
||||
End If
|
||||
End If
|
||||
If IsVictoriousGame Then
|
||||
Call Show_Mines
|
||||
MsgBox "You win." & vbCrLf & "in : " & PlaysCount & " clicks, and in : " & Timer - vTime & " seconds."
|
||||
Erase Neighbours
|
||||
myForm.Hide
|
||||
End If
|
||||
End Sub
|
||||
|
||||
Private Sub Show_Mines()
|
||||
Dim cle As Variant
|
||||
For Each cle In DicoParent.Keys
|
||||
If DicoParent.Item(cle).Mine Then DicoParent.Item(cle).myButton.BackColor = COLOR_MINE
|
||||
Next
|
||||
End Sub
|
||||
|
||||
Private Sub Demine(Cl As cMinesweeper)
|
||||
Dim NbMines As Integer
|
||||
NbMines = Count_Of_Mines(Cl.myButton.Name)
|
||||
If NbMines > 0 Then
|
||||
Cl.myButton.Caption = NbMines
|
||||
Cl.boolFind = True
|
||||
Cl.myButton.BackColor = COLOR_BOUTON
|
||||
Else
|
||||
If Cl.boolFind = False Then
|
||||
Cl.boolFind = True
|
||||
Cl.myButton.Visible = False
|
||||
What_Neighbours Cl
|
||||
Dim Tb() As cMinesweeper, i As Integer
|
||||
Tb = Cl.Neighbours
|
||||
For i = 0 To UBound(Tb)
|
||||
Demine Tb(i)
|
||||
Next
|
||||
End If
|
||||
End If
|
||||
End Sub
|
||||
|
||||
Private Function Count_Of_Mines(Bout As String) As Integer
|
||||
Dim i As Integer, j As Integer, Col As Integer, Lin As Integer
|
||||
Dim myClass As cMinesweeper
|
||||
For i = -1 To 1
|
||||
For j = -1 To 1
|
||||
Col = CInt(Split(Bout, "-")(0)) + i
|
||||
Lin = CInt(Split(Bout, "-")(1)) + j
|
||||
If DicoParent.Exists(Col & "-" & Lin) Then
|
||||
Set myClass = DicoParent.Item(Col & "-" & Lin)
|
||||
If myClass.Mine Then Count_Of_Mines = Count_Of_Mines + 1
|
||||
End If
|
||||
Next j
|
||||
Next i
|
||||
End Function
|
||||
|
||||
Private Sub What_Neighbours(Cl As cMinesweeper)
|
||||
Dim i As Integer, j As Integer, Col As Integer, Lin As Integer
|
||||
Dim myClass As cMinesweeper, ListNeighbours() As cMinesweeper, cpt As Byte
|
||||
For i = -1 To 1
|
||||
For j = -1 To 1
|
||||
Col = CInt(Split(Cl.myButton.Name, "-")(0)) + i
|
||||
Lin = CInt(Split(Cl.myButton.Name, "-")(1)) + j
|
||||
If DicoParent.Exists(Col & "-" & Lin) And Cl.myButton.Name <> Col & "-" & Lin Then
|
||||
Set myClass = DicoParent.Item(Col & "-" & Lin)
|
||||
ReDim Preserve ListNeighbours(cpt)
|
||||
Set ListNeighbours(cpt) = myClass
|
||||
cpt = cpt + 1
|
||||
End If
|
||||
Next j
|
||||
Next i
|
||||
Cl.Neighbours = ListNeighbours
|
||||
End Sub
|
||||
|
||||
Private Function IsVictoriousGame() As Boolean
|
||||
Dim cle As Variant
|
||||
For Each cle In DicoParent.Keys
|
||||
If DicoParent.Item(cle).boolFind = False And DicoParent.Item(cle).Mine = False Then IsVictoriousGame = False: Exit Function
|
||||
Next
|
||||
IsVictoriousGame = True
|
||||
End Function
|
||||
|
||||
Private Sub Class_Terminate()
|
||||
Dim VBComp
|
||||
Set Dico = Nothing
|
||||
Set DicoParent = Nothing
|
||||
If strName <> "" Then
|
||||
Set VBComp = ThisWorkbook.VBProject.VBComponents(strName)
|
||||
ThisWorkbook.VBProject.VBComponents.Remove VBComp
|
||||
End If
|
||||
End Sub
|
||||
204
Task/Minesweeper-game/Wren/minesweeper-game.wren
Normal file
204
Task/Minesweeper-game/Wren/minesweeper-game.wren
Normal file
|
|
@ -0,0 +1,204 @@
|
|||
import "/dynamic" for Struct
|
||||
import "/fmt" for Fmt
|
||||
import "random" for Random
|
||||
import "/ioutil" for Input
|
||||
import "/str" for Str
|
||||
|
||||
var Cell = Struct.create("Cell", ["isMine", "display"])
|
||||
|
||||
var lMargin = 4
|
||||
var grid = []
|
||||
var mineCount = 0
|
||||
var minesMarked = 0
|
||||
var isGameOver = false
|
||||
var rand = Random.new()
|
||||
|
||||
var makeGrid = Fn.new { |n, m|
|
||||
if ( n <= 0 || m <= 0) Fiber.abort("Grid dimensions must be positive.")
|
||||
grid = List.filled(n, null)
|
||||
for (i in 0...n) {
|
||||
grid[i] = List.filled(m, null)
|
||||
for (j in 0...m) grid[i][j] = Cell.new(false, ".")
|
||||
}
|
||||
var min = (n * m * 0.1).round // 10% of tiles
|
||||
var max = (n * m * 0.2).round // 20% of tiles
|
||||
mineCount = min + rand.int(max - min + 1)
|
||||
var rm = mineCount
|
||||
while (rm > 0) {
|
||||
var x = rand.int(n)
|
||||
var y = rand.int(m)
|
||||
if (!grid[x][y].isMine) {
|
||||
rm = rm - 1
|
||||
grid[x][y].isMine = true
|
||||
}
|
||||
}
|
||||
minesMarked = 0
|
||||
isGameOver = false
|
||||
}
|
||||
|
||||
var displayGrid = Fn.new { |isEndOfGame|
|
||||
if (!isEndOfGame) {
|
||||
System.print("Grid has %(mineCount) mine(s), %(minesMarked) mine(s) marked.")
|
||||
}
|
||||
var margin = " " * lMargin
|
||||
System.write("%(margin) ")
|
||||
for (i in 1..grid.count) System.write(i)
|
||||
System.print()
|
||||
System.print("%(margin) %("-" * grid.count)")
|
||||
for (y in 0...grid[0].count) {
|
||||
Fmt.write("$*d:", lMargin, y+1)
|
||||
for (x in 0...grid.count) System.write(grid[x][y].display)
|
||||
System.print()
|
||||
}
|
||||
}
|
||||
|
||||
var endGame = Fn.new { |msg|
|
||||
isGameOver = true
|
||||
System.print(msg)
|
||||
var ans = Input.option("Another game (y/n)? : ", "ynYN")
|
||||
if (ans == "n" || ans == "N") return
|
||||
makeGrid.call(6, 4)
|
||||
displayGrid.call(false)
|
||||
}
|
||||
|
||||
var resign = Fn.new {
|
||||
var found = 0
|
||||
for (y in 0...grid[0].count) {
|
||||
for (x in 0...grid.count) {
|
||||
if (grid[x][y].isMine) {
|
||||
if (grid[x][y].display == "?") {
|
||||
grid[x][y].display = "Y"
|
||||
found = found + 1
|
||||
} else if (grid[x][y].display != "x") {
|
||||
grid[x][y].display = "N"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
displayGrid.call(true)
|
||||
var msg = "You found %(found), out of %(mineCount) mine(s)."
|
||||
endGame.call(msg)
|
||||
}
|
||||
|
||||
var usage = Fn.new {
|
||||
System.print("h or ? - this help,")
|
||||
System.print("c x y - clear cell (x,y),")
|
||||
System.print("m x y - marks (toggles) cell (x,y),")
|
||||
System.print("n - start a new game,")
|
||||
System.print("q - quit/resign the game,")
|
||||
System.print("where x is the (horizontal) column number and y is the (vertical) row number.\n")
|
||||
}
|
||||
|
||||
var markCell = Fn.new { |x, y|
|
||||
if (grid[x][y].display == "?") {
|
||||
minesMarked = minesMarked - 1
|
||||
grid[x][y].display = "."
|
||||
} else if (grid[x][y].display == ".") {
|
||||
minesMarked = minesMarked + 1
|
||||
grid[x][y].display = "?"
|
||||
}
|
||||
}
|
||||
|
||||
var countAdjMines = Fn.new { |x, y|
|
||||
var count = 0
|
||||
for (j in y-1..y+1) {
|
||||
if (j >= 0 && j < grid[0].count) {
|
||||
for (i in x-1..x+1) {
|
||||
if (i >= 0 && i < grid.count) {
|
||||
if (grid[i][j].isMine) count = count + 1
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return count
|
||||
}
|
||||
|
||||
var clearCell // recursive function
|
||||
clearCell = Fn.new { |x, y|
|
||||
if (x >= 0 && x < grid.count && y >= 0 && y < grid[0].count) {
|
||||
if (grid[x][y].display == ".") {
|
||||
if (!grid[x][y].isMine) {
|
||||
var count = countAdjMines.call(x, y)
|
||||
if (count > 0) {
|
||||
grid[x][y].display = String.fromByte(48 + count)
|
||||
} else {
|
||||
grid[x][y].display = " "
|
||||
clearCell.call(x+1, y)
|
||||
clearCell.call(x+1, y+1)
|
||||
clearCell.call(x, y+1)
|
||||
clearCell.call(x-1, y+1)
|
||||
clearCell.call(x-1, y)
|
||||
clearCell.call(x-1, y-1)
|
||||
clearCell.call(x, y-1)
|
||||
clearCell.call(x+1, y-1)
|
||||
}
|
||||
} else {
|
||||
grid[x][y].display = "x"
|
||||
System.print("Kaboom! You lost!")
|
||||
return false
|
||||
}
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
var testForWin = Fn.new {
|
||||
var isCleared = false
|
||||
if (minesMarked == mineCount) {
|
||||
isCleared = true
|
||||
for (x in 0...grid.count) {
|
||||
for (y in 0...grid[0].count) {
|
||||
if (grid[x][y].display == ".") isCleared = false
|
||||
}
|
||||
}
|
||||
}
|
||||
if (isCleared) System.print("You won!")
|
||||
return isCleared
|
||||
}
|
||||
|
||||
var splitAction = Fn.new { |action|
|
||||
var fields = action.split(" ").where{ |s| s != "" }.toList
|
||||
if (fields.count != 3) return [0, 0, false]
|
||||
var x = Num.fromString(fields[1])
|
||||
if (x < 1 || x > grid.count) return [0, 0, false]
|
||||
var y = Num.fromString(fields[2])
|
||||
if (y < 1 || y > grid[0].count) return [0, 0, false]
|
||||
return [x, y, true]
|
||||
}
|
||||
|
||||
usage.call()
|
||||
makeGrid.call(6, 4)
|
||||
displayGrid.call(false)
|
||||
while (!isGameOver) {
|
||||
var action = Str.lower(Input.text("\n>", 1))
|
||||
var first = action[0]
|
||||
if (first == "h" || first == "?") {
|
||||
usage.call()
|
||||
} else if (first == "n") {
|
||||
makeGrid.call(6, 4)
|
||||
displayGrid.call(false)
|
||||
} else if (first == "c") {
|
||||
var res = splitAction.call(action)
|
||||
if (!res[2]) continue
|
||||
var x = res[0]
|
||||
var y = res[1]
|
||||
if (clearCell.call(x-1, y-1)) {
|
||||
displayGrid.call(false)
|
||||
if (testForWin.call()) resign.call()
|
||||
} else {
|
||||
resign.call()
|
||||
}
|
||||
} else if (first == "m") {
|
||||
var res = splitAction.call(action)
|
||||
if (!res[2]) continue
|
||||
var x = res[0]
|
||||
var y = res[1]
|
||||
markCell.call(x-1, y-1)
|
||||
displayGrid.call(false)
|
||||
if (testForWin.call()) resign.call()
|
||||
} else if (first == "q") {
|
||||
resign.call()
|
||||
} else {
|
||||
System.print("Invalid option, try again")
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue