_TITLE "Roman SUB Test" ' B+ 2020-08-30 rewrite old to one sub, using several hints from SMcNeill
'I hope you can understand how this testing part works :)
PRINT " Testing conversion of numbers 1 to 3999 to or from Roman Numerals >" INPUT " Enter a string to test "; test$
'Here is the crucial call to the SUB we are testing.
SUB Roman
(inStr$
, outStr$
) ' 1 to 3999 The inStr$ variable brings in a decimal or a Roman Numeral ' and Roman SUB will output the conversion or an Error: message in outStr$.
'STATIC preserves all values between calls to the SUB procedure.
IF Ones$
(10) = "" THEN 'setup our arrays 'If Ones$(10) = "" then this is very first time this sub is called, so load up the arrays of data.
'directly load data into the arrays without READ and DATA statements
Ones$(1) = "I": Ones$(2) = "II": Ones$(3) = "III": Ones$(4) = "IV": Ones$(5) = "V"
Ones$(6) = "VI": Ones$(7) = "VII": Ones$(8) = "VIII": Ones$(9) = "IX": Ones$(10) = "X"
Tens$(1) = "X": Tens$(2) = "XX": Tens$(3) = "XXX": Tens$(4) = "XL": Tens$(5) = "L"
Tens$(6) = "LX": Tens$(7) = "LXX": Tens$(8) = "LXXX": Tens$(9) = "XC": Tens$(10) = "C"
H100s$(1) = "C": H100s$(2) = "CC": H100s$(3) = "CCC": H100s$(4) = "CD": H100s$(5) = "D"
H100s$(6) = "DC": H100s$(7) = "DCC": H100s$(8) = "DCCC": H100s$(9) = "CM": H100s$(10) = "M"
'R is for Roman, the R$() array will hold all the Roman Numeral Strings from 1 to 3999.
cd = i 'cd originally stood for copy decimal from original Decimal2Roman function,
' here I just kept the name for decimal numbers.
convert$ = "" ' I am converting the decimal number to Roman,
' this variable is storing the building of the Roman string.
'Building from decimal 1000's:
' INT(cd / 1000) is how many 1000's the number cd has.
' The STRING$ function creates repeated characters, so repeating M the number of 1000's I have.
'Take away 1000's in build, whats left is back in cd.
cd
= cd
- 1000 * INT(cd
/ 1000)
'Now how many 100's do I have? This many = INT(cd / 100). Lookup that number in h100s$() symbols.
'If it was 5 then h100s$(5) = "D", add that to my build variable convert$.
IF cd
> 100 THEN convert$
= convert$
+ H100s$
(INT(cd
/ 100))
'And sutract my 100's from cd.
cd
= cd
- 100 * INT(cd
/ 100)
'Now how many 10's do I have? This many = INT(cd / 10), use that number for index to Tens$() lookup symbol.
'and add it to convert$.
IF cd
> 10 THEN convert$
= convert$
+ Tens$
(INT(cd
/ 10))
'And subtract 10's from cd.
cd
= cd
- 10 * INT(cd
/ 10)
'And finally for ones place of decimal number cd is all that remains lookup the symbol in Ones$()
'and add it to convert$.
IF cd
>= 1 THEN convert$
= convert$
+ Ones$
(cd
)
'OK the Roman Numeral string is built in the variable convert$, save it in our big R$() array.
R$(i) = convert$
'we are now done with all setup and ready to start converting number by array lookups
'Make a copy of instr$ it could be decimal or it could be Roman we don't know yet,
' but we want to make sure spaces are trimmed and any letters are capitalized.
's is for string!
' Let's get rid of trivial error cases first.
IF s$
= "" OR s$
= "0" THEN outStr$
= "Error: nada":
EXIT SUB 'handle nothing
' Now is inStr$ all decimal digits or all Roman Letters or something that indicates an error?
' pd is for place of digit. pr is for place of Roman Letter.
' If both are 0 then there is a crazy character on the loose, time to bug out!
IF pd
= 0 AND pr
= 0 THEN outStr$
= "Error: unknown character.":
EXIT SUB 'handle wrong alpha
' Here we compare the pd to the last pd and pr to the last pr to check for mixed messages.
' If the current character is Roman and the last was a decimal then WTH? letters are mixed with digits.
' Time to get out of Dodge!
IF i
> 1 THEN 'check for mixed messages IF (lastpd
= 0 AND pd
> 0) OR (lastpr
= 0 AND pr
> 0) THEN outStr$
= "Error: digits mixed with letters.":
EXIT SUB
'save for comparing the next characters
lastpd = pd: lastpr = pr
'OK we have checked that all the characters are either all Roman letters OR all decimal digits.
' Time to lay our cards on the table and see which is which from VAL function.
IF v
= 0 THEN ' Then it must be that s$ was all letters that have no value to VAL. FOR i
= 1 TO 3999 ' So run through the table of Roman strings and match it to what we have in s$.
'Aha a match at i = something, then i is the decimal number for that Roman String.
'Ship it out in the outStr$ variable, trimmed nice and neat of spaces STR$ tends to add to positive numbers.
'If we are still in this SUB that means we did not find a matching string, so sorry ;(
outStr$ = "Error: Invalid Roman Numeral? string."
'Else s$ has been loaded with digits all this time but are the digits in range of our Roman Numbers?
' Yes it is safe to call on index v of R$(), there will be a Roman Numeral ready to ship out in outStr$,
' so put it there.
outStr$ = R$(v)
' We are not in range, so report a complaint ;(
outStr$ = "Error: Not in range of 1 to 3999."