1. Welcome to skUnity!

    Welcome to skUnity! This is a forum where members of the Skript community can communicate and interact. Skript Resource Creators can post their Resources for all to see and use.

    If you haven't done so already, feel free to join our official Discord server to expand your level of interaction with the comminuty!

    Now, what are you waiting for? Join the community now!

Dismiss Notice
This site uses cookies. By continuing to use this site, you are agreeing to our use of cookies. Learn More.

[#2] Winners of Skript Challenge - Numbers to Words

Discussion in 'Skript Challenge' started by BaeFell, Feb 18, 2017.

  1. BaeFell

    BaeFell I'm Poppy
    Admin

    Joined:
    Nov 27, 2016
    Messages:
    834
    Likes Received:
    226
    Hi everyone,

    After remembering yesterday, then forgetting and remembering now, here are the winners of the second skUnity Skript Challenge! There weren't many entries this time (to be honest, it was slightly more complex), but there were some amazing ones anyway! I've also got the medal system up and running, and have created a medal for the people who win a Skript Challenge! The 3 winners from #1 were award their medals earlier.

    Anyway, without further ado, here are the winners:

    In first place is @SwiKZiiK - a French Skripter who created the shortest way of doing it, while not using any loops, addons or splitting!
    Code (Skript):
    1.     set {_num} to "Put your number here."
    2.     length of {_num} <= 2:
    3.         return {_num}
    4.     else if length of {_num} = 3:
    5.         return "%first character of {_num}% hundred and %last 2 characters of {_num}%"
    6.     else if length of {_num} <= 6:
    7.         return "%first (length of {_num} - 3) characters of {_num}% thousand, %subtext of {_num} from (length of {_num} - 2) and (length of {_num} - 2)% hundred and %last 2 characters of {_num}%"
    8.     else if length of {_num} <= 9:
    9.         return "%first (length of {_num} - 6) characters of {_num}% million, %subtext of {_num} from (length of {_num} - 5) and (length of {_num} - 3)% thousand, %subtext of {_num} from (length of {_num} - 2) and (length of {_num} - 2)% hundred and %last 2 characters of {_num}%"
    10.  
    (while I'm not looking for the shortest, it amazed me and many others on how this one was so simple for the challenge).

    In join-second place is @Rezz - a beautiful and well crafted solution to the challenge. Massively extensive and covers a wide range of features.
    Code (Skript):
    1. options:
    2.     TABLE: number-to-name
    3.     ERROR: [Error]
    4.     ENABLE_LARGE_NUMBER_NAMES: true
    5.  
    6. # Define all masks in a string with pattern:name pairs.
    7.  
    8. function defineMasksIn(values: text):
    9.  
    10.     set {_pairs::*} to {_values} split at " "
    11.  
    12.     loop {_pairs::*}:
    13.  
    14.         set {_pair::*} to loop-value split at ":"
    15.         set {{@TABLE}::%{_pair::1}%} to {_pair::2}
    16.    
    17. on script load:
    18.  
    19.     defineMasksIn("1:one 2:two 3:three 4:four 5:five 6:six 7:seven 8:eight 9:nine")
    20.     defineMasksIn("10:ten 11:eleven 12:twelve 13:thirteen 14:fourteen 15:fifteen 16:sixteen 17:seventeen 18:eighteen 19:nineteen")
    21.     defineMasksIn("2.:twenty 3.:thirty 4.:forty 5.:fifty 6.:sixty 7.:seventy 8.:eighty 9.:ninety")
    22.     defineMasksIn(".__:hundred ...___:thousand ...______:million ..._________:billion ...____________:trillion ..._______________:quadrillion")
    23.  
    24.     {@ENABLE_LARGE_NUMBER_NAMES} is true
    25.  
    26.     # Number names from: https://en.wikipedia.org/wiki/Names_of_large_numbers
    27.  
    28.     defineMasksIn("...__________________:quintillion ..._____________________:sextillion ...________________________:septillion")
    29.     defineMasksIn("...___________________________:octillion ...______________________________:nonillion ..._________________________________:decillion")
    30.  
    31.     defineMasksIn("...____________________________________:undecillion ..._______________________________________:duodecillion")
    32.     defineMasksIn("...__________________________________________:tredecillion ..._____________________________________________:quattuordecillion")
    33.     defineMasksIn("...________________________________________________:quindecillion ...___________________________________________________:sexdecillion")
    34.  
    35. on script unload:
    36.  
    37.     delete {{@TABLE}::*}
    38.  
    39. # Returns the matching mask for a string of digits or an error if nothing is found.
    40.  
    41. function findMaskFor(number: text) :: text:
    42.  
    43.     set {_length} to length of {_number}
    44.     set {_digits::*} to {_number} split at ""
    45.  
    46.     loop {{@TABLE}::*}:
    47.  
    48.         if {_skip} is set:
    49.    
    50.             delete {_skip}
    51.    
    52.         set {_mask} to loop-index
    53.         set {_mask-length} to length of {_mask}
    54.         set {_minimum-length} to {_mask-length}
    55.         set {_chars::*} to {_mask} split at ""
    56.    
    57.         loop {_chars::*}:
    58.        
    59.             {_skip} is not set
    60.        
    61.             set {_char} to loop-value-2
    62.             set {_digit} to {_digits::%loop-index-2%}
    63.                    
    64.             if {_char} is ".":
    65.        
    66.                 set {_minimum-length} to {_minimum-length} - 1
    67.            
    68.             else:
    69.        
    70.                 if {_minimum-length} is greater than {_length}:
    71.            
    72.                     set {_skip} to true
    73.                
    74.                 else if {_char} is not {_digit} or "_":
    75.            
    76.                     set {_skip} to true
    77.    
    78.         {_skip} is not set
    79.    
    80.         if {_mask-length} is {_length}:
    81.    
    82.             return {_mask}
    83.        
    84.         else if {_length} is less than {_mask-length}:
    85.        
    86.             if {_length} is greater than {_minimum-length}:
    87.        
    88.                 return {_mask}
    89.        
    90.     return "{@ERROR} Unsupported value: '%{_number}%' with length %{_length}%"
    91.  
    92. # Determine whether a string starts with another.
    93.  
    94. function startsWith(start-text: text, full-text: text) :: boolean:
    95.  
    96.     if the first (length of {_start-text}) characters of {_full-text} is {_start-text}:
    97.         return true
    98.     return false
    99.  
    100. # Determine whether a string ends with another.
    101.  
    102. function endsWith(end-text: text, full-text: text) :: boolean:
    103.  
    104.     if the last (length of {_end-text}) characters of {_full-text} is {_end-text}:
    105.         return true
    106.     return false
    107.  
    108. # Insert a string into another at a specified index.
    109.  
    110. function insert(insertion: text, index: number, text: text) :: text:
    111.  
    112.     set {_left} to the first {_index} characters of {_text}
    113.     set {_right} to the last (length of {_text} - {_index}) characters of {_text}
    114.  
    115.     return "%{_left}%%{_insertion}%%{_right}%"
    116.  
    117. # Count the occurrences of a character in a string.
    118.  
    119. function occurrencesOf(char: text, in: text) :: number:
    120.  
    121.     set {_count} to 0
    122.     set {_characters::*} to {_in} split at ""
    123.  
    124.     loop {_characters::*}:
    125.  
    126.         if "%loop-value%" is {_char}:
    127.    
    128.             add 1 to {_count}
    129.        
    130.     return {_count}
    131.  
    132. # Strip all leading zeroes from a string of digits.
    133.  
    134. function stripLeadingZeroes(number: text) :: text:
    135.  
    136.     while startsWith("0", {_number}) is true:
    137.  
    138.         if length of {_number} is 1:
    139.             set {_number} to ""
    140.         else:
    141.             set {_number} to the last (length of {_number} - 1) characters of {_number}
    142.  
    143.     return {_number}
    144.  
    145. # Returns the full name of all digits in a string.
    146.  
    147. function nameOfDigits(number: text) :: text:
    148.  
    149.     if {_number} is "0":
    150.  
    151.         return "zero"
    152.  
    153.     set {_number} to stripLeadingZeroes({_number})
    154.     set {_length} to length of {_number}
    155.  
    156.     if {_length} is 0:
    157.  
    158.         return ""
    159.  
    160.     set {_mask} to findMaskFor({_number})
    161.    
    162.     if startsWith("{@ERROR}", {_mask}) is true:
    163.  
    164.         return {_mask}
    165.    
    166.     set {_mask-length} to length of {_mask}
    167.     set {_mask-cutoff} to {_mask-length} - {_length}
    168.     set {_active-mask} to the last ({_mask-length} - {_mask-cutoff}) characters of {_mask}
    169.    
    170.     if startsWith(".", {_active-mask}) is true:
    171.  
    172.         set {_left-side-components} to occurrencesOf(".", {_active-mask})
    173.         set {_split-number::*} to insert(":", {_left-side-components}, {_number}) split at ":"
    174.    
    175.         set {_left} to nameOfDigits({_split-number::1})  
    176.         set {_right} to nameOfDigits({_split-number::2})  
    177.         set {_name} to {{@TABLE}::%{_mask}%}
    178.    
    179.         if {_right} is "zero" or "":
    180.             return "%{_left}% %{_name}%"
    181.         else if {_name} is "hundred":
    182.             return "%{_left}% %{_name}% %{_right}%"
    183.         else:
    184.             return "%{_left}% %{_name}%, %{_right}%"
    185.  
    186.     else if endsWith(".", {_active-mask}) is true:
    187.  
    188.         set {_left} to {{@TABLE}::%{_mask}%}
    189.         set {_digit} to the last character of {_number}
    190.         set {_right} to nameOfDigits({_digit})
    191.    
    192.         if {_right} is "zero" or "":
    193.             return "%{_left}%"
    194.         else:
    195.             return "%{_left}%-%{_right}%"
    196.    
    197.     else:
    198.  
    199.         return {{@TABLE}::%{_mask}%}
    200.    
    201. # Converts an integer to a string and returns the result of nameOfDigits()
    202.  
    203. function nameOfNumber(number: integer) :: text:
    204.  
    205.     return nameOfDigits("%{_number}%")
    206.  
    207. command /nameof <integer>:
    208.     trigger:
    209.  
    210.         set {_result} to nameOfNumber(arg-1)
    211.         send "%arg-1%: &a%{_result}%"
    212.    
    213. # A function to ensure a string only contains numeric characters.
    214.  
    215. function validateDigitsOf(text: text) :: boolean:
    216.  
    217.     set {_chars::*} to {_text} split at ""
    218.  
    219.     loop {_chars::*}:
    220.         if "0123456789" doesn't contain "%loop-value%":
    221.             return false
    222.        
    223.     return true
    224.  
    225. command /nameofdigits <text>:
    226.     trigger:
    227.  
    228.         if validateDigitsOf(arg-1) is true:
    229.    
    230.             set {_result} to nameOfDigits(arg-1)
    231.             send "%arg-1%: &a%{_result}%"
    232.        
    233.         else:
    234.    
    235.             send "&cThe only characters allowed are: 0-9"
    236.  
    In joint-second place is @Tlatoani - his answer is also very extensive and even converts the numbers themselves into words: 2009 -> two thousand and nine

    Code (Skript):
    1. on load:
    2.   set {small numbers::*} to "one", "two", "three", "four", "five", "six", "seven", "eight", "nine", "ten", "eleven", "twelve", "thirteen", "fourteen", "fifteen", "sixteen", "seventeen", "eighteen", "nineteen"
    3.   set {multiples of ten::*} to "ten", "twenty", "thirty", "forty", "fifty", "sixty", "seventy", "eighty", "ninety"
    4.   set {powers of thousand::*} to "thousand", "million", "billion", "trillion", "quadrillion", "quintillion"
    5.  
    6. function modulus(num: number, by: number) :: number:
    7.   return {_num} - {_by} * rounded down {_num} / {_by}
    8.  
    9. function smallNumToEnglish(num: number) :: string:
    10.   if {_num} < 20:
    11.     return {small numbers::%{_num}%}
    12.   if {_num} < 100:
    13.     set {_tens} to rounded down {_num}/10
    14.     set {_result} to {multiples of ten::%{_tens}%}
    15.     if modulus({_num}, 10) > 0:
    16.       set {_result} to "%{_result}%-%smallNumToEnglish(modulus({_num}, 10))%"
    17.     return {_result}
    18.   set {_result} to "%smallNumToEnglish(rounded down {_num}/100)% hundred"
    19.   if modulus({_num}, 100) > 0:
    20.     set {_result} to "%{_result}% and %smallNumToEnglish(modulus({_num}, 100))%"
    21.   return {_result}
    22.  
    23. function numToEnglish(num: number) :: string:
    24.   if {_num} is 0:
    25.     return "zero"
    26.   set {_power of thousand} to 0
    27.   while {_num} > 0:
    28.     if modulus({_num}, 1000) > 0:
    29.       set {_number name} to {powers of thousand::%{_power of thousand}%}
    30.       set {_result} to "%smallNumToEnglish(modulus({_num}, 1000))% %{_number name}%, %{_result}%"
    31.     set {_num} to rounded down {_num} / 1000
    32.     add 1 to {_power of thousand}
    33.   if {_result} contains ">,":
    34.     return first length of {_result} - 15 characters of {_result} #Removes the extra " <none>, <none>" at the end of the string
    35.   else:
    36.     return first length of {_result} - 8 characters of {_result} #Removes the extra ", <none>" at the end of the string
    Also in joint-second place is @xXAndrew28Xx - another amazing submission which deserves to be appreciated.
    Code (Skript):
    1. function modulo(dividend: integer, divisor: integer) :: number:
    2.   set {_quotient} to {_dividend} / {_divisor}
    3.   set {_floor} to floor({_quotient})
    4.   return {_dividend} - ({_floor} * {_divisor})
    5. function wholeDivision(dividend: integer, divisor: integer) :: number:
    6.   set {_quotient} to {_dividend} / {_divisor}
    7.   set {_floor} to floor({_quotient})
    8.   return {_floor}
    9. function expandedForm(number: integer) :: text:
    10.   #Letter Prefixes so it loops in the correct order
    11.   set {_format::a-quadrillion} to 1000000000000000
    12.   set {_format::b-trillion} to 1000000000000
    13.   set {_format::c-billion} to 1000000000
    14.   set {_format::d-million} to 1000000
    15.   set {_format::e-thousand} to 1000
    16.   set {_format::f-hundred} to 100
    17.   while {_number} is not 0:
    18.     if {_number} < 100:
    19.       #set {_lowerNumberFormats::*} to "one", "two", "three", "four", "five", "six", "seven", "eight", "nine", "ten", "eleven", "twelve", "thirteen", "fourteen", "fifteen", "sixteen", "seventeen", "eighteen", and "nineteen"
    20.       #set {_tensFormats::*} to "twenty", "thirty", "fourty", "fifty", "sixty", "seventy", "eighty", and "ninty"
    21.       #if {_number} < 20:
    22.       #  set {_numberFormatted} to {_lowerNumberFormats::%{_number}%}
    23.       #else if {_number} is 100:
    24.       #  set {_numberFormatted} to "one hundred"
    25.       #else:
    26.       #  set {_tensFormatsIndex} to (wholeDivision({_number}, and 10)) - 1
    27.       #  set {_numberFormatted} to {_tensFormats::%{_tensFormatsIndex}%}
    28.       #  if modulo({_number},10) is not 0:
    29.       #    set {_digitNumber} to modulo({_number}, and 10)
    30.       #    set {_digitNumberFormatted} to {_lowerNumberFormats::%{_digitNumber}%}
    31.       #    set {_numberFormatted} to "%{_numberFormatted}% %{_digitNumberFormatted}%"
    32.       #broadcast "ADDED %{_numberFormatted}%"
    33.       set {_numberFormatted} to "%{_number}%"
    34.       add {_numberFormatted} to {_values::*}
    35.       exit loop
    36.     loop {_format::*}:
    37.       set {_place} to loop-value
    38.       #EVALUATE because {_whole} isn't changing after the first time without it
    39.       evaluate "set {_whole} to wholeDivision(%{_number}%, and %{_place}%)"
    40.       if {_whole} > 0:
    41.         if {_place} is 100:
    42.           if {_whole} > 9:
    43.             exit 3 sections
    44.         set {_number} to {_number} - ({_whole} * {_place})
    45.         set {_placeName} to loop-index
    46.         set {_placeName} to subtext of {_placeName} from characters 3 to length of {_placeName}
    47.         if {_whole} is not 0:
    48.           set {_formattedWhole} to {_whole} #Will update later
    49.           add "%{_formattedWhole}% %{_placeName}%" to {_values::*}
    50.   return  "%{_values::*}%"
    I won't normally have 3 joint-seconds or anything like that, but the answers were all amazing but similar in idea, that they all deserved it.

    In third place is @Getreidemonster - a submission so beautiful that I cried too much reading it to be able to put it any higher. It had the most winner ratings and even solves the issue of world hunger.
    Code (Skript):
    1. command /SkriptChallenge:
    2.     trigger:
    3.         send "§oDo you really though that I'm posting here the task? ;)"
    4.         send "§a§oOkay, let's start!"
    5.         shutdown server
    6.  
    (This is a joke winner, kinda. This probably won't ever happen again, so please don't try and make jokes to win, this is just a really good first one to ever happen).

    A huge thanks to everyone who took part in the second skUnity Skript Challenge! I hope to set up some more soon.

    And I also hope you all enjoyed this Skript challenge! If you have an idea for the next one, PM me and I'll see what I can do.

    Thanks,
    BaeFell
     
    • Like Like x 6
    • Winner Winner x 2
    • Agree Agree x 1

Share This Page

Loading...