原文地址:https://www.cnblogs.com/jingjiangtao/p/14766049.html
效果
文章最后有完整代碼,以下是逐步實現。
准備工作
要在控制台上繪制出數字,可以將控制台看作一個網格,在網格中填充顏色就可以顯示不同的數字。首先在excel中做一個網格來確定大小和坐標:
可以看到,畫布大小是 41 x 11,組成每個數字的網格也都標出了坐標,程序中需要繪制數字時只需要參照這個excel網格就行了。
關於如何將excel的表格修改成正方形,可以參考這篇博客:使用Excel在圖片上添加正方形網格線_zy_like_study的博客-CSDN博客_圖片添加網格線
開始編寫代碼
創建網格
新建一個 .net 5 控制台項目。因為功能簡單,所以就直接在默認的Program類中用靜態函數實現了。
首先要定義一個 41 x 11 的網格用來展示數字。新建一個類 Cell 表示網格中的每一個格子,Value屬性表示這個格子是否激活,true為激活,false為未激活。
public class Cell { public bool Value { get; set; } }
接下來要定義網格,可以用一個二維數組來表示,數組的類型就是上面定義的Cell。將這個二維數組定義為類的靜態變量,就可以在類的靜態函數中使用。
private static Cell[,] grid = new Cell[11, 41];
定義完成之后需要初始化網格,對二維數組中的類型進行實例化。Init() 函數遍歷網格數組,實例化每個格子,並顯式將Value設為false
private static void Init() { for (int i = 0; i < grid.GetLength(0); i++) { for (int j = 0; j < grid.GetLength(1); j++) { grid[i, j] = new Cell(); grid[i, j].Value = false; } } }
在控制台上顯示網格
現在有了數據,接下來就要將數據展示在控制台上。update() 函數遍歷網格數組,判斷每個格子的Value值,如果為true,就將格子設為白色,如果為false,就將格子設為黑色,其中白色表示激活,黑色表示未激活。
private static void Update() { for (int i = 0; i < grid.GetLength(0); i++) { for (int j = 0; j < grid.GetLength(1); j++) { if (grid[i, j].Value) { SetWhite(i, j); } else { SetBlack(i, j); } } } }
SetWhite()函數和SetBlack()函數調用了C#控制台的接口,將指定位置的背景設為指定顏色。
private static void SetWhite(int i, int j) { string fill = " "; // 兩個空格 Console.SetCursorPosition(j * fill.Length, i); Console.BackgroundColor = ConsoleColor.White; Console.Write(fill); } private static void SetBlack(int i, int j) { string fill = " "; // 兩個空格 Console.SetCursorPosition(j * fill.Length, i); Console.BackgroundColor = ConsoleColor.Black; Console.Write(fill); }
至此,網格的創建和顯示就完成了,不過這兩個函數還沒有被調用。
在網格上繪制數字
現在網格可以通過update()函數顯示到控制台上了,接下來就可以對照那張excel表繪制指定的數字了。我用的這個繪制數字的方式是比較笨的,沒有想出來更好的辦法,如果有,歡迎在評論區指出。
繪制的基本方法就是把組成數字的格子設成白色,沒有數字的格子設成黑色,0到9一共10個數字全都繪制一遍。
先是一個枚舉,表示要繪制的數字開始的列,其中HourFirst表示“小時”的十位,開始於網格第1列,HourSecond表示“小時”的個位,開始於網格的第7列,依此類推。
public enum NumberLocation { HourFirst = 1, HourSecond = 7, MinuteFirst = 15, MinuteSecond = 21, SecondFirst = 29, SecondSecond = 35, }
下面是繪制代碼,因為太長就默認折疊了。其中TraverseNumber函數就是為了復用二重循環。DisplayNumber函數根據每個數字的坐標設置格子的Value值,location參數表示要顯示數字的列位置,接收一個枚舉,比如 DisplayNumber(3, NumberLocation.HourFirst) 表示“小時”的十位是3。

private static void DisplayNumber(int number, NumberLocation location) { int colOffset = (int)location; switch (number) { case 0: TraverseNumber(colOffset, (i, j) => { if (i == 1 || i == 9) { grid[i, j].Value = true; return; } if (i == 2 || i == 3 || i == 4 || i == 5 || i == 6 || i == 7 || i == 8) { if (j == colOffset || j == colOffset + 4) { grid[i, j].Value = true; return; } } grid[i, j].Value = false; }); break; case 1: TraverseNumber(colOffset, (i, j) => { if (j == colOffset + 4) { grid[i, j].Value = true; return; } grid[i, j].Value = false; }); break; case 2: TraverseNumber(colOffset, (i, j) => { if (i == 1 || i == 5 || i == 9) { grid[i, j].Value = true; return; } if (i == 2 || i == 3 || i == 4) { if (j == colOffset + 4) { grid[i, j].Value = true; return; } } if (i == 6 || i == 7 || i == 8) { if (j == colOffset) { grid[i, j].Value = true; return; } } grid[i, j].Value = false; }); break; case 3: TraverseNumber(colOffset, (i, j) => { if (i == 1 || i == 5 || i == 9) { grid[i, j].Value = true; return; } if (i == 2 || i == 3 || i == 4 || i == 6 || i == 7 || i == 8) { if (j == colOffset + 4) { grid[i, j].Value = true; return; } } grid[i, j].Value = false; }); break; case 4: TraverseNumber(colOffset, (i, j) => { if (i == 5) { grid[i, j].Value = true; return; } if (i == 1 || i == 2 || i == 3 || i == 4) { if (j == colOffset || j == colOffset + 4) { grid[i, j].Value = true; return; } } if (i == 6 || i == 7 || i == 8 || i == 9) { if (j == colOffset + 4) { grid[i, j].Value = true; return; } } grid[i, j].Value = false; }); break; case 5: TraverseNumber(colOffset, (i, j) => { if (i == 1 || i == 5 || i == 9) { grid[i, j].Value = true; return; } if (i == 2 || i == 3 || i == 4) { if (j == colOffset) { grid[i, j].Value = true; return; } } if (i == 6 || i == 7 || i == 8) { if (j == colOffset + 4) { grid[i, j].Value = true; return; } } grid[i, j].Value = false; }); break; case 6: TraverseNumber(colOffset, (i, j) => { if (i == 1 || i == 5 || i == 9) { grid[i, j].Value = true; return; } if (i == 2 || i == 3 || i == 4) { if (j == colOffset) { grid[i, j].Value = true; return; } } if (i == 6 || i == 7 || i == 8) { if (j == colOffset || j == colOffset + 4) { grid[i, j].Value = true; return; } } grid[i, j].Value = false; }); break; case 7: TraverseNumber(colOffset, (i, j) => { if (i == 1) { grid[i, j].Value = true; return; } if (i == 2 || i == 3 || i == 4 || i == 5 || i == 6 || i == 7 || i == 8 || i == 9) { if (j == colOffset + 4) { grid[i, j].Value = true; return; } } grid[i, j].Value = false; }); break; case 8: TraverseNumber(colOffset, (i, j) => { if (i == 1 || i == 5 || i == 9) { grid[i, j].Value = true; return; } if (i == 2 || i == 3 || i == 4 || i == 6 || i == 7 || i == 8) { if (j == colOffset || j == colOffset + 4) { grid[i, j].Value = true; return; } } grid[i, j].Value = false; }); break; case 9: TraverseNumber(colOffset, (i, j) => { if (i == 1 || i == 5 || i == 9) { grid[i, j].Value = true; return; } if (i == 2 || i == 3 || i == 4) { if (j == colOffset || j == colOffset + 4) { grid[i, j].Value = true; return; } } if (i == 6 || i == 7 || i == 8) { if (j == colOffset + 4) { grid[i, j].Value = true; return; } } grid[i, j].Value = false; }); break; } }
利用這個函數,就可以在控制台上顯示數字了,修改Main函數:
static void Main(string[] args) { Init(); DisplayNumber(1, NumberLocation.HourFirst); DisplayNumber(2, NumberLocation.HourSecond); DisplayNumber(3, NumberLocation.MinuteFirst); DisplayNumber(4, NumberLocation.MinuteSecond); DisplayNumber(5, NumberLocation.SecondFirst); DisplayNumber(6, NumberLocation.SecondSecond); Update(); }
但是現在只有數字,沒有分隔 小時 : 分鍾 : 秒 的那兩個小點。接下來繪制分隔點。首先定義枚舉類,確定分隔點所在的列:
public enum DotLocation { First = 13, Second = 27 }
然后顯示分隔點:
private static void ShowAllDot() { int firstCol = (int)DotLocation.First; int secondCol = (int)DotLocation.Second; grid[3, firstCol].Value = true; SetWhite(3, firstCol); grid[7, firstCol].Value = true; SetWhite(7, firstCol); grid[3, secondCol].Value = true; SetWhite(3, secondCol); grid[7, secondCol].Value = true; SetWhite(7, secondCol); }
在Main函數中調用:
static void Main(string[] args) { Init(); DisplayNumber(1, NumberLocation.HourFirst); DisplayNumber(2, NumberLocation.HourSecond); DisplayNumber(3, NumberLocation.MinuteFirst); DisplayNumber(4, NumberLocation.MinuteSecond); DisplayNumber(5, NumberLocation.SecondFirst); DisplayNumber(6, NumberLocation.SecondSecond); ShowAllDot(); Update(); }
運行看效果:
至此,數字和分隔點可以正常顯示了。
開始倒計時
完成了設置數據和顯示數據的功能,就可以開始實現倒計時功能了。實現倒計時需要計時庫,C#提供了Stopwatch用來精確計時,我們就用這個類。
一開始先把倒計時的時間硬編碼,比如倒計時70秒,完成主要功能后再考慮讓用戶輸入。LeftTime函數將倒計時的總時間和經過的時間相減,再調用DisplayNumber修改網格的值。
修改Main函數。Main函數定義了倒計時時間,初始化網格,再定義Stopwatch變量,之后是一個無限循環。循環過程中用Stopwatch計時,如果經過時間大於倒計時總時間,則說明計時時間到。每次循環都調用Update函數來顯示數字:
static void Main(string[] args) { int countdownSec = 70; Init(); Stopwatch stopwatch = null; while (true) { if (stopwatch == null) { stopwatch = Stopwatch.StartNew(); } // 時間到 if (stopwatch != null && stopwatch.Elapsed.TotalSeconds > countdownSec) { LeftTime(countdownSec, countdownSec); stopwatch.Stop(); stopwatch = null; } else { LeftTime(countdownSec, (int)stopwatch.Elapsed.TotalSeconds); } Update(); } } private static void LeftTime(int countdownSec, int elapsedSec) { var timeLeft = TimeSpan.FromSeconds(countdownSec - elapsedSec); DisplayNumber(timeLeft.Hours / 10, NumberLocation.HourFirst); DisplayNumber(timeLeft.Hours % 10, NumberLocation.HourSecond); DisplayNumber(timeLeft.Minutes / 10, NumberLocation.MinuteFirst); DisplayNumber(timeLeft.Minutes % 10, NumberLocation.MinuteSecond); DisplayNumber(timeLeft.Seconds / 10, NumberLocation.SecondFirst); DisplayNumber(timeLeft.Seconds % 10, NumberLocation.SecondSecond); }
運行一下:
可以看到計時器開始正常運行了。但是發現了一個問題,沒有分隔點。分隔點都是閃爍的,不是靜止的,所以需要添加一個切換分隔點狀態的函數,每次調用這個函數,分隔點都會切換顯示或隱藏的狀態:
private static void SwitchDot(DotLocation location) { int colOffset = (int)location; if (grid[3, colOffset].Value) { grid[3, colOffset].Value = false; SetBlack(3, colOffset); } else { grid[3, colOffset].Value = true; SetWhite(3, colOffset); } if (grid[7, colOffset].Value) { grid[7, colOffset].Value = false; SetBlack(7, colOffset); } else { grid[7, colOffset].Value = true; SetWhite(7, colOffset); } }
可以讓分隔點每500ms切換一次狀態,方法和倒計時的方法相同。為了不讓分隔點的計算影響倒計時的計算,需要單獨開一個線程。這里用Thread開線程,也可以用Task.Run開線程。修改Main函數:
static void Main(string[] args) { int countdownSec = 70; Init(); Thread dotThread = new Thread(() => { ShowAllDot(); Stopwatch dotWatch = null; while (true) { if (dotWatch == null) { dotWatch = Stopwatch.StartNew(); } if (dotWatch.ElapsedMilliseconds >= 500) { SwitchDot(DotLocation.First); SwitchDot(DotLocation.Second); dotWatch.Stop(); dotWatch = null; } } }); dotThread.Start(); Stopwatch stopwatch = null; while (true) { if (stopwatch == null) { stopwatch = Stopwatch.StartNew(); } // 時間到 if (stopwatch != null && stopwatch.Elapsed.TotalSeconds > countdownSec) { LeftTime(countdownSec, countdownSec); stopwatch.Stop(); stopwatch = null; } else { LeftTime(countdownSec, (int)stopwatch.Elapsed.TotalSeconds); } Update(); } }
運行一下:
可以看到分隔點閃爍起來了。
但是現在的這個計時器不會停止,等計時完成后會重新開始,所以我們要讓計時完成時停止計時,並讓分隔點靜止。設置一個bool變量isCounting表示是否正在計時,為true表示正在計時,為false表示計時完畢。
修改Main函數:
static void Main(string[] args) { int countdownSec = 5; Init(); bool isCounting = true; Thread dotThread = new Thread(() => { ShowAllDot(); Stopwatch dotWatch = null; while (true) { if (dotWatch == null && isCounting) { dotWatch = Stopwatch.StartNew(); } if (isCounting && dotWatch.ElapsedMilliseconds >= 500) { SwitchDot(DotLocation.First); SwitchDot(DotLocation.Second); dotWatch.Stop(); dotWatch = null; } } }); dotThread.Start(); Stopwatch stopwatch = null; while (true) { if (stopwatch == null && isCounting) { stopwatch = Stopwatch.StartNew(); } // 時間到 if (stopwatch != null && stopwatch.Elapsed.TotalSeconds > countdownSec) { LeftTime(countdownSec, countdownSec); ShowAllDot(); stopwatch.Stop(); stopwatch = null; isCounting = false; } else if(isCounting) { LeftTime(countdownSec, (int)stopwatch.Elapsed.TotalSeconds); } Update(); } }
為了盡快看到效果,把計時總時間改為5秒。運行一下:
可以看到計時完成之后數字不再改變,分隔點也靜止了。
至此,倒計時的主要功能就完成了。
用戶輸入
作為一個倒計時工具,把倒計時時間硬編碼肯定是不行的,需要讓用戶輸入,還有退出倒計時頁面、隱藏游標等功能。修改Main函數:
static void Main(string[] args) { while (true) { Console.Clear(); Console.CursorVisible = true; bool isQuit = false; bool isCounting = false; int countdownSec = 0; while (true) { Console.Write("Input Countdown Seconds: "); string countdownSecStr = Console.ReadLine(); if (int.TryParse(countdownSecStr, out countdownSec)) { break; } } Init(); Console.CursorVisible = false; isCounting = true; Thread dotThread = new Thread(() => { ShowAllDot(); Stopwatch dotWatch = null; while (true) { if (isQuit) { break; } if (dotWatch == null && isCounting) { dotWatch = Stopwatch.StartNew(); } if (isCounting && dotWatch.ElapsedMilliseconds >= 500) { SwitchDot(DotLocation.First); SwitchDot(DotLocation.Second); dotWatch.Stop(); dotWatch = null; } } }); dotThread.Start(); Thread quitThread = new Thread(() => { ConsoleKeyInfo key = Console.ReadKey(); if (key.Key == ConsoleKey.Q) { isQuit = true; } }); quitThread.Start(); Stopwatch stopwatch = null; while (true) { if (isQuit) { break; } if (stopwatch == null && isCounting) { stopwatch = Stopwatch.StartNew(); } // 時間到 if (stopwatch != null && stopwatch.Elapsed.TotalSeconds > countdownSec) { LeftTime(countdownSec, countdownSec); ShowAllDot(); stopwatch.Stop(); stopwatch = null; isCounting = false; } else if (isCounting) { LeftTime(countdownSec, (int)stopwatch.Elapsed.TotalSeconds); } Update(); Console.WriteLine("\n Press q to quit"); } } }
最外層是一個無限循環,以保證程序不會自己退出。循環剛開始就接收用戶輸入的以秒為單位的總時間,之后初始化網格,隱藏游標,設置標志變量,開啟線程等。quitThread線程監聽用戶是否按了q鍵,是就退出倒計時頁面,返回到輸入頁面。
完整代碼
完整代碼將Main函數中的所有操作提取到了Countdown函數中,Main函數調用Countdown函數。
using System; using System.Diagnostics; using System.Threading; using System.Threading.Tasks; namespace Countdown { class Program { private static Cell[,] grid = new Cell[11, 41]; static void Main(string[] args) { Countdown(); } private static void Countdown() { while (true) { Console.Clear(); Console.CursorVisible = true; bool isQuit = false; bool isCounting = false; int countdownSec = 0; while (true) { Console.Write("Input Countdown Seconds: "); string countdownSecStr = Console.ReadLine(); if (int.TryParse(countdownSecStr, out countdownSec)) { if (countdownSec > 86400) { continue; } break; } } Init(); Console.CursorVisible = false; isCounting = true; Thread dotThread = new Thread(() => { ShowAllDot(); Stopwatch dotWatch = null; while (true) { if (isQuit) { break; } if (dotWatch == null && isCounting) { dotWatch = Stopwatch.StartNew(); } if (isCounting && dotWatch.ElapsedMilliseconds >= 500) { SwitchDot(DotLocation.First); SwitchDot(DotLocation.Second); dotWatch.Stop(); dotWatch = null; } } }); dotThread.Start(); Thread quitThread = new Thread(() => { ConsoleKeyInfo key = Console.ReadKey(); if (key.Key == ConsoleKey.Q) { isQuit = true; } }); quitThread.Start(); Stopwatch stopwatch = null; while (true) { if (isQuit) { break; } if (stopwatch == null && isCounting) { stopwatch = Stopwatch.StartNew(); } // 時間到 if (stopwatch != null && stopwatch.Elapsed.TotalSeconds > countdownSec) { LeftTime(countdownSec, countdownSec); ShowAllDot(); stopwatch.Stop(); stopwatch = null; isCounting = false; } else if (isCounting) { LeftTime(countdownSec, (int)stopwatch.Elapsed.TotalSeconds); } Update(); Console.WriteLine("\n Press q to quit"); } } } private static void LeftTime(int countdownSec, int elapsedSec) { var timeLeft = TimeSpan.FromSeconds(countdownSec - elapsedSec); DisplayNumber(timeLeft.Hours / 10, NumberLocation.HourFirst); DisplayNumber(timeLeft.Hours % 10, NumberLocation.HourSecond); DisplayNumber(timeLeft.Minutes / 10, NumberLocation.MinuteFirst); DisplayNumber(timeLeft.Minutes % 10, NumberLocation.MinuteSecond); DisplayNumber(timeLeft.Seconds / 10, NumberLocation.SecondFirst); DisplayNumber(timeLeft.Seconds % 10, NumberLocation.SecondSecond); } private static void Init() { for (int i = 0; i < grid.GetLength(0); i++) { for (int j = 0; j < grid.GetLength(1); j++) { grid[i, j] = new Cell(); grid[i, j].Value = false; } } } private static void Update() { for (int i = 0; i < grid.GetLength(0); i++) { for (int j = 0; j < grid.GetLength(1); j++) { if (grid[i, j].Value) { SetWhite(i, j); } else { SetBlack(i, j); } } } } private static void SetWhite(int i, int j) { string fill = " "; Console.SetCursorPosition(j * fill.Length, i); Console.BackgroundColor = ConsoleColor.White; Console.Write(fill); } private static void SetBlack(int i, int j) { string fill = " "; Console.SetCursorPosition(j * fill.Length, i); Console.BackgroundColor = ConsoleColor.Black; Console.Write(fill); } private static void DisplayNumber(int number, NumberLocation location) { int colOffset = (int)location; switch (number) { case 0: TraverseNumber(colOffset, (i, j) => { if (i == 1 || i == 9) { grid[i, j].Value = true; return; } if (i == 2 || i == 3 || i == 4 || i == 5 || i == 6 || i == 7 || i == 8) { if (j == colOffset || j == colOffset + 4) { grid[i, j].Value = true; return; } } grid[i, j].Value = false; }); break; case 1: TraverseNumber(colOffset, (i, j) => { if (j == colOffset + 4) { grid[i, j].Value = true; return; } grid[i, j].Value = false; }); break; case 2: TraverseNumber(colOffset, (i, j) => { if (i == 1 || i == 5 || i == 9) { grid[i, j].Value = true; return; } if (i == 2 || i == 3 || i == 4) { if (j == colOffset + 4) { grid[i, j].Value = true; return; } } if (i == 6 || i == 7 || i == 8) { if (j == colOffset) { grid[i, j].Value = true; return; } } grid[i, j].Value = false; }); break; case 3: TraverseNumber(colOffset, (i, j) => { if (i == 1 || i == 5 || i == 9) { grid[i, j].Value = true; return; } if (i == 2 || i == 3 || i == 4 || i == 6 || i == 7 || i == 8) { if (j == colOffset + 4) { grid[i, j].Value = true; return; } } grid[i, j].Value = false; }); break; case 4: TraverseNumber(colOffset, (i, j) => { if (i == 5) { grid[i, j].Value = true; return; } if (i == 1 || i == 2 || i == 3 || i == 4) { if (j == colOffset || j == colOffset + 4) { grid[i, j].Value = true; return; } } if (i == 6 || i == 7 || i == 8 || i == 9) { if (j == colOffset + 4) { grid[i, j].Value = true; return; } } grid[i, j].Value = false; }); break; case 5: TraverseNumber(colOffset, (i, j) => { if (i == 1 || i == 5 || i == 9) { grid[i, j].Value = true; return; } if (i == 2 || i == 3 || i == 4) { if (j == colOffset) { grid[i, j].Value = true; return; } } if (i == 6 || i == 7 || i == 8) { if (j == colOffset + 4) { grid[i, j].Value = true; return; } } grid[i, j].Value = false; }); break; case 6: TraverseNumber(colOffset, (i, j) => { if (i == 1 || i == 5 || i == 9) { grid[i, j].Value = true; return; } if (i == 2 || i == 3 || i == 4) { if (j == colOffset) { grid[i, j].Value = true; return; } } if (i == 6 || i == 7 || i == 8) { if (j == colOffset || j == colOffset + 4) { grid[i, j].Value = true; return; } } grid[i, j].Value = false; }); break; case 7: TraverseNumber(colOffset, (i, j) => { if (i == 1) { grid[i, j].Value = true; return; } if (i == 2 || i == 3 || i == 4 || i == 5 || i == 6 || i == 7 || i == 8 || i == 9) { if (j == colOffset + 4) { grid[i, j].Value = true; return; } } grid[i, j].Value = false; }); break; case 8: TraverseNumber(colOffset, (i, j) => { if (i == 1 || i == 5 || i == 9) { grid[i, j].Value = true; return; } if (i == 2 || i == 3 || i == 4 || i == 6 || i == 7 || i == 8) { if (j == colOffset || j == colOffset + 4) { grid[i, j].Value = true; return; } } grid[i, j].Value = false; }); break; case 9: TraverseNumber(colOffset, (i, j) => { if (i == 1 || i == 5 || i == 9) { grid[i, j].Value = true; return; } if (i == 2 || i == 3 || i == 4) { if (j == colOffset || j == colOffset + 4) { grid[i, j].Value = true; return; } } if (i == 6 || i == 7 || i == 8) { if (j == colOffset + 4) { grid[i, j].Value = true; return; } } grid[i, j].Value = false; }); break; } } private static void TraverseNumber(int colOffset, Action<int, int> action) { for (int i = 1; i < 10; i++) { for (int j = colOffset; j < colOffset + 5; j++) { action(i, j); } } } private static void SwitchDot(DotLocation location) { int colOffset = (int)location; if (grid[3, colOffset].Value) { grid[3, colOffset].Value = false; SetBlack(3, colOffset); } else { grid[3, colOffset].Value = true; SetWhite(3, colOffset); } if (grid[7, colOffset].Value) { grid[7, colOffset].Value = false; SetBlack(7, colOffset); } else { grid[7, colOffset].Value = true; SetWhite(7, colOffset); } } private static void ShowAllDot() { int firstCol = (int)DotLocation.First; int secondCol = (int)DotLocation.Second; grid[3, firstCol].Value = true; SetWhite(3, firstCol); grid[7, firstCol].Value = true; SetWhite(7, firstCol); grid[3, secondCol].Value = true; SetWhite(3, secondCol); grid[7, secondCol].Value = true; SetWhite(7, secondCol); } private static void HideAllDot() { int firstCol = (int)DotLocation.First; int secondCol = (int)DotLocation.Second; grid[3, firstCol].Value = false; SetBlack(3, firstCol); grid[7, firstCol].Value = false; SetBlack(7, firstCol); grid[3, secondCol].Value = false; SetBlack(3, secondCol); grid[7, secondCol].Value = false; SetBlack(7, secondCol); } } public class Cell { public bool Value { get; set; } } public enum NumberLocation { HourFirst = 1, HourSecond = 7, MinuteFirst = 15, MinuteSecond = 21, SecondFirst = 29, SecondSecond = 35, } public enum DotLocation { First = 13, Second = 27 } }