Files
BH2023-Minesweeper/info/Minesweeper2/MinesweeperGui/MainWindow.xaml.cs
2023-09-28 20:23:18 +08:00

956 lines
33 KiB
C#

using System;
using System.Collections.Generic;
using System.Threading;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Controls.Primitives;
using System.Windows.Input;
using System.Windows.Media;
using MinesweeperControl;
using MinesweeperSolver;
using static MinesweeperControl.GameDescription;
using static MinesweeperControl.MinesweeperGame;
namespace MinesweeperGui {
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window
{
private readonly bool verbose = true; // determines whether diagnostic info gets written to the console
private readonly ImageSource Hidden;
private readonly ImageSource[] MineValue = new ImageSource[9];
private readonly ImageSource Flagged;
private readonly ImageSource FlaggedWrong;
private readonly ImageSource Mine;
private readonly ImageSource MineWrong;
private readonly ImageSource[] LedValue = new ImageSource[10];
private int tileSize = 32;
private GameDescription gameDescription = GameDescription.EXPERT_SAFE;
// details about the solver
private SolverInfo solverInfo;
private SolverActionHeader solverActions = new SolverActionHeader();
// graphical components
private Image hintImage; // overlay of hints from the solver
private Image totalImage; // composite image of imageDrawings
private DrawingGroup imageDrawings; // contains all the tiles
private ImageDrawing[,] images; // all the tiles
private readonly Image[] digits = new Image[8];
// tool tip elements
private Popup gameToolTip = new Popup();
private readonly TextBox popupText = new TextBox();
// details about the visible board
private int topX = 0;
private int topY = 0;
private int boardWidth = 0;
private int boardHeight = 0;
private ActionResult[,] tiles;
private MinesweeperGame game;
private int minesLeftSize = 6;
private bool useSolver = false;
private bool autoRunning = false;
private bool useGuesses = false;
private bool logicalLock = false;
private int gameNumber = 1;
private int autoPlayMinDelay = 250;
private SolverAction jumpTo;
public object MinesweeperMain { get; private set; }
public MainWindow() {
Utility.Write("At MainWindow constructor");
InitializeComponent();
// load the images we need
Hidden = Utility.BuildImageSource("facingDown.png", tileSize);
Flagged = Utility.BuildImageSource("flagged.png", tileSize);
FlaggedWrong = Utility.BuildImageSource("flaggedWrong.png", tileSize);
Mine = Utility.BuildImageSource("mine.png", tileSize);
MineWrong = Utility.BuildImageSource("exploded.png", tileSize);
for (int i = 0; i < 9; i++) {
MineValue[i] = Utility.BuildImageSource(i + ".png", tileSize);
}
for (int i = 0; i < 10; i++) {
LedValue[i] = Utility.BuildImageSource("led" + i + ".png", 24, 40);
}
CustomWidth.Text = "100";
CustomHeight.Text = "100";
CustomMines.Text = "2000";
for (int i = 0; i < digits.Length; i++) {
digits[i] = new Image() {
Source = LedValue[0]
};
Canvas.SetTop(digits[i], 0);
Canvas.SetLeft(digits[i], i * LedValue[0].Width);
MinesLeft.Children.Add(digits[i]);
}
// complete creating the popup
popupText.Text = "";
popupText.Background = new SolidColorBrush( Color.FromArgb(128, 227, 227, 227));
popupText.Foreground = Brushes.Black;
popupText.FontSize = 20;
popupText.FontWeight = FontWeights.Bold;
gameToolTip.Child = popupText;
gameToolTip.AllowsTransparency = true;
gameToolTip.Placement = PlacementMode.Relative;
gameToolTip.PlacementTarget = gameCanvas;
gameToolTip.IsOpen = true;
gameCanvas.Children.Add(gameToolTip);
// start up a game
InitializeTiles1();
Utility.Write("Graphics rendering tier = " + (RenderCapability.Tier >> 16));
SolverMain.Initialise();
}
private void AutoPlay() {
Thread autoplay = new Thread(AutoPlayRunner);
autoplay.Start();
}
// this method runs on a different thread. gameNumber is changed by clicking chosing a new game from the UI thread.
private void AutoPlayRunner() {
Dispatcher.Invoke(() => gameCanvas.Cursor = Cursors.Wait);
logicalLock = true;
int runningGameNumber = gameNumber; // remember the game number we are solving
//Utility.Write("AutoRunning thread starting");
solverActions = SolverMain.FindActions(solverInfo); // pass the solver info into the solver and see what it comes up with
Dispatcher.Invoke(() => RenderHints());
while (IsAutoPlayValid() && gameNumber == runningGameNumber) {
long start = DateTime.Now.Ticks;
GameResult result = game.ProcessActions(solverActions.solverActions);
//Utility.Write("Game controller returned " + result.actionResults.Count + " results from this action");
long end1 = DateTime.Now.Ticks;
// do the rendering while we are stil playing the same game
if (gameNumber == runningGameNumber) {
gameCanvas.Dispatcher.Invoke(() => RenderResults(result));
} else {
break;
}
//Utility.Write("After RenderResults took " + (DateTime.Now.Ticks - start) + " ticks");
solverInfo.AddInformation(result); // let the solver know what has happened
// nothing more to do if we have won or lost
if (result.status == GameStatus.Lost || result.status == GameStatus.Won) {
Dispatcher.Invoke(() => DisplayFinalOutcome(result));
break;
}
solverActions = SolverMain.FindActions(solverInfo); // pass the solver info into the solver and see what it comes up with
//foreach (SolverAction action in solverActions) {
// Utility.Write("Playing " + action.AsText() + " probability " + action.safeProbability);
//}
//long end2 = DateTime.Now.Ticks;
// do the rendering while we are stil playing the same game
if (gameNumber == runningGameNumber) {
Dispatcher.Invoke(() => RenderHints());
} else {
break;
}
//Utility.Write("After RenderHints took " + (DateTime.Now.Ticks - start) + " ticks");
Utility.Write("Tiles remaining " + solverInfo.GetTilesLeft());
long end = DateTime.Now.Ticks;
int milliseconds = (int) ((end - start) / 10000);
int wait = Math.Max(0, autoPlayMinDelay - milliseconds);
//Utility.Write("Autoplay processing took " + milliseconds + " milliseconds (" + (end - start) + " ticks)");
//Console.WriteLine("Autoplay processing took " + milliseconds + " milliseconds");
if (!IsAutoPlayValid()) {
break;
}
Thread.Sleep(wait); // wait until all the time is used up
}
logicalLock = false;
Dispatcher.Invoke(() => gameCanvas.Cursor = Cursors.Arrow);
//Utility.Write("AutoRunning thread ending");
}
// create the non-graphical parts of the game
private void InitializeTiles1() {
gameNumber++;
logicalLock = false;
minesLeftSize = Math.Max(3, (int) Math.Log10(gameDescription.mines) + 1);
MinesLeftHolder.Width = 24 * minesLeftSize + 8;
for (int i= 0; i < digits.Length; i++) {
if (i < minesLeftSize) {
digits[i].Visibility = Visibility.Visible;
} else {
digits[i].Visibility = Visibility.Hidden;
}
}
int seed = 0;
if (useSeed.IsChecked == true) {
try {
seed = int.Parse(SeedTextBox.Text);
} catch (Exception) {
}
}
//game = new MinesweeperGame(gameDescription, seed);
game = new MinesweeperGame(gameDescription, seed, (hardcore.IsChecked == true));
solverInfo = new SolverInfo(gameDescription, verbose);
RenderMinesLeft();
long start = DateTime.Now.Ticks;
tiles = new ActionResult[gameDescription.width, gameDescription.height];
solverActions = new SolverActionHeader(); // remove any hints from the previous game
Utility.Write("Ticks to build screen " + (DateTime.Now.Ticks - start));
}
// build the graphical part of the board
private void BuildBoard() {
//long start = DateTime.Now.Ticks;
images = new ImageDrawing[boardWidth, boardHeight];
// remove existing tiles from the canvas
gameCanvas.Children.Clear(); // clear game board
imageDrawings = new DrawingGroup();
for (int y = 0; y < boardHeight; y++) {
for (int x = 0; x < boardWidth; x++) {
ActionResult tile = tiles[topX + x, topY + y];
ImageSource imageSource;
if (tile == null) {
imageSource = Hidden;
} else if (tile.resultType == ResultType.Cleared) {
imageSource = MineValue[tile.value];
} else if (tile.resultType == ResultType.Flagged) {
imageSource = Flagged;
} else if (tile.resultType == ResultType.Hidden) {
imageSource = Hidden;
} else if (tile.resultType == ResultType.Exploded) {
imageSource = MineWrong;
} else if (tile.resultType == ResultType.FlaggedWrong) {
imageSource = FlaggedWrong;
} else if (tile.resultType == ResultType.Mine) {
imageSource = Mine;
} else {
imageSource = Hidden;
}
ImageDrawing image = new ImageDrawing() {
ImageSource = imageSource,
Rect = new Rect(x * tileSize, y * tileSize, tileSize, tileSize)
};
imageDrawings.Children.Add(image);
images[x, y] = image;
}
}
totalImage = new Image() {
Source = new DrawingImage(imageDrawings)
};
Canvas.SetLeft(totalImage, 0);
Canvas.SetTop(totalImage, 0);
gameCanvas.Children.Add(totalImage);
// create an empty hints image which we'll use later
hintImage = new Image();
Canvas.SetLeft(hintImage, 0);
Canvas.SetTop(hintImage, 0);
gameCanvas.Children.Add(hintImage);
//Utility.Write("Ticks to build screen " + (DateTime.Now.Ticks - start));
}
private void DoAction(int x, int y, ActionType action) {
//int index = gameDescription.width * y + x;
GameResult result = game.ProcessActions(new GameAction[] { new GameAction(x, y, action) });
Utility.Write("Game controller returned " + result.actionResults.Count + " results from this action");
RenderResults(result); // draw the new board
solverInfo.AddInformation(result); // let the solver know what has happened
if (result.status == GameStatus.Lost) {
MessageLine.Content = "The game is lost!";
} else if (result.status == GameStatus.Won) {
if (game.GetDeaths() != 0) {
MessageLine.Content = "The game is won with " + game.GetDeaths() + " deaths";
} else {
MessageLine.Content = "The game is won";
}
} else {
// if we are showing hints or auto playing then get the hints
if (useSolver || autoRunning) {
AutoPlay(); // let the solver playout the moves
}
}
}
private void DisplayFinalOutcome(GameResult result) {
if (result.status == GameStatus.Lost) {
MessageLine.Content = "The game is lost!";
} else if (result.status == GameStatus.Won) {
if (this.game.GetDeaths() != 0) {
MessageLine.Content = "The game is won with " + game.GetDeaths() + " deaths";
} else {
MessageLine.Content = "The game is won";
}
}
}
private bool IsAutoPlayValid() {
if (!autoRunning) {
//Utility.Write("Autoplay not valid - AutoPlay is not checked");
return false;
}
// if we have no actions then we can't autoplay
if (solverActions.solverActions.Count == 0) {
//Utility.Write("Autoplay not valid - no actions found by the solver");
return false;
}
// if we are accepting guesses then everything goes
if (useGuesses) {
//Utility.Write("Autoplay valid - accepting guesses");
return true;
}
if ((solverActions.solverActions[0].safeProbability > 0 && solverActions.solverActions[0].safeProbability < 1)) {
//Utility.Write("Autoplay not valid - no certain actions found by the solver and we aren't accepting guesses");
return false;
}
//Utility.Write("Autoplay valid - certain actions found by the solver");
return true;
}
// draw the outputs from the Game onto the visible board
private void RenderResults(GameResult result) {
//long start = DateTime.Now.Ticks;
SeedTextBox.Text = game.seed.ToString();
hintImage.Visibility = Visibility.Hidden; // hide the previous hints
foreach (ActionResult ar in result.actionResults) {
// remember what happen here last
tiles[ar.x, ar.y] = ar;
int boardX = ar.x - topX;
int boardY = ar.y - topY;
// if the action is taking place in the part of the board we are looking at
if (boardX >= 0 && boardX < boardWidth && boardY >= 0 && boardY < boardHeight) {
ImageDrawing image = images[boardX, boardY];
if (ar.resultType == ResultType.Cleared) {
image.ImageSource = MineValue[ar.value];
} else if (ar.resultType == ResultType.Flagged) {
image.ImageSource = Flagged;
} else if (ar.resultType == ResultType.Hidden) {
image.ImageSource = Hidden;
} else if (ar.resultType == ResultType.Exploded) {
image.ImageSource = MineWrong;
} else if (ar.resultType == ResultType.FlaggedWrong) {
image.ImageSource = FlaggedWrong;
} else if (ar.resultType == ResultType.Mine) {
image.ImageSource = Mine;
}
}
}
RenderMinesLeft();
//Utility.Write("Ticks to render results " + (DateTime.Now.Ticks - start));
}
// draw the outputs from the Solver onto the visible board
private void RenderHints() {
//long start = DateTime.Now.Ticks;
DrawingGroup hintDrawings = new DrawingGroup();
int offSetLeft = tileSize * (boardWidth + 1);
int offSetTop = tileSize * (boardHeight + 1);
jumpTo = null;
if (this.game.GetGameStatus() == GameStatus.InPlay) {
if (solverActions.solverActions.Count == 0) {
MessageLine.Content = "The solver has no suggestions!";
} else if (solverActions.solverActions.Count > 1) {
MessageLine.Content = "The solver has found " + solverActions.solverActions.Count + " moves.";
} else if (solverActions.solverActions[0].safeProbability > 0 && solverActions.solverActions[0].safeProbability < 1) {
MessageLine.Content = "The solver suggests guessing " + solverActions.solverActions[0].AsText();
jumpTo = solverActions.solverActions[0];
} else {
MessageLine.Content = "The solver has found 1 move.";
}
}
foreach (SolverAction ar in solverActions.solverActions) {
int boardX = ar.x - topX;
int boardY = ar.y - topY;
// if the action is taking place in the part of the board we are looking at
if (boardX >= 0 && boardX < boardWidth && boardY >= 0 && boardY < boardHeight) {
int x = boardX * tileSize;
int y = boardY * tileSize;
if (x < offSetLeft) {
offSetLeft = x;
}
if (y < offSetTop) {
offSetTop = y;
}
Color fill;
if (ar.action == ActionType.Clear) {
if (ar.safeProbability == 1) {
fill = Color.FromArgb(128, 0, 255, 0); // green if safe
} else if (ar.isDead) {
fill = Color.FromArgb(128, 0, 0, 0); // black if excluded
} else {
fill = Color.FromArgb(128, 255, 165, 0); // orange if not safe
}
} else if (ar.action == ActionType.Flag) {
fill = Color.FromArgb(128, 255, 0, 0); // red if a mine
}
GeometryDrawing square =
new GeometryDrawing(
new SolidColorBrush(fill),
new Pen(Brushes.Black, 0),
new RectangleGeometry(new Rect(x, y, tileSize, tileSize))
);
hintDrawings.Children.Add(square);
}
}
// render dead tiles
foreach (SolverAction ar in solverActions.deadActions) {
int boardX = ar.x - topX;
int boardY = ar.y - topY;
// if the action is taking place in the part of the board we are looking at
if (boardX >= 0 && boardX < boardWidth && boardY >= 0 && boardY < boardHeight) {
int x = boardX * tileSize;
int y = boardY * tileSize;
if (x < offSetLeft) {
offSetLeft = x;
}
if (y < offSetTop) {
offSetTop = y;
}
Color fill = Color.FromArgb(128, 0, 0, 0); // black if dead
GeometryDrawing square =
new GeometryDrawing(
new SolidColorBrush(fill),
new Pen(Brushes.Black, 0),
new RectangleGeometry(new Rect(x, y, tileSize, tileSize))
);
hintDrawings.Children.Add(square);
}
}
// replace the old composite hints image with the new
hintImage.Source = new DrawingImage(hintDrawings);
// and place it in the write position
Canvas.SetLeft(hintImage, offSetLeft);
Canvas.SetTop(hintImage, offSetTop);
hintImage.Visibility = Visibility.Visible;
//Utility.Write("Ticks to render hints " + (DateTime.Now.Ticks - start));
}
private void RebuildBoard(int topX, int topY, int boardWidth, int boardHeight) {
this.topX = topX;
this.topY = topY;
this.boardWidth = boardWidth;
this.boardHeight = boardHeight;
// make sure the top position allows enough space to fill the board
if (this.topX + this.boardWidth > gameDescription.width) {
this.topX = gameDescription.width - this.boardWidth;
}
if (this.topY + this.boardHeight > gameDescription.height) {
this.topY = gameDescription.height - this.boardHeight;
}
if (boardWidth > 0 && boardHeight > 0) {
BuildBoard();
RenderHints();
}
}
private void RenderMinesLeft() {
int i = minesLeftSize - 1;
int mines = game.GetMinesLeft();
while (i >= 0) {
int d0 = mines % 10;
mines = (mines - d0) / 10;
digits[i].Source = LedValue[d0];
i--;
}
}
private void CanvasMouseDown(object sender, MouseButtonEventArgs e) {
if (logicalLock) { // this means the solver is playing the game and the user input is ignored
return;
}
int x = (int) e.GetPosition(gameCanvas).X;
int y = (int) e.GetPosition(gameCanvas).Y;
//Utility.Write("Mouse clicked at X=" + x + ", Y=" + y);
int col = x / tileSize;
int row = y / tileSize;
if (col < 0 || col > boardWidth || row < 0 || row > boardHeight) {
Utility.Write("Clicked outside of game boundary col=" + col + ", row=" + row);
return;
}
//Utility.Write("col=" + col + ", row=" + row);
ActionType actionType;
ActionResult tile = tiles[col + topX, row + topY];
if (e.ChangedButton == MouseButton.Left) {
if (tile == null || tile.resultType == ResultType.Hidden) {
actionType = ActionType.Clear;
} else if (tile.resultType == ResultType.Cleared) {
actionType = ActionType.Chord;
} else {
return;
}
} else if (e.ChangedButton == MouseButton.Right) {
actionType = ActionType.Flag;
} else {
return;
}
DoAction(col + topX, row + topY, actionType);
}
private void NewGame() {
InitializeTiles1();
// reposition the display to the top left
//topX = 0;
//topY = 0;
// move the scroll bars back to the start
horizontalScrollbar.Value = 0;
verticalScrollbar.Value = 0;
// work out if scroll bars are need and how big the thumb is
//boardWidth = DoWidth(mainWindow.ActualWidth);
//boardHeight = DoHeight(mainWindow.ActualHeight);
RebuildBoard(0, 0, DoWidth(mainWindow.ActualWidth), DoHeight(mainWindow.ActualHeight));
}
private void BeginnerClick(object sender, RoutedEventArgs e) {
if (zeroStart.IsChecked == true) {
gameDescription = GameDescription.BEGINNER_ZERO;
} else {
gameDescription = GameDescription.BEGINNER_SAFE;
}
NewGame();
}
private void IntermediateClick(object sender, RoutedEventArgs e) {
if (zeroStart.IsChecked == true) {
gameDescription = GameDescription.INTERMEDIATE_ZERO;
} else {
gameDescription = GameDescription.INTERMEDIATE_SAFE;
}
NewGame();
}
private void ExpertClick(object sender, RoutedEventArgs e) {
if (zeroStart.IsChecked == true) {
gameDescription = GameDescription.EXPERT_ZERO;
} else {
gameDescription = GameDescription.EXPERT_SAFE;
}
NewGame();
}
private void CustomClick(object sender, RoutedEventArgs e) {
int gameWidth;
int gameHeight;
int gameMines;
try {
gameWidth = int.Parse(CustomWidth.Text);
} catch (System.Exception) {
gameWidth = 30;
CustomWidth.Text = gameWidth.ToString();
}
try {
gameHeight = int.Parse(CustomHeight.Text);
} catch (System.Exception) {
gameHeight = 16;
CustomHeight.Text = gameHeight.ToString();
}
try {
gameMines = int.Parse(CustomMines.Text);
} catch (System.Exception) {
gameMines = gameWidth * gameHeight / 5;
CustomMines.Text = gameMines.ToString();
}
if (zeroStart.IsChecked == true) {
gameDescription = new GameDescription(gameWidth, gameHeight, gameMines, GameType.Zero);
} else {
gameDescription = new GameDescription(gameWidth, gameHeight, gameMines, GameType.Safe);
}
NewGame();
}
// redraws the controls based on the new width and returns the number of columns we are now able to show
private int DoWidth(double width) {
MessageHolder.Width = Math.Max(0, width - 260);
double boardMax = gameDescription.width * tileSize + 8;
double actualWidth = Math.Max(8, Math.Min(boardMax, width - 260));
int showTilesWidth = (int)Math.Floor((actualWidth - 8) / tileSize);
double boardWidthPixels = showTilesWidth * tileSize + 8; // board is in Whole tiles
BoardHolder.Width = boardWidthPixels;
if (showTilesWidth == gameDescription.width) {
horizontalScrollbar.Visibility = Visibility.Hidden;
} else {
horizontalScrollbar.Visibility = Visibility.Visible;
}
horizontalScrollbar.Width = boardWidthPixels;
horizontalScrollbar.Maximum = (gameDescription.width - showTilesWidth);
horizontalScrollbar.ViewportSize = showTilesWidth;
horizontalScrollbar.LargeChange = showTilesWidth; // scroll bar large scroll is a whole screen
return showTilesWidth;
}
// redraws the controls based on the new height and returns the number of columns we are now able to show
private int DoHeight(double height) {
double boardMax = gameDescription.height * tileSize + 8;
double actualHeight = Math.Max(8, Math.Min(boardMax, height - 140));
int showTilesHeight = (int) Math.Floor((actualHeight - 8) / tileSize);
double boardHeightPixels = showTilesHeight * tileSize + 8; // board is in Whole tiles
BoardHolder.Height = boardHeightPixels;
if (showTilesHeight == gameDescription.height) {
verticalScrollbar.Visibility = Visibility.Hidden;
} else {
verticalScrollbar.Visibility = Visibility.Visible;
}
verticalScrollbar.Height = boardHeightPixels;
verticalScrollbar.Maximum = (gameDescription.height - showTilesHeight);
verticalScrollbar.ViewportSize = showTilesHeight;
verticalScrollbar.LargeChange = showTilesHeight; // scroll bar large scroll is a whole screen
return showTilesHeight;
}
private void RedrawWindow(object sender, SizeChangedEventArgs e) {
//Utility.Write("New width:" + e.NewSize.Width + " height:" + e.NewSize.Height);
int newBoardWidth = boardWidth;
int newBoardHeight = boardHeight;
if (e.WidthChanged == true) {
newBoardWidth = DoWidth(e.NewSize.Width);
}
if (e.HeightChanged == true) {
newBoardHeight = DoHeight(e.NewSize.Height);
}
if (newBoardWidth != this.boardWidth || newBoardHeight != this.boardHeight) {
RebuildBoard(topX, topY, newBoardWidth, newBoardHeight);
}
}
private void VerticalScroll(object sender, System.Windows.Controls.Primitives.ScrollEventArgs e) {
//Utility.Write("Vertical scroll : " + e.NewValue);
int newTopY = (int) Math.Floor(e.NewValue + 0.5d);
if (newTopY != topY) {
RebuildBoard(topX, newTopY, boardWidth, boardHeight);
}
}
private void HorizontalScroll(object sender, System.Windows.Controls.Primitives.ScrollEventArgs e) {
//Utility.Write("Horizontal scroll : " + e.NewValue);
int newTopX = (int)Math.Floor(e.NewValue + 0.5d);
if (newTopX != topX) {
RebuildBoard(newTopX, topY, boardWidth, boardHeight);
}
}
private void MouseMoveOnBoard(object sender, MouseEventArgs e) {
int x = (int)e.GetPosition(gameCanvas).X;
int y = (int)e.GetPosition(gameCanvas).Y;
int col = x / tileSize;
int row = y / tileSize;
if (col < 0 || col > boardWidth || row < 0 || row > boardHeight) {
Utility.Write("Mouse outside of game boundary col=" + col + ", row=" + row);
return;
}
int realCol = col + topX;
int realRow = row + topY;
double prob = solverInfo.GetProbability(realCol, realRow);
string probText;
if (prob == -1) {
probText = "";
} else if (prob == 0) {
probText = "Mine";
} else if (prob == 1) {
probText = "Clear";
} else {
//probText = String.Format("0.00", prob) + " Safe";
probText = (prob * 100).ToString("N2") + "% Safe";
}
popupText.Text = "(" + realCol + "," + realRow + ") " + probText;
gameToolTip.HorizontalOffset = x;
gameToolTip.VerticalOffset = y + 10;
}
private void MouseLeftBoard(object sender, MouseEventArgs e) {
gameToolTip.IsOpen = false;
}
private void MouseEnteredBoard(object sender, MouseEventArgs e) {
gameToolTip.IsOpen = true;
}
private void ClickMessageLine(object sender, MouseButtonEventArgs e) {
if (jumpTo == null) {
return;
}
// set the scroll bars
verticalScrollbar.Value = jumpTo.y - this.boardHeight / 2;
horizontalScrollbar.Value = jumpTo.x - this.boardWidth / 2;
// now see where the scrollbars are
int newTopY = (int)Math.Floor(verticalScrollbar.Value + 0.5d);
int newTopX = (int)Math.Floor(horizontalScrollbar.Value + 0.5d);
// redraw board if we need to
if (newTopY != topY || newTopX != topX) {
RebuildBoard(newTopX, newTopY, boardWidth, boardHeight);
}
}
private void MouseWheelOnBoard(object sender, MouseWheelEventArgs e) {
// if shift is pressed scroll left and right
if ((Keyboard.Modifiers & ModifierKeys.Shift) == ModifierKeys.Shift) {
horizontalScrollbar.Value -= e.Delta / 40;
int newTopX = (int)Math.Floor(horizontalScrollbar.Value + 0.5d);
if (newTopX != topX) {
RebuildBoard(newTopX, topY, boardWidth, boardHeight);
}
return;
}
if ((Keyboard.Modifiers & ModifierKeys.Control) == ModifierKeys.Control) {
return;
}
verticalScrollbar.Value -= e.Delta / 40;
int newTopY = (int)Math.Floor(verticalScrollbar.Value + 0.5d);
if (newTopY != topY) {
RebuildBoard(topX, newTopY, boardWidth, boardHeight);
}
}
private void SetSolverDetails(object sender, RoutedEventArgs e) {
useSolver = (showHInts.IsChecked == true);
autoRunning = (autoPlay.IsChecked == true);
useGuesses = (acceptGuesses.IsChecked == true);
//Console.WriteLine(useSolver + " " + autoRunning + " " + useGuesses);
}
}
}