public List <List <Glyph> > Render(bool showMines = false) { var boardLines = new List <List <Glyph> >(); //construct the top and bottom legends and borders var yLegendPad = Height > 9 ? " " : " "; //when the height reaches double digits more padding is needed var xLegendLine = Utils.StringToLine(yLegendPad + " "); var xLegendBorderCenter = new List <Glyph>(); var xLegendBorderTop = Utils.StringToLine(yLegendPad + "┌──┐", ConsoleColor.Blue); var xLegendBorderBottom = Utils.StringToLine(yLegendPad + "└──┘", ConsoleColor.Blue); for (int i = 0; i < Width; i++) { //generate horizontal A/B/C etc legend markers and border, changing colour if player is on this column xLegendLine.AddRange(Utils.StringToLine(Utils.GetXLegendValue(i) + " ", _Player.PositionX == i ? ConsoleColor.Red : ConsoleColor.White)); xLegendBorderCenter.AddRange(Utils.StringToLine("──", ConsoleColor.Blue)); } //2 gets us into the ┌──┐ space xLegendBorderTop.InsertRange(yLegendPad.Length + 2, xLegendBorderCenter); xLegendBorderBottom.InsertRange(yLegendPad.Length + 2, xLegendBorderCenter); //add the top legend lines boardLines.Add(xLegendLine); boardLines.Add(xLegendBorderTop); //generate mine field lines remembering that we loop the rows first since we're printing glyphs left to right one line at a time for (int y = Height - 1; y >= 0; y--) { int lineNum = y + 1; string legendPad = Height > 9 && lineNum <= 9 ? " " : ""; //correct padding depending on if this is a double digit row //create a new line starting with the the legend, switching colours if the player is on this row var line = new List <Glyph>() { new Glyph(legendPad + lineNum.ToString(), _Player.PositionY == y ? ConsoleColor.Red : ConsoleColor.White), new Glyph(' '), new Glyph('│', ConsoleColor.Blue), new Glyph(' '), }; //loop the columns for (int x = 0; x < Width; x++) { //display the player icon or mine field square as necessary if (_Player.PositionX == x && _Player.PositionY == y) { line.Add(new Glyph(_Output.EmojiSupport ? "⛵️" : "|>")); } else { //show a mine location only if required (e.g. game is over) var square = GetSquare(x, y); if (square == Enums.SquareStatus.Mine && !showMines) { square = Enums.SquareStatus.Safe; } line.Add(new Glyph(_Output.ConvertGameSquareToGlyphValue(square))); } } //finish the line with the legend line.Add(new Glyph(' ')); line.Add(new Glyph('│', ConsoleColor.Blue)); line.Add(new Glyph(' ')); line.Add(new Glyph(lineNum.ToString(), _Player.PositionY == y ? ConsoleColor.Red : ConsoleColor.White)); boardLines.Add(line); } //add the bottom legend to the board boardLines.Add(xLegendBorderBottom); boardLines.Add(xLegendLine); return(boardLines); }
public void RenderToOutput() { var gameLines = new List <List <Glyph> >(); var gameTitle = $"{_Output.ConvertGameSquareToGlyphValue(Enums.SquareStatus.Mine)} Welcome to {_GameTitle} {_Output.ConvertGameSquareToGlyphValue(Enums.SquareStatus.Mine)}"; var padding = (_Output.WindowWidth - gameTitle.Length) / 2; //insert the main heading gameLines.Insert(0, new List <Glyph>()); gameLines.Insert(1, Utils.StringToLine(new StringBuilder().Append(' ', padding).Append(gameTitle).ToString(), ConsoleColor.Red)); gameLines.Insert(2, Utils.StringToLine(new StringBuilder().Append(' ', padding - 1).Append('═', gameTitle.Length + 2).ToString(), ConsoleColor.Red)); gameLines.Insert(3, new List <Glyph>()); //generate the board var boardLines = _Board.Render(State == Enums.GameState.Loser || State == Enums.GameState.Winner); //generate the status/info lines to sit beside the board var info = new List <string>() { "Navigate from West to East using the arrow keys", "Watch out for the mines!", "", State == Enums.GameState.DifficultySelect ? "Select difficulty: [E]asy / [M]edium / [H]ard" : State == Enums.GameState.StartPositionSelect ? "Enter start row number and press ENTER:" : State == Enums.GameState.Loser || State == Enums.GameState.Winner ? "Press R to reset, ESC to quit" : "", "", State == Enums.GameState.StartPositionSelect ? _DesiredStartPosition : "", State == Enums.GameState.Loser ? "GAME OVER" : State == Enums.GameState.Winner ? $"CONGRATULATIONS, YOU MADE IT!" : State == Enums.GameState.FreeMovement ? $"Position: {Utils.GetXLegendValue(_Player.PositionX)}{_Player.PositionY + 1}" : "", State != Enums.GameState.Loser && State != Enums.GameState.Winner ? $"Lives remaining: {LivesRemaining}" : "", State != Enums.GameState.DifficultySelect ? $"Moves made: {MoveCounter}" : "" }; //board should be positioned to the right of the screen so the lhs has space for status and instructions var boardWidth = boardLines.First().Count; padding = (_Output.WindowWidth - boardWidth) - 10; //10 cols of safety margin //create the default padding used for board lines without any info/status text var defaultPadder = new StringBuilder().Append(' ', padding).ToString(); var infoStartLine = (boardLines.Count - info.Count) / 2; //positions the info/status block roughly in the middle of the board height //merge our status/info lines with the board lines for (int i = 0; i < boardLines.Count - 1; i++) { var linePrepend = defaultPadder; //check we're in an appropriate place in the board lines array and build the status/info padded string if (i >= infoStartLine && i - infoStartLine < info.Count) { linePrepend = BuildBoardLinePrependString(info[i - infoStartLine], padding); } //insert the status/info line into the list of chars for this board line boardLines[i].InsertRange(0, Utils.StringToLine(linePrepend)); } //add the board into the overall output array gameLines.AddRange(boardLines); //clear the display and print out each line of the game _Output.Clear(); foreach (var line in gameLines) { foreach (var chr in line) { _Output.RenderSingle(chr); } _Output.Flush(); } _Output.SetGameDefaultColors(); }