Skip to content

Instantly share code, notes, and snippets.

@geekskick
Created November 25, 2019 21:20
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save geekskick/8cfea222093924d4e753f68197ed5502 to your computer and use it in GitHub Desktop.
Save geekskick/8cfea222093924d4e753f68197ed5502 to your computer and use it in GitHub Desktop.
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