Adding commas to numbers

I think I just figured out how to add commas to large numbers to make them easier to read.
Here’s my code.
Inspired by BUNNIES!

*temp one "12345678901234"
*temp one1 ""
*temp two ","
*temp counter 1
*temp counter2 0
*temp counter3 1
*temp counter4 0
*temp results 0
*temp results2 0
*temp results3 0
*temp num ""
*temp num2 ""

Enter a big number, and I will put in some commas.

*input_number one1 1 99999999999999
*set one one1

*if length(one) < 4
 *set num2 one
 *goto final

*set results3 length(one)/3
*if length(results3) = 1
 *set results3 -1
*if results3 < 1
 *set results3 0
*if length(results3) > 1
 *set results3 (results3#1)

*label next
*set counter3 length(one)
*set counter2 length(one)
*set counter4 length(one)

*label resultsloop
*set results (counter4/3)
*if length(results) > 1
 *set counter4 +1
 *set results2 +1
 *goto resultsloop

*label main

*if length(num) < counter3
 *set num &(one#counter2)
 *set counter2 -1
 *set counter +1
 *goto main
*if length(num) = counter3
 *set counter 1
 *set counter +results2
 *set counter2 length(one)
 *goto main2

*label main2

*if length(num2) < (counter3 +results3)
 *if counter < 4
  *set num2 &(num#counter2)
  *set counter +1
  *set counter2 -1
  *goto main2
 *if counter = 4
  *set num2 &two
  *set counter 1
  *goto main2

*label final
Your number = ${num2}

This is my way over engineered version (with implicit_control_flow). (I set up my subroutines with the idea of taking them with me from game to game.)

*label display_number
*params n
*comment param_1: n:(numeric) input number
*if param_count >= 2
	*temp p param_2
	*temp p false
*comment param_2: p:(boolean|string) inserted before number (assumes $ if true) (optional: defaults to false)
*if param_count >= 3
	*temp f param_3
	*temp f false
*comment param_3: f:(boolean|string) inserted after number (assumes .00 if true) (optional: defaults to false)
*if param_count >= 4
	*temp z param_4
	*temp z false
*comment param_4: z:(false|"variable") Return variable: if not false, sets this variable rather than displays number (optional: defaults to false)
*temp x length(n)
*temp d ""
*comment x:place in number where writing from; d:display number
*if round(n) != n
	*if (choice_randomtest) or not(choice_purchase_supported)
		*bug n should be a whole number (is currently ${n}). In play through anything after the decimal will be truncated.
	*set n round(n-0.5)
	*set x length(n)
*if p = false
	*set p ""
*if p = true
	*set p "$"
*if f = false
	*set f ""
*if f = true
	*set f ".00"
*if z != false
	*if z = true
		*bug Invalid parameter: Return variable is ${z}. Acceptable values are "variables" stored as strings or the boolean false.
	*set {z} ""
	*comment Above line clears z if not false, and will throw a non-existent variable error if z is not a "variable".
*label display_number_loop
*set d (n#x)&d
*set x - 1
*if x = 0
	*label display_number_exit
	*if z = false
		*set {z} p&d
*if (n#x) = "."
*if ((length(n)-x) modulo 3) = 0
	*set d ","&d
*goto display_number_loop

There’s one parameter (the number) which is not optional, then another 3 which are optional, and if it’s not a whole number, it runs into a bug (unless the game is set up for purchase), which is that the whole *check_purchase thing is.


Seriously, Wow!

Such work just to add commas… I feel humbled and also a little bit perplexed as to why it should be quite so hard!

1 Like

Bear in mind this may confuse foreign readers, who might use commas to mark decimals and periods to separate groups of three. So they’d expect 999999999 as 999.999.999,00. Or in other countries they might expect 999 999 999,00.

1 Like

I ended up using a simple, brute force method to (where applicable) turn any value up to $999999 into something more appropriate for display, e.g. $23,795, using the ability to extract / overwrite particular letters or numbers in variable values. In short, it treats the value as a string, not numeric, since it’s purely for display purposes.

I’ll lay out the whole thing here in step-by-step fashion but it should be easy enough to tweak to suit particular needs, and thereby reduce the number of lines used / needed.

*set word "${wealth}"

*comment turn value into a 6-digit number by prefixing with zeros
*if length(word) = 1
  *set word (("0"&"0")&("0"&"0"))&("0"&(word#1))
*if length(word) = 2
  *set word (("0"&"0")&("0"&"0"))&((word#1)&(word#2))
*if length(word) = 3
  *set word (("0"&"0")&("0"&(word#1)))&((word#2)&(word#3))
*if length(word) = 4
  *set word (("0"&"0")&((word#1)&(word#2)))&((word#3)&(word#4))
*if length(word) = 5
  *set word (("0"&(word#1))&((word#2)&(word#3)))&((word#4)&(word#5))

*comment insert comma in middle of 6-digit currency value
*if length(word) = 6
  *set word (((word#1)&(word#2))&((word#3)&(",")))&(((word#4)&(word#5))&(word#6))

*comment remove leading zeros one at a time, including comma if not needed
*if (word#1) = "0"
  *set word (((word#2)&(word#3))&((word#4)&(word#5)))&((word#6)&(word#7))
  *if (word#1) = "0"
    *set word (((word#2)&(word#3))&((word#4)&(word#5)))&(word#6)
    *if (word#1) = "0"
      *set word ((word#3)&(word#4))&(word#5)
      *if (word#1) = "0"
        *set word (word#2)&(word#3)
        *if (word#1) = "0"
          *set word (word#2)

Note that while the following, more obvious method works in practice, it actually generates a ‘fake bug’ in QuickTest on the *set lines (in the event the value of word is fewer than x-characters in length, despite the specific *if condition).

*set word "${wealth}"
*if length(word) < 4
  *goto next
*if length(word) = 4
  *set word (((word#1)&(","))&((word#2)&(word#3)))&(word#4)
  *goto next
*if length(word) = 5
  *set word (((word#1)&(word#2))&((",")&(word#3)))&((word#4)&(word#5))
  *goto next
*if length(word) = 6
  *set word (((word#1)&(word#2))&((word#3)&(",")))&(((word#4)&(word#5))&(word#6))
  *goto next
*label next