I am new in developer role, and I have my code which I would like to simplify or make it better. And wondering if someone can do a quick check.
The code calculates the Score of the Bowling game, which is input as a string of the whole game (ex. as following: "X|7/|9-|x|-8|8/|-6|x|X|X||81").
Program.cs
public class Program { public static void Main(string[] args) { Console.WriteLine("#=======================#"); Console.WriteLine("# Welcome to Ten-Pin Bowling! #"); Console.WriteLine("#=======================#"); var game = new TenPinGame("X|7/|9-|x|-8|8/|-6|x|X|X||81"); Console.WriteLine("Game: {0}", input); Console.WriteLine("Score: " + game.Score()); Console.WriteLine("#=====#"); } Console.WriteLine("Thank you for playing with us!"); Console.WriteLine("Have a nice day!"); Console.Read(); } } TenPinGame.cs
public class TenPinGame : IGame { public const int MaxFrameNumber = 10; public const int StartingPinsNumber = 10; public List<Frame> Frames { get; } = new List<Frame>(); private string[] framesStringArray; public static string bonusSubsctring; public TenPinGame (string gameInput) { string framesSubstring = ParseGame(gameInput); framesStringArray = Utilities.SplitFramesString(framesSubstring, MaxFrameNumber); FrameRepository.ProcessFrameString(framesStringArray, Frames, MaxFrameNumber, StartingPinsNumber); } /// <summary> /// Splitting input string into 2 parts: Frames and Bonus throws /// </summary> /// <param name="gameInput"></param> internal string ParseGame(string gameInput) { string framesSubstring = ""; if (gameInput.Contains("||")) { int index = gameInput.IndexOf("||"); framesSubstring = gameInput.Substring(0, index); bonusSubsctring = gameInput.Substring(index + 2); } return framesSubstring; } /// <summary> /// Calculate the Total score for the whole game/line. /// </summary> /// <returns></returns> public int Score() { int score = 0; foreach (var frame in Frames) { int frameIndex = Frames.IndexOf(frame); if (!frame.IsLastFrame && frame.IsStrike) { if (Frames[frameIndex + 1].Throws.Count == 1) score += 10 + Frames[frameIndex + 1].Throws[0] + Frames[frameIndex + 2].Throws[0]; else if (Frames[frameIndex + 1].Throws.Count == 2 || Frames[frameIndex + 1].Throws.Count == 3) score += 10 + Frames[frameIndex + 1].Throws[0] + Frames[frameIndex + 1].Throws[1]; //else // throw new ArgumentException($"The next frame has invalid throws count {Frames[frameIndex + 1].Throws.Count}."); } else if (!frame.IsLastFrame && frame.IsSpare) { score += 10 + Frames[frameIndex + 1].Throws[0]; } else if (frame.IsLastFrame && frame.IsStrike) { score += 10 + Frames[frameIndex].Throws[1] + Frames[frameIndex].Throws[2]; } else if (frame.IsLastFrame && frame.IsSpare) { score += 10 + Frames[frameIndex].Throws[1]; } else { score += frame.Throws[0] + frame.Throws[1]; } } return score; } } Frame.cs
public class Frame { public List<int> Throws = new List<int>(); public int KnokcedDownPinsCount { get; set; } public bool IsStrike { get; set; } public bool IsSpare { get; set; } public bool IsLastFrame { get; set; } public bool IsBonusAllowed { get; set; } public bool IsFrameOver { get; set; } public Frame(bool isLastFrame = false) { this.IsLastFrame = isLastFrame; } public void ValidateEachThrow () { if (TenPinGame.StartingPinsNumber == 0) { throw new InvalidOperationException("Sorry, no pins are left standing."); } if (KnokcedDownPinsCount < 0) { throw new InvalidOperationException($"Sorry, the # of knocked down pins {KnokcedDownPinsCount} is out of range."); } else if (KnokcedDownPinsCount > TenPinGame.StartingPinsNumber) { throw new InvalidOperationException($"Sorry, the # of knocked down pins {KnokcedDownPinsCount} is is more than {TenPinGame.StartingPinsNumber} still standing pins."); } } } Utilities.cs
public class Utilities { /// <summary> /// Split each frame into a separate string in the string array /// </summary> /// <param name="framesString"></param> public static string[] SplitFramesString(string framesString, int maxFrameNumber) { string[] framesStringArray = Array.Empty<string>(); if (framesString.Contains("|")) { framesStringArray = framesString.Split(new string[] { "|" }, StringSplitOptions.RemoveEmptyEntries); if (framesStringArray.Length > maxFrameNumber) { throw new ArgumentException($"Sorry, you have {framesStringArray.Length} frames, " + $"which is higher than Max number of {maxFrameNumber} frames allowed for this game."); } } return framesStringArray; } /// <summary> /// Process each charcters in the given frame and set corresponding frame properties accordingly. /// </summary> /// <param name="characterInString"></param> /// <param name="Frames"></param> /// <param name="stratingPinsNumber"></param> /// <returns></returns> public static int ProcessCharArray(char characterInString, Frame Frames, int stratingPinsNumber) { int pinsCount = 0; if (characterInString >= '0' && characterInString <= '9') { Frames.Throws.Add((int)char.GetNumericValue(characterInString)); pinsCount = int.Parse(characterInString.ToString()); } else if (characterInString.ToString().ToUpperInvariant() == "X") { Frames.IsStrike = true; Frames.IsFrameOver = true; Frames.Throws.Add(10); pinsCount = 10; } else if (characterInString.ToString().ToUpperInvariant() == "/") { Frames.IsSpare = true; Frames.IsFrameOver = true; Frames.Throws.Add(stratingPinsNumber - Frames.Throws[0]); pinsCount = 10; } else if (characterInString.ToString().ToUpperInvariant() == "-") { Frames.Throws.Add(0); pinsCount += 0; } else if (characterInString.ToString().ToUpperInvariant() == "/" && Frames.IsLastFrame && Frames.IsBonusAllowed) { throw new ArgumentException("The Spare cannot be set on the Bonus Throws, please check."); } else { throw new ArgumentException($"Invalid argument '{characterInString}' was detected in the provided input, please check."); } return pinsCount; } } FrameRepository.cs
public class FrameRepository { /// <summary> /// Process each frame-string in the frames string array, to determine the pins count for each frame /// </summary> /// <param name="framesList"></param> public static void ProcessFrameString(string[] framesList, List<Frame> Frames, int MaxFrameNumber, int StartingPinsNumber) { foreach (var frame in framesList) { if (!Frames.Any() || Frames.Last().IsFrameOver) { var isLastFrame = Frames.Count == MaxFrameNumber - 1; Frames.Add(new Frame(isLastFrame)); } char[] frameCharArr = frame.ToCharArray(); foreach (char c in frameCharArr) { Frames.Last().KnokcedDownPinsCount = Utilities.ProcessCharArray(c, Frames.Last(), StartingPinsNumber); if (!Frames.Last().IsLastFrame && Frames.Last().Throws.Count == 2) { Frames.Last().IsFrameOver = true; } } if (Frames.Count == MaxFrameNumber) { Frames.Last().IsLastFrame = true; char[] bonusCharArr = TenPinGame.bonusSubsctring.ToCharArray(); if (Frames.Last().IsStrike) { if (bonusCharArr.Length > 2) { throw new ArgumentException($"The number of bonus throws {bonusCharArr.Length}, is over allowed for the Last Strike. Please check."); } Frames.Last().IsBonusAllowed = true; foreach (char c in bonusCharArr) { Frames.Last().KnokcedDownPinsCount = Utilities.ProcessCharArray(c, Frames.Last(), StartingPinsNumber); } } else if (Frames.Last().IsSpare) { if (bonusCharArr.Length != 1) { throw new ArgumentException($"The number of bonus throws {bonusCharArr.Length}, is over allowed for the Last Spare. Please check."); } Frames.Last().IsBonusAllowed = true; Frames.Last().KnokcedDownPinsCount = Utilities.ProcessCharArray(bonusCharArr[0], Frames.Last(), StartingPinsNumber); } } } } }