} //END (Cell_Up) /// <summary> /// Double click the mine field cell event handler /// </summary> /// <param name="sender">Event sender</param> /// <param name="e">Event arguments</param> private void MineFieldLabel_DoubleClick(object sender, EventArgs e) { if (ME.CurrentGameState.State != MinesEngine.GameState.NewGame && //if current game state is NOT NewGame ME.CurrentGameState.State != MinesEngine.GameState.InProgress) //AND current game state is NOT InProgress return; //just do nothing and return MineFieldLabel Cell = (MineFieldLabel)sender; //get the cell upon which mouse acted MinesEngine.CurrentGameStateInfo GS = ME.OpenMany(Cell.Column, Cell.Row); //open the current cell and cells around it switch (GS.State) //switch between the current game states { case MinesEngine.GameState.InProgress: //game's in progress RedrawOpened(); //redraw already opened cells break; case MinesEngine.GameState.Loose: //game's lost tTime.Stop(); //stop game timer RedrawOpened(); //redraw already opened cells OpenLoose(GS); //open field as for the lost game butNewGame.ImageIndex = 3; //set the NewGame button's image to LOST MStats.CalcStats(ME, MS, GameSeconds, AskForUserName); //calculate game stats break; case MinesEngine.GameState.Win: //game's won tTime.Stop(); //stop game timer RedrawOpened(); //redraw already opened cells butNewGame.ImageIndex = 4; //set the NewGame button's image to WON MStats.CalcStats(ME, MS, GameSeconds, AskForUserName); //calculate game stats break; case MinesEngine.GameState.Stopped: //game's stopped break; //do nothing } //ENDSWITCH (game states) } //END (MineFieldLabel_DoubleClick)
} //END (ChangeLabel) /// <summary> /// Get the new Mine Field Cell Label for the specified mine field location /// </summary> /// <param name="location">Location of the new Cell</param> /// <returns>Instance of the new Cell Label</returns> public MineFieldLabel GetNew(int cellSize, int column, int row) { MineFieldLabel newLabel = (MineFieldLabel)Clone(); //clone new cell label from prototype newLabel.Location = new Point(cellSize * column + 2, cellSize * row + 8); //set label location on the form newLabel.Column = column; //set mine field column number newLabel.Row = row; //set mine field row number return(newLabel); //return instance of the new cell label } //END (GetNew)
} //END (butNewGame_Click) /// <summary> /// Mouse button goes down upon the minefield cell (event handler) /// </summary> /// <param name="sender">Sender of the event</param> /// <param name="e">Event arguments</param> private void Cell_Down(object sender, MouseEventArgs e) { if (ME.CurrentGameState.State != MinesEngine.GameState.NewGame && //if current game state NOT equals NewGame ME.CurrentGameState.State != MinesEngine.GameState.InProgress) //AND current game state NOT equals InProgress //which means that current game is not in progress and is not starting return; //then just return (mouse events are handled only when game is not stopped) //if we're here then game is not stopped MineFieldLabel Cell = (MineFieldLabel)sender; //cell-sender of the current event (clicked cell of the mine field) //save upon which cell acted current mouse button if (e.Button == MouseButtons.Left) //if it was left button LBDown = new MouseEventArgs( //we'll save arguments for the left button (will be used later) MouseButtons.Left, //left button constant 1, //number of clicks isn't used Cell.Column, //as an X coordinate we will save clicked cell's column number Cell.Row, //as an Y coordinate we will save clicked cell's row number 0); //delta isn't used if (e.Button == MouseButtons.Right) //if it was right button RBDown = new MouseEventArgs( //we'll save arguments for the right button (will be used later) MouseButtons.Right, //right button constant 1, //number of clicks isn't used Cell.Column, //as an X coordinate we will save clicked cell's column number Cell.Row, //as an Y coordinate we will save clicked cell's row number 0); //delta isn't used //check whether both left and right buttons acted upon the same cell if (SameButton(LBDown, RBDown)) //if left and right buttons acted upon the same cell { //we will change the current cell and all cells around the current one for (int dI = -1; dI <= 1; dI++) //moving through the previous, current and next columns { if (Cell.Column + dI < 0 || Cell.Column + dI >= ME.Width) //if current dI gets us outside the mine field borders continue; //we will skip current dI for (int dJ = -1; dJ <= 1; dJ++) //moving thouugh the previous, current and next cells in the current column { if (Cell.Row + dJ < 0 || Cell.Row + dJ >= ME.Height) //if current dJ gets us outside the mine field borders continue; //we will skip current dJ FL[Cell.Column + dI][Cell.Row + dJ].BackColor = OpenedColor; //set current cell's back color to the opened-cell-color } //ENDFOR (cells in the current column) } //ENDFOR (columns) } //ENDIF (same cell) else if (e.Button == MouseButtons.Left) //if not the same cell and left button acted FL[Cell.Column][Cell.Row].BackColor = OpenedColor; //set back color of the current cell to the opened-cell-color } //END (Cell_Down)
} //END (Cell_Down) /// <summary> /// Mouse button goes up upon the minefield cell (event handler) /// </summary> /// <param name="sender">Event sender</param> /// <param name="e">Event arguments</param> private void Cell_Up(object sender, MouseEventArgs e) { if (ME.CurrentGameState.State != MinesEngine.GameState.NewGame && //if current game state is NOT NewGame ME.CurrentGameState.State != MinesEngine.GameState.InProgress) //AND current game state is NOT InProgress //which means that game is stopped return; //just return (mine field doesn't work while game is stopped) //if we're here then game is NOT stopped MineFieldLabel Cell = (MineFieldLabel)sender; //get the cell upon mouse button acted MouseEventArgs curButton = //create arguments for the current mouse button new MouseEventArgs(e.Button, //which button acted (left or right) e.Clicks, //number of clicks (not used) Cell.Column, //current cell's column number Cell.Row, //current cell's row number e.Delta); //delta (not used) //check whether it is a new game if (!GameStart) //if game wasn't started by now (it was the first click on the mine field) { if (SameButton(LBDown, curButton) || SameButton(curButton, RBDown)) //if button goes up on the same cell where it went down { GameStart = true; //start game GameSeconds = 0; //clear game time tTime.Start(); //start game timer } //ENDIF (same cell) } //ENDIF (GameStart) //check the combinations of the currently acted buttons if (SameButton(LBDown, RBDown)) //Left+Right buttons acted together { //we will work with the current cell and all the cells around it for (int dI = -1; dI <= 1; dI++) //moving through the previous, current and next columns { if (Cell.Column + dI < 0 || Cell.Column + dI >= ME.Width) //if current dI gets us outside the mine field borders continue; //just skip current dI for (int dJ = -1; dJ <= 1; dJ++) //moving through the previous, current and next cells in current column { if (Cell.Row + dJ < 0 || Cell.Row + dJ >= ME.Height) //if current dJ gets us outside the mine field borders continue; //just skip current dJ FL[Cell.Column + dI][Cell.Row + dJ].BackColor = ClosedColor; //set current cell's color to the closed-cell-color } //ENDFOR (cells in column) } //ENDFOR (columns) MinesEngine.CurrentGameStateInfo GS = ME.OpenMany(Cell.Column, Cell.Row); //open the clicked cell and cells around it switch (GS.State) //switch between the game states { case MinesEngine.GameState.InProgress: //game's in progress RedrawOpened(); //redraw already opened cells break; case MinesEngine.GameState.Loose: //game's lost tTime.Stop(); //stop the game timer RedrawOpened(); //redraw already opened cells OpenLoose(GS); //open field as for the lost game butNewGame.ImageIndex = 3; //set the NewGame button's image to the LOOSE MStats.CalcStats(ME, MS, GameSeconds, AskForUserName); //calculate stats break; case MinesEngine.GameState.Win: //game's won tTime.Stop(); //stop the game timer RedrawOpened(); //redraw already opened cells butNewGame.ImageIndex = 4; //set the NewGame button's image to the WIN MStats.CalcStats(ME, MS, GameSeconds, AskForUserName); //calculate stats break; case MinesEngine.GameState.Stopped: //game's stopped break; //do nothing } //ENDSWITCH (game state) } //ENDIF (left+right buttons) else if (SameButton(LBDown, curButton)) //same left button upped as was down (left-click on the cell) { FL[Cell.Column][Cell.Row].BackColor = ClosedColor; //set current cell's back color to the closed-cell-color MinesEngine.CurrentGameStateInfo GS = ME.OpenCell(Cell.Column, Cell.Row); //open the clicked cell switch (GS.State) //switch between the game states { case MinesEngine.GameState.InProgress: //game's in progress RedrawOpened(); //redraw already opened cells break; case MinesEngine.GameState.Loose: //game's lost tTime.Stop(); //stop the game timer RedrawOpened(); //redraw already opened cells OpenLoose(GS); //open field as for the lost game butNewGame.ImageIndex = 3; //set the NewGame button's image to the LOOSE MStats.CalcStats(ME, MS, GameSeconds, AskForUserName); //calculate stats break; case MinesEngine.GameState.Win: //game's won tTime.Stop(); //stop the game timer RedrawOpened(); //redraw already opened cells butNewGame.ImageIndex = 4; //set the NewGame button's image to the WIN MStats.CalcStats(ME, MS, GameSeconds, AskForUserName); //calculate stats break; case MinesEngine.GameState.Stopped: //game's stopped break; //do nothing } //ENDSWITCH (game state) } //ENDELSEIF (left click) else if (SameButton(curButton, RBDown)) //same right button upped as was down (right-click on the cell) { ME.ChangeMarker(Cell.Column, Cell.Row); //change marker on the current cell if (ME[Cell.Column, Cell.Row].marker > 0) //if there is marker set on the current cell FL[Cell.Column][Cell.Row].ImageIndex = ME[Cell.Column, Cell.Row].marker; //draw marker on the current cell else //otherwise (marker not set) FL[Cell.Column][Cell.Row].ImageIndex = -1; //hide marker on the current cell lMines.Text = ((int)ME.NumMines - (int)ME.NumFlags).ToString(); //change number of mines in the mines-textfield } //ENDELSEIF (right click) LBDown = null; //clear the information about the pushed left button of the mouse RBDown = null; //clear the information about the pushed right button of the mouse } //END (Cell_Up)
} //END (ctor) /// <summary> /// Main form load handler /// </summary> /// <param name="sender">Sender of the form load event</param> /// <param name="e">Form load event args</param> private void FormMineSweeper_Load(object sender, EventArgs e) { //loading game settings try //trying to load settings from the file { FileStream fs = new FileStream("minesettings.soap", FileMode.Open); //using SOAP-serialization SoapFormatter formatter = new SoapFormatter(); MS = (MinesSettings)formatter.Deserialize(fs); //disposing the file-stream fs.Dispose(); fs = null; } //ENDTRY catch (FileNotFoundException) //if game-settings file wasn't found { MS = MinesSettings.setSettings(); //loading default settings } //ENDCATCH (File not found) catch (SerializationException) //if something went wrong with serialization { MS = MinesSettings.setSettings(); //loading default settings } //ENDCATCH (Serialization) //loading game stats try //trying to load stats from the file { FileStream fs = new FileStream("minestats.soap", FileMode.Open); //using SOAP-serialization SoapFormatter formatter = new SoapFormatter(); MStats = (MinesStatistics)formatter.Deserialize(fs); //disposing the file-stream fs.Dispose(); fs = null; } //ENDTRY catch (FileNotFoundException) //if game-stats file wasn't found { MStats = MinesStatistics.getInstance(); //create empty stats } //ENDCATCH (File not found catch (SerializationException) //if something went wrong with serialization { MStats = MinesStatistics.getInstance(); //create empty stats } //ENDCATCH (Serialization) //setting styles for the form controls SetStyle(ControlStyles.UserPaint, true); //controls must be drawn by themselves (not by OS) SetStyle(ControlStyles.AllPaintingInWmPaint, true); //controls must ignore WM_ERASEBKGND message (reduces flicker) SetStyle(ControlStyles.OptimizedDoubleBuffer, true); //controls must be pre-drawn in buffer (reduces flicker) SetStyle(ControlStyles.ResizeRedraw, true); //controls must be re-drawn when their size changes UpdateStyles(); //force apply the new styles //creating prototype mine-field label (will be used in cloning all the minefield cells) flPrototype = new MineFieldLabel( new Size(CellSize, CellSize), //label size ilIconsField, //image list for label ClosedColor, //back color of the label Cell_Down, //mouse-down event handler Cell_Up, //mouse-up event handler MineFieldLabel_DoubleClick); //double-click event handler //generating all the cells for the maximal-field-dimensions by using prototype label Array.Resize(ref FL, MinesSettings.MaxWidth); //get memory for the field for(int i = 0; i < MinesSettings.MaxWidth; i++) //moving through all the columns { Array.Resize(ref FL[i], MinesSettings.MaxHeight); //get memory for the current field column for (int j = 0; j < MinesSettings.MaxHeight; j++) //moving through all the cells in current column FL[i][j] = flPrototype.GetNew(CellSize, i, j); //create new label for the current cell gbMineField.Controls.AddRange(FL[i]); //add current column of cells into the field } //ENDFOR (columns) //initialising the mine field InitialiseField(); } //END (FormMineSweeper_Load)