June 2018 Update

This commit is contained in:
Ingy döt Net 2018-06-22 20:57:24 +00:00
parent ba8067c3b7
commit 22f33d4004
5278 changed files with 84726 additions and 14379 deletions

View 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;
}
}
}
}
}

View 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,
}
}
}
}

View 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

View 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