Last active
August 29, 2019 10:34
-
-
Save MikuroXina/a78132b2dd933c2df1b83be7123e0ccb to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| using System; | |
| using System.Diagnostics; | |
| using System.Linq; | |
| using System.Text.RegularExpressions; | |
| class Cell { | |
| public enum State { | |
| None, | |
| Mine, | |
| } | |
| State state; | |
| public bool Opened { get; private set; } | |
| public bool Flagged { get; private set; } | |
| public int Count = 0; | |
| public Cell(bool isMine) { | |
| state = isMine ? State.Mine : State.None; | |
| Opened = false; | |
| Flagged = false; | |
| } | |
| public bool OpenWhetherMine() { | |
| Opened = true; | |
| Flagged = false; | |
| if (state == State.Mine) { | |
| return true; | |
| } | |
| return false; | |
| } | |
| public void ToggleFlag() { | |
| if (Opened) { return; } | |
| Flagged = !Flagged; | |
| } | |
| public override String ToString() { | |
| if (Opened) { | |
| if (state == State.Mine) { | |
| return "!"; | |
| } | |
| if (0 < Count) { | |
| return Count.ToString(); | |
| } | |
| return " "; | |
| } else if (Flagged) { | |
| return "F"; | |
| } | |
| return "?"; | |
| } | |
| } | |
| class Game { | |
| enum State { | |
| BeforeGame, | |
| Playing, | |
| AfterGame, | |
| } | |
| State state; | |
| Action onClear; | |
| Action onGameOver; | |
| bool[, ] cellsWhetherMine; | |
| public Cell[, ] Cells { get; } | |
| public Game(int width, int height, | |
| Action clear, Action gameOver) { | |
| state = State.BeforeGame; | |
| Cells = new Cell[width, height]; | |
| onClear = clear; | |
| onGameOver = gameOver; | |
| var gen = new Random(); | |
| cellsWhetherMine = new bool[width, height]; | |
| for (int y = 0; y < height; ++y) { | |
| for (int x = 0; x < width; ++x) { | |
| var isMine = gen.Next(6) == 1; | |
| Cells[x, y] = new Cell(isMine); | |
| cellsWhetherMine[x, y] = isMine; | |
| } | |
| } | |
| (int, int) [] offsets = { | |
| (-1, -1), | |
| (-1, 0), | |
| (-1, 1), | |
| (0, -1), | |
| (0, 1), | |
| (1, -1), | |
| (1, 0), | |
| (1, 1) | |
| }; | |
| for (int y = 0; y < height; ++y) { | |
| for (int x = 0; x < width; ++x) { | |
| var countAroundMines = 0; | |
| foreach (var(offestX, offsetY) in offsets) { | |
| if (!(0 <= x + offestX && x + offestX < width && 0 <= y + offsetY && y + offsetY < height)) { continue; } | |
| if (cellsWhetherMine[x + offestX, y + offsetY]) { | |
| ++countAroundMines; | |
| } | |
| } | |
| Cells[x, y].Count = countAroundMines; | |
| } | |
| } | |
| } | |
| void CheckIfCleared() { | |
| for (int y = 0; y < Cells.GetLength(1); ++y) { | |
| for (int x = 0; x < Cells.GetLength(0); ++x) { | |
| if (Cells[x, y].Flagged && !cellsWhetherMine[x, y] || !Cells[x, y].Flagged && cellsWhetherMine[x, y]) { return; } | |
| } | |
| } | |
| state = State.AfterGame; | |
| onClear(); | |
| } | |
| public void Start() { | |
| if (state != State.BeforeGame) { return; } | |
| state = State.Playing; | |
| } | |
| public void OpenCell(int x, int y) { | |
| if (!(0 <= x && x < Cells.GetLength(0) && 0 <= y && y < Cells.GetLength(1))) { return; } | |
| if (state != State.Playing || Cells[x, y].Flagged || Cells[x, y].Opened) { return; } | |
| if (Cells[x, y].OpenWhetherMine()) { | |
| state = State.AfterGame; | |
| onGameOver(); | |
| return; | |
| } | |
| if (Cells[x, y].Count == 0) { | |
| OpenCell(x - 1, y); | |
| OpenCell(x, y - 1); | |
| OpenCell(x - 1, y - 1); | |
| OpenCell(x + 1, y); | |
| OpenCell(x, y + 1); | |
| OpenCell(x + 1, y + 1); | |
| OpenCell(x + 1, y - 1); | |
| OpenCell(x - 1, y + 1); | |
| } | |
| } | |
| public void FlagCell(int x, int y) { | |
| if (!(0 <= x && x < Cells.GetLength(0) && 0 <= y && y < Cells.GetLength(1))) { return; } | |
| if (state != State.Playing) { return; } | |
| Cells[x, y].ToggleFlag(); | |
| CheckIfCleared(); | |
| } | |
| } | |
| class GameView { | |
| enum Mode { | |
| Flag, | |
| Open, | |
| } | |
| Mode mode; | |
| Game game; | |
| Stopwatch sw; | |
| bool playing = true; | |
| public GameView() { | |
| game = new Game(10, 10, this.Clear, this.GameOver); | |
| mode = Mode.Open; | |
| sw = new Stopwatch(); | |
| } | |
| void Clear() { | |
| sw.Stop(); | |
| FlushScreen(); | |
| var ts = sw.Elapsed; | |
| Console.WriteLine("クリア! {0:00}:{1:00}", ts.Minutes, ts.Seconds); | |
| playing = false; | |
| } | |
| void GameOver() { | |
| sw.Stop(); | |
| FlushScreen(); | |
| Console.WriteLine("ゲームオーバー……"); | |
| playing = false; | |
| } | |
| void StartGame() { | |
| game.Start(); | |
| sw.Start(); | |
| } | |
| void AskCommand() { | |
| Console.WriteLine("コマンドを入力してね | F/f - フラグ立てモード | T/t - マス開けモード | 数字,数字 - 座標に今のモードを実行"); | |
| string command = Console.ReadLine(); | |
| if (command == "f" || command == "F") { | |
| mode = Mode.Flag; | |
| return; | |
| } else if (command == "T" || command == "t") { | |
| mode = Mode.Open; | |
| return; | |
| } | |
| var match = Regex.Match(command, @"(?<x>\d+).*,.*(?<y>\d+)"); | |
| if (match.Success) { | |
| try { | |
| var x = int.Parse(match.Groups["x"].Value); | |
| var y = int.Parse(match.Groups["y"].Value); | |
| if (mode == Mode.Flag) { | |
| game.FlagCell(x, y); | |
| } else { | |
| game.OpenCell(x, y); | |
| } | |
| } catch (FormatException ignore) { } | |
| } | |
| } | |
| void FlushScreen() { | |
| Console.Clear(); | |
| var cells = game.Cells; | |
| var line = " " + string.Concat(Enumerable.Repeat("-", cells.GetLength(0) * 4 + 1)); | |
| Console.Write(" "); | |
| for (int x = 0; x < cells.GetLength(0); ++x) { | |
| Console.Write(" {0} ", x); | |
| } | |
| Console.WriteLine(""); | |
| for (int y = 0; y < cells.GetLength(1); ++y) { | |
| Console.WriteLine(line); | |
| Console.Write(" {0} |", y); | |
| for (int x = 0; x < cells.GetLength(0); ++x) { | |
| Console.Write(" {0} |", cells[x, y].ToString()); | |
| } | |
| Console.WriteLine(); | |
| } | |
| Console.WriteLine(line); | |
| var ts = sw.Elapsed; | |
| Console.WriteLine("- {0}モード - {1:00}:{2:00}", (mode == Mode.Flag ? "フラグ立て" : "マス開け"), ts.Minutes, ts.Seconds); | |
| } | |
| public void Run() { | |
| StartGame(); | |
| while (playing) { | |
| FlushScreen(); | |
| AskCommand(); | |
| } | |
| } | |
| } | |
| class MineSweeper { | |
| static int Main() { | |
| var view = new GameView(); | |
| view.Run(); | |
| return 0; | |
| } | |
| } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment