Created
November 25, 2019 21:20
-
-
Save geekskick/8cfea222093924d4e753f68197ed5502 to your computer and use it in GitHub Desktop.
This file contains 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.Collections.Generic; | |
using System.Linq; | |
using System.Text.RegularExpressions; | |
namespace PhillyC1 | |
{ | |
struct Split | |
{ | |
public int startIdx; | |
public int length; | |
} | |
struct Duo | |
{ | |
public string higher; | |
public string lower; | |
} | |
class Program | |
{ | |
private static bool HelpNeeded(List<String> args) => args.Contains("-h") || args.Contains("--help"); | |
private static void PrintUsage() => Console.WriteLine("{0} <positive whole number>", System.Diagnostics.Process.GetCurrentProcess().ProcessName); | |
private static bool IsNumber(string s) => Regex.IsMatch(s, @"^\d+$"); | |
private static readonly string[] unitStrings = { "one", "two", "three", "four", "five", "six", "seven", "eight", "nine", "ten", "eleven", "twelve", "thirtheen", "fourteen", "fifteen", "sixteen", "seventeen", "eighteen", "ninetneen" }; | |
private static readonly string[] tenStrings = { "twenty", "thirty", "fourty", "fifty", "sixty", "seventy", "eighty", "ninety" }; | |
private static readonly string[] biggieStrings = { String.Empty, "hundred" }; | |
private static readonly string[] reallyBiggieStrings = { string.Empty, "thousand", "million", "billion", "trillion", "quadrillion?", "hexillion?", "pentillion?", "septillion?", "octillion?", "nonillion", "decillion?","eleven-illion?" }; //decillion only to beat paul | |
private static string getUnitString(int s) => unitStrings[s - 1]; | |
private static string getTensString(int s) => tenStrings[s - 1]; | |
private static string getTripletSeparatorString(int s) => reallyBiggieStrings[s]; | |
private static int getNextMultipleOf(string number, int multiple) => number.Length % multiple != 0 ? ((number.Length / multiple) + 1) * multiple : number.Length; | |
private static List<String> splitNumberIntoTriplets(string number) | |
{ | |
var rc = new List<string>(); | |
var desiredLength = getNextMultipleOf(number, 3); | |
number = number.PadLeft(desiredLength, '0'); | |
while (number != string.Empty) | |
{ | |
var topTriplet = number.Substring(0, 3); | |
number = number.Substring(3); | |
if (!IsNumber(topTriplet)) { throw new ArgumentException("{0} isn't a number", topTriplet); } | |
rc.Add(topTriplet); | |
} | |
return rc; | |
} | |
private static Split getSplit(string number, int rhs_chunk) | |
{ | |
var backTrack = rhs_chunk; | |
var candidateStartIdx = number.Length - Math.Min(backTrack, number.Length); | |
var startIdx = candidateStartIdx; | |
var length = number.Length - startIdx; | |
var rc = new Split | |
{ | |
startIdx = startIdx, | |
length = length | |
}; | |
return rc; | |
} | |
private static Duo getGroup(string number, int size) | |
{ | |
var s = getSplit(number, size); | |
var rc = new Duo | |
{ | |
higher = number.Substring(0, number.Length - s.length), | |
lower = number.Substring(s.startIdx) | |
}; | |
return rc; | |
} | |
private static Duo getBottomDuo(string number) | |
{ | |
return getGroup(number, 2); | |
} | |
private static List<string> handleTriplet(String number) | |
{ | |
var rc = new List<string>(); | |
for (int repeats = 0; number.Length > 0; ++repeats) | |
{ | |
var duo = getBottomDuo(number); | |
var bottomDigits = duo.lower; | |
number = duo.higher; | |
int.TryParse(bottomDigits, out int num); | |
if (num == 0) { continue; } | |
// Usually an 'and' goes after the word 'hundred' and before something else | |
if (repeats == 1 && rc.Count != 0) | |
{ | |
rc.Insert(0, "and"); | |
} | |
rc.Insert(0, biggieStrings[repeats]); | |
if (num < 20) | |
{ | |
rc.Insert(0, getUnitString(num)); | |
} | |
else | |
{ | |
var tens = (num / 10) - 1; | |
var units = num % 10; | |
if (units - 1 >= 0) | |
{ | |
rc.Insert(0, getUnitString(units)); | |
} | |
rc.Insert(0, getTensString(tens)); | |
} | |
} | |
rc.RemoveAll(x => x == String.Empty); | |
return rc; | |
} | |
static void Main(string[] args) | |
{ | |
var listArgs = new List<String>(args); | |
var number = listArgs[0]; | |
if (listArgs.Count != 1 || HelpNeeded(listArgs) || !IsNumber(number)) | |
{ | |
PrintUsage(); | |
return; | |
} | |
number = number.TrimStart('0'); | |
if (number.Length > 39) | |
{ | |
Console.WriteLine("I dont support x . 10^39 (I think that's the right number for an twelve-illion) yet"); | |
return; | |
} | |
var triplets = splitNumberIntoTriplets(number); | |
var finalResult = new List<string>(); | |
var tripletSeparatorLabelIdx = triplets.Count - 1; | |
while(triplets.Count > 0) | |
{ | |
finalResult.AddRange(handleTriplet(triplets[0])); | |
if (!reallyBiggieStrings.Contains(finalResult[finalResult.Count - 1])) | |
{ | |
finalResult.Add(getTripletSeparatorString(tripletSeparatorLabelIdx)); | |
} | |
// Incases like "20001" where 'and' needs plopping in | |
if (finalResult.Count >= 3 && triplets.Count == 1) | |
{ | |
var secondToLast = finalResult[finalResult.Count - 1 - 1 - 1]; | |
var last = finalResult[finalResult.Count - 1 - 1]; | |
if(!biggieStrings.Contains(last) && reallyBiggieStrings.Contains(secondToLast)) | |
{ | |
finalResult.Insert(finalResult.Count -1-1,"and"); | |
} | |
} | |
triplets.RemoveAt(0); | |
tripletSeparatorLabelIdx--; | |
} | |
Console.WriteLine(String.Join(" ", finalResult)); | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment