A Beginners Guide To Euphoria

Advanced Data Object Handling, Part One

If you want to get the most out of the Euphoria programming language, getting a handle on how to work with data objects should be at the top of your list. There are a lot of library routines that are meant for handling data objects. You can check for the type of a data object. You can also change the way a data object is presented, such as going from 2.34 to "2.34", and can even go beyond the simple operators of Euphoria to create your own unique data structures. 
Because some of the library routines in Euphoria can return either an atom or a sequence, it is very important to test for the type of a data object. The library routines involved are named the same as the variable type portion of a variable declaration statement. To begin, atom() returns a 1 if the data object is an atom value:
 
   ri = atom(o)
 
integer() returns a 1 if the data object is an integer:
 
   ri = integer(o)

sequence() returns a 1 if the data object is a sequence:

  ri = sequence(o)
 
All of these library routines will return 0 if data object o is not the expected type. Run a demo from this screen now to demonstrate how to test for the type of a keyed-in data value. For obvious reasons, there is no such thing as an object() library routine.

Demo program 23
include get.e

atom atom_received, integer_received, sequence_received
sequence inputted_string

atom_received = 'n'
integer_received = 'n'
sequence_received = 'n'

puts(1,"Enter any numeric value (such as 5.004 or -7)\n")

while atom_received = 'n' and integer_received = 'n' do
     inputted_string = get(0)
     if inputted_string[1] = 0 then
          if integer(inputted_string[2]) then
               integer_received = 'y'
               puts(1,"\nThank you! This value is an integer!\n\n")
          else
               if atom(inputted_string[2]) then
                    atom_received = 'y'
                    puts(1,"\nThank you! This value is an atom!\n\n")
               end if
          end if
     end if
end while

puts(1,"Enter a sequence value (such as {54,-8,2.3} or \"Hi There!\")\n")

while sequence_received = 'n' do
     inputted_string = get(0)
     if inputted_string[1] = 0 then
          if sequence(inputted_string[2]) then
               sequence_received = 'y'
          end if
     end if
end while

puts(1,"\nThank you! Program Finished!\n")

To convert a character string to either an atom or a sequence value, you use the value() library routine: 

   include get.e
   rs = value(s) 

This works the same way as get(), as it returns a two element sequence value, the first element being the error code, and the second element, if successful, being the actual atom or sequence value equivalent of the character string. The only difference is that the source is a sequence variable (s) and the destination is a receiving sequence variable (rs). A demo is available showing how three character strings are converted to atom and sequence values.
 
Demo program 24
include get.e

sequence character_strings, value_string
object actual_value

character_strings = {"45.99","{1,2,3,{4,4},5}","\"Euphoria\""}

for ix = 1 to 3 do
     printf(1,"Character String: %s\n",{character_strings[ix]})
     value_string = value(character_strings[ix])
     actual_value = value_string[2]
     puts(1,"Euphoria Data Object After value(): ")
     print(1,actual_value)
     puts(1,"\n\n")
end for

You can also convert a Euphoria data object into a character string, or as part of a formatted character string by using sprintf():
 
   rs = sprintf(s,o)
 
sprintf() is similar to printf(), as it takes either an atom value or a sequence representing a list of values (o), which it then edits by using a format string (s). The format codes introduced in our discussion on printf() are used in sprintf() as well. The only differences between printf() and sprintf() is that sprintf() sends the formatted string to a receiving sequence variable (rs), and that sprintf() only requires two parameters in comparison to printf()'s three. A demo is available showing one possible use of sprintf().
 
Demo program 25
sequence print_line

for line = 1 to 5 do
    print_line = sprintf("This is line %03d\n", line)
    puts(1,print_line)
end for

Another way of changing the state of a data object is by altering the case of alphabetic characters. Euphoria has two library routines that can do this for you.
To change any characters between 'A' and 'Z' in both atom and sequence data objects to lowercase, you use the lower() library routine:
 
   include wildcard.e
   ro = lower(o) 
 
With lower(), a character string of "Euphoria" and "EUPHORIA" passed to this library routine as o would produce a string of "euphoria" that is then stored in the receiving variable ro. With single atom values like 'J' or 74, what is stored in the receiving variable is 'j' or 106. The opposite of lower() is upper(), which coverts any characters in both atoms and sequences that are between 'a' and 'z' to uppercase:
 
   include wildcard.e
   ro = upper(o) 

A character string of "Euphoria" and "euphoria" passed to upper(),as o would produce a string of "EUPHORIA", which is then stored in the receiving variable ro. With single atom values like 'z' or 122, upper() will store 'Z' or 90 in the receiving variable. A demo program is available to show how upper() and lower() works.

Demo program 26
include wildcard.e
sequence test_string, uppered, lowered

test_string = "This is a fun way to learn Euphoria!"
uppered = upper(test_string)
lowered = lower(test_string)
printf(1,"Original String     : %s\n",{test_string})
printf(1,"     After lower()  : %s\n",{lowered})
printf(1,"     After upper()  : %s\n",{uppered})

Earlier in the tutorial, we introduced the & operator, which allows you to join atom or sequence data objects together to create new sequences. Euphoria offers other ways of linking data objects together, the first being append():
 
   rs = append(s,o)

append() creates a new sequence, which is stored in variable rs, by adding o to the end of s as an entire element. So how does this differ from the & operator? Do we really need append() anyways? When & joins any two or more data objects, it creates a sequence that is as long as the total number of elements made up by the participating data objects. However, append() will always create a new sequence that is one element longer than the length of s. The reason for this is because append() will make o the new last element of s. When only atoms are involved in the joining, & and append()'s efforts produce the same result. The difference is only apparent when sequences are involved. A demo program is available to help you clarify the usage of append(), with mention being made to show how it differs from the & operator.

Demo program 27
atom     atom1, atom2
sequence seq1, seq2, union

atom1 = 83
atom2 = 4
seq1 = {1,1,1,1}
seq2 = {2,2}

puts(1,"& And append()\n")
puts(1,"==============\n\n")

printf(1,"Atom Values: %d, %d\n",{atom1,atom2})
puts(1,"   Using &: ")

union = atom1 & atom2
print(1,union)
puts(1,"\n")

puts(1,"   Using append(): ")
union = {}
union = append(union,atom1)
union = append(union,atom2)
print(1,union)
puts(1,"\n\n")

puts(1,"Sequence Values: ")
print(1,seq1)
puts(1," ")
print(1,seq2)
puts(1,"\n")
puts(1,"   Using &: ")

union = seq1 & seq2
print(1,union)
puts(1,"\n")

puts(1,"   Using append(): ")
union = {}
union = append(seq1,seq2)
print(1,union)
puts(1,"\n\n")

A related library routine to append() is prepend():
 
   rs = prepend(s,o)

prepend() creates a new sequence, which is stored in variable rs, by adding o to the beginning of s as a single element. This means o becomes the new first element of s, or s[1] in Euphoria terms. Like append(),  prepend() creates a new sequence that is one element longer than s. A demo program is ready to demonstrate prepend().

Demo program 28
atom     atom1, atom2
sequence seq1, seq2, union

atom1 = 83
atom2 = 4
seq1 = {1,1,1,1}
seq2 = {2,2}

puts(1,"& And prepend()\n")
puts(1,"==============\n\n")

printf(1,"Atom Values: %d, %d\n",{atom1,atom2})
puts(1,"   Using &: ")

union = atom1 & atom2
print(1,union)
puts(1,"\n")

puts(1,"   Using prepend(): ")
union = {}
union = prepend(union,atom1)
union = prepend(union,atom2)
print(1,union)
puts(1,"\n\n")

puts(1,"Sequence Values: ")
print(1,seq1)
puts(1," ")
print(1,seq2)
puts(1,"\n")
puts(1,"   Using &: ")

union = seq1 & seq2
print(1,union)
puts(1,"\n")

puts(1,"   Using prepend(): ")
union = {}
union = prepend(seq1,seq2)
print(1,union)
puts(1,"\n\n")

Both append() and prepend() are handy when you want to stack atoms and sequences in a queue, like candies in a "PEZ" dispenser. When append() or prepend() is used to attach a data object to a larger sequence, that data object retains its separate identity. Sequences can also be created "on the fly" by repeating a value so many times. The repeat() library routine was created to perform just that:
 
   rs = repeat(o,a) 

repeat() creates a sequence value a elements long, where each element has the value of o. repeat() can create sequences that are made up of atom or
sequence elements. These created sequences can be as long as you need them to be. A demo is available showing some sequences made by repeat().

Demo program 29
puts(1,"Some Sequences Created By repeat()\n\n")
puts(1,"repeat(20,10):\n   ")
print(1,repeat(20,10))
puts(1,"\n\n")
puts(1,"repeat({1,1,1,1,1},5):\n   ")
print(1,repeat({1,1,1,1,1},5))
puts(1,"\n\n")
puts(1,"repeat(\"Tim\",4):\n   ")
print(1,repeat("Tim",4))
puts(1,"\n")

Once you've created your sequences, it's a good idea to know how large they are if you plan to examine one or many of the elements that make the sequence up. The length() library routine returns the length of a sequence in number of elements: 
 
   ri = length(s) 
 
The length of the sequence, shown here as s, is placed in the receiving variable ri. Note that the returned value is how long sequence s is in elements, not atoms. This means the sequences {{1,1},{1,1}} and {1,1} are the same length in elements, even though the former contains more atoms. A sequence value of {}, which is a null sequence, returns a value of 0. A demo program is available to show how length() can be used in a "for" statement to create a loop that adjusts to the size of a sequence.

Demo program 30
sequence seq
seq = {{0,0,0},{65,{7,7,7},23.1},"Timmy"}
for element1 = 1 to 3 do
    puts(1,"Elements For Sequence ")
    print(1,seq[element1])
    puts(1,":\n")
    for element2 = 1 to length(seq[element1]) do
         printf(1,"   Element %d: ",element2)
         print(1,seq[element1][element2])
         puts(1,"\n")
    end for
    puts(1,"\n")
end for

The next chapter will introduce library routines that search sequences!

ToC

Advanced Data Object Handling, Part Two

As you build larger, more complex sequence data objects, you are going to need tools that can search them quickly. One way is to write some code using "if", "while",  and "for" statements that compare each element against a specific value. A much easier way is to take advantage of Euphoria's sequence search library routines. These library routines allow the programmer to find elements either using a specific value or a partial search string. 
 
   ri = find(o,s)

find() searches sequence s for element o. If found, the element number of o is stored in receiving variable ri. If not, 0 is stored in rifind() starts searching a sequence from the first element onward. If there is more than one element with the search value present in the sequence, find() only returns the element number of the first one. If you want to continue searching after the first match, you will need to search a segment of the sequence, starting with the element following
the first match. A demo program demonstrates the use of find() and also how to match more than one element using find().

Demo program 31
atom found, more_finds, offset
sequence search_string

search_string = {34,5,106,72,65,5,90,17,5,13}
puts(1,"Searching Sequence ")
print(1,search_string)
puts(1," For 5\n\n")

offset = 0
more_finds = 'y'

while more_finds = 'y' do
     found = find(5,search_string)
     if found then
          offset = offset + found
          printf(1,"5 Found As Element %d\n",offset)
          search_string = search_string[found+1..length(search_string)]
     else
          more_finds = 'n'
     end if
end while

puts(1,"\nProgram completed\n")

While find() finds a single element in a sequence, match() allows you to search a sequence for a specfic group of elements: 
 
   ri = match(s1,s2) 

match() searches sequence s2 in order to find a sequence of elements, shown here as s1. If successful, receiving variable ri is assigned the element number in s2 where the first element of s1 is located. What would each of the receiving variables contain after each match()?
 
   atom element_id1, element_id2, element_id3
   element_id1 = match("Al", "David Alan Gay")
   element_id2 = match({3,4,5}, {1,2,3,4,5,6,7,8,9,0})
   element_id3 = match({{50,23,4},{-1,-2}}, {{15,89},{50,23,4},{-1,-2}})
 
Here are the results:

   "David Alan Gay"                 - element_id1 is assigned the value of 7
   {1,2,3,4,5,6,7,8,9,0}            - element_id2 is assigned the value of 3
   {{15,89}, {50,23,4},{-1,-2}}     - element_id3 is assigned the value of 2

If match() cannot find what it is looking for in the searched sequence, then 0 is returned. A demo program is available to further clarify match() if needed.

Demo program 32
sequence nursery_rhyme
atom found
nursery_rhyme = "Jack and Jill went up the hill to fetch a pail of water"
puts(1,nursery_rhyme & "\n\n")
printf(1,"Searching String For \"%s\"\n",{"hill"})
found = match("hill",nursery_rhyme)
printf(1,"     Found \"%s\" beginning at element %d\n\n",{"hill",found})
printf(1,"Searching String For \"%s\"\n",{"l of water"})
found = match("l of water",nursery_rhyme)
printf(1,"     Found \"%s\" beginning at element %d\n\n",{"l of water",
                                                           found})
puts(1,  "Searching String For ")
print(1, {97,110,100})
puts(1,"\n")
found = match({97,110,100},nursery_rhyme)
puts(1,"     Found ")
print(1, {97,110,100})
printf(1," beginning at element %d\n\n",found)

The previous library routines we introduced in this chapter used an actual value to match one or a specific group of elements in a sequence. The next library routine uses "wildcards" to search for elements in sequences. Before we introduce this library routine, we need to discuss what wildcards are. Wildcards are single substitution characters used in conjunction with other characters to make a generic search string. You may have seen wildcards at work when you use the DIR command in DOS as follows:
 
    dir *.com   - lists all files ending with an extension of .COM

Euphoria has two wildcard characters that closely follow DOS' version:  

    *     - matches any 0 or more characters.

For example, a generic search string of "A*" will match values like "Apple", "Acorn", and "A". A generic search string of "*e" would match values like "value"
"cue", and "e".

    ?     - matches any single character.

A generic search string of "g???" for example would match values like "game", "gone", and "goat". A generic search string of "??t" would match values like "Cat",
"dot", and "Hit". With wildcards now explained, we can introduce the wildcard_match() library routine.

    include wildcard.e
    ri = wildcard_match(s1,s2) 

wildcard_match() checks if sequence s2 matches the wildcard pattern defined in sequence s1. A 1 is returned if s2 matches s1, otherwise a 0 is returned. The return value is stored in the receiving variable ri. The use of matching sequence values with wildcard patterns is a little tricky. This is because wildcard_match() takes into consideration both alphabetic case and the placement of the wildcard characters in the pattern string. Look at the examples on the next page to see some common mistakes when using wildcard_match().
 
   atom match_1, match_2, match_3
   match_1 = wildcard_match("a*","ABCDEFGHIJKLMNOPQRSTUVWXYZ")
   match_2 = wildcard_match("?Z","ABCDEFGHIJKLMNOPQRSTUVWXYZ")
   match_3 = wildcard_match("PQR*","ABCDEFGHIJKLMNOPQRSTUVWXYZ")
 
All three variables above will be assigned a value of 0. The first wildcard_match() line won't match because the pattern has a lowercase letter while the searched string is all in uppercase. The second wildcard_match() will not match because ? was used instead of *, even though "Z" is indeed the last letter of the searched string. "?Z" means any two character string, the second character being "Z". The last wildcard_match() line will not match because even though "PQR" does exist in the searched string, the pattern "PQR*" implies a match only if the searched string begins with "PQR". If you want to search for a substring of characters anywhere in the target sequence, place a * wildcard on both sides of the substring. This will produce a match pattern of "*PQR*" for example. You can also mix wildcards in a match pattern, such as "A?c*1". This means wildcard_match() will only get a match on this pattern if the searched string's first character is "A", its third character is "c", and its last character is "1". A demo program is available that allows you to experiment with pattern strings, to help you get a better understanding of wildcard_match().

Demo program 33
include wildcard.e

sequence pattern_string, search_string
atom halt_program, matched

halt_program = 'n'

search_string = "wildcard_match() is a powerful feature of Euphoria."

while halt_program = 'n' do
     puts(1,search_string & "\n")
     puts(1,"Enter a wildcard pattern string or \"STOP\": ")
     pattern_string = gets(0)
     pattern_string = pattern_string[1..(length(pattern_string)-1)]
     if compare(pattern_string,"STOP") = 0 then
          halt_program = 'y'
     else
          matched = wildcard_match(pattern_string, search_string)
          puts(1,"\n")
          if matched then
               puts(1,pattern_string & " matches above string.\n\n")
          else
               puts(1,pattern_string & " does not match above string.\n\n")
          end if
     end if
end while

If you want to write your own sequence search programs, one important factor is the speed on finding the element you are searching for. To optimize your search, it is best to sort the sequence and then look up each element until you either get a match, or compare a value that is larger than the element you are looking for (which means not found). To sort a sequence to be searched, you use the sort() library routine.
 
   include sort.e
   rs = sort(s) 
 
sort() sorts sequence s, but does not change s. The sorted sequence is instead stored in receiving variable rs. The sequence to be sorted can be made up of any combination of atoms and sequences. The result of the sort will be a sequence with its elements sorted in ascending order, with any atom values appearing first before sequence elements. Elements that are sequences are sorted based on an element by element comparison, starting with the first element onward. The comparison is based on the value of each element. Run a demo program now that demonstrates how sort() works with sample data.

Demo program 34
include sort.e
sequence sorted, unsorted

unsorted = {"world","the","Euphoria","rules"}
sorted = sort(unsorted)

puts(1,"Unsorted: ")
for words = 1 to length(unsorted) do
     puts(1,unsorted[words] & " ")
end for
puts(1,"\n")
puts(1,"Sorted: ")
for words = 1 to length(sorted) do
     puts(1,sorted[words] & " ")
end for
puts(1,"\n\n")

unsorted = {{1,1,8,2},5,{1,2,3},{1,1,9},-45,{1,2,1}}
sorted = sort(unsorted)
puts(1,"Unsorted: ")
print(1,unsorted)
puts(1,"\n")
puts(1,"Sorted: ")
print(1,sorted)
puts(1,"\n")

This concludes your introduction to advanced data object handling library routines. The next chapter will introduce library routines that can enhance any arithmetic computations you may have in your programs.

ToC

Advanced Arithmetic Library Routines
 
Euphoria offers a set of library routines that save the programmer from coding complex programs to handle advanced math formulas. These library routines can handle some algebra and trigonometry formulas, rounding down of numbers to the smallest whole number, and even the generation of random numbers. Note that some of these library routines require a strong background in certain areas of mathematics before you attempt to use them. The first library routine we will introduce is sqrt():
 
   ro = sqrt(o) 
 
sqrt() returns the square root of o, which is then stored in variable ro. To refresh your memory, a square root of a number is any number that is multiplied by itself to produce a number. For example, the square root of 25 is 5, because 5 times 5 gives 25. This library routine can accept both atom and sequence data objects. For sequence data objects passed to sqrt(), a sequence with the same length is generated, with each atom element a sequare root of the elements in the original sequence. For example, {16,0.25} passed to sqrt() returns a value of {4,0.5}. The one word of caution is not to pass a negative atom value or a sequence with any negative atom elements to sqrt(), or your program will encounter a runtime error message. A demo program is available showing how atoms and sequences are squared using sqrt().

Demo program 35
atom value1
sequence value2

value1 = 25
value2 = {81,{9,4},100}

puts(1, "The square root of ")
print(1,value1)
puts(1, " is ")
print(1,sqrt(value1))
puts(1,"\n")
puts(1, "The square root of ")
print(1,value2)
puts(1, " is ")
print(1,sqrt(value2))
puts(1,"\n")

The opposite of square-rooting a number is to raise a number by the power of 2. Euphoria has a library routine that can raise a number to the power 2, or any power for that matter. Here is the library routine used to raise a data object value by a given power:
 
   ro = power(o1,o2) 
 
power() raises o1 to the power of o2, the result being stored in receiving variable ro. Because power() can use raise both atoms and sequence data objects to
a power that in itself can also be either an atom or a sequence data object, conversion of values must first occur. If o1 is an atom and o2 is a sequence, Euphoria converts o1 to a sequence value that is the same length as o2,  composed of elements that equal the value of o1. If o1 is a sequence and o2 is an atom, Euphoria converts o2 to a sequence that is the same length as o1, composed of elements equalling the value of o2. This concept was introduced in "Assigning Values To Sequence Variables". Only after any needed conversion of atoms to sequence data objects is completed does power() execute. A demo is available to show how power() works with both atoms and sequences data objects.

Demo program 36
atom base, result
sequence base2, result2

base = 2

for exponent = 1 to 4 do
     result = power(base,exponent)
     printf(1, "%d to the power of %d is %d\n",{base,exponent,result})
end for

puts(1,"\n")

for exponent = 1 to 4 do
    base2 = repeat(10,5)
    result2 = power(base2,exponent)
    print(1, base2)
    puts(1, " to the power of ")
    print(1,exponent)
    puts(1, " is ")
    print(1,result2)
    puts(1,"\n")
end for
puts(1, "\n")

base = 3
result2 = power(base,{2,3,4})
print(1, base)
puts(1, " to the power of ")
print(1,{2,3,4})
puts(1, " is ")
print(1,result2)
puts(1,"\n")

Another library routine related to sqrt() is log()
 
   ro = log(o)

log() returns the natural logarithm of a number, o. A logarithm is the exponent that raises a number, called the base, to a specific power. A natural logarithm is the exponent that raises a base number of 2.71828 (approximately) to a specific power. For example, log(27) will return a value of 3.29584. If you were to raise 2.71828 to the power of 3.29584 by using power(), you would get back a value of 26.9999. log() can handle both atoms and sequences in the same fashion sqrt() can, returning a value that is stored in a receiving variable, named ro here. One note: do not pass a negative number or a zero to log(), or your program will encounter a runtime error. Natural logarithms are used in calculations like statistics and trigonometry, so it is unlikely you will use this library routine much, unless you are working in areas of mathematics that require natural logarithms. A demo program is available if you want to see some examples of how log() is used.

Demo program 37
atom log1, base, result1
sequence log2, result2

base = 2.71828

log1 = log(63)
log2 = log({100,50,25})

result1= power(base,log1)
result2= power(base,log2)

printf(1,"The natural logarithm of 63 is %f\n",log1)

printf(1,"%.5f to the power of %f is %.0f (rounded up)\n\n",
         {base,log1,result1})

puts(1,"The natural logarithm of ")
print(1,{100,50,25})
puts(1," is ")
print(1,log2)
puts(1,"\n")

printf(1,"%.5f to the power of ",base)
print(1,log2)
puts(1," is ")
printf(1,"{%.0f,%.0f,%.0f} (rounded up)\n\n",result2)

When one number does not evenly divide by another, have you wondered what the decimal part of the result means? Well, the numbers to the right of the decimal is what is left over, shown as a decimal fraction. For example, 3.5 returned from dividing 7 by 2 means "3 with 1 left over". How did we get 1? Multiply .5 by the divisor 2 and you get 1. Sometimes this remainder of a division is just as important as the result, and usually it is preferable to have that remainder shown as a whole number. You could use the technique shown above to determine the remainder, or you can use this next Euphoria library routine instead.
 
    ro = remainder(o1,o2)

remainder() returns the remainder left over from dividing o1 by o2, and stores it in the receiving variable ro. The value returned by remainder() is always less than the value of o2, the divisor. Because remainder() can be either atoms or sequences for both the quotient and the divisor, Euphoria will convert an atom to a sequence that will match the length of the other sequence before remainder() is executed. The elements of this new other sequence will have the value of the original atom value. You may want to review power() or the chapter "Assigning Values To Sequence Variables" if you need any help in understanding this. A demo program is available that uses various examples of remainder().

Demo program 38
sequence format_string
atom leftovers, result
format_string = "10 divided by %d goes %d time(s) with %d left over.\n"

for divisor = 2 to 9 do

     leftovers = remainder(10,divisor)

     result = 10/divisor
     printf(1,format_string,{divisor,result,leftovers})

end for

If you are working with floating point numbers and want to convert that value to an integer, one way to do it is to use the floor() library routine:

    ro = floor(o)

floor() takes any data object, o,and rounds it down to the nearest integer value. If o is a sequence, each atom element in that sequence is rounded down to the nearest integer value. Understand that using floor() is not the same as chopping the decimal fraction part off a value. While examples like floor(64.55) or floor ({32.1, 56.87, 2.044}) would result in truncation (64 and {32, 56, 2}), floor(-55.3) and floor({-1.3, -0.5}) would return -56 and {-2,-1}, respectively. If floor() receives an integer, that same value is returned. A demo program is ready to show examples of floor().

Demo program 39
object value1, value2

value1 = 5.3
value2 = -5.3

printf(1,"%.1f floor()'d gives %d\n",{value1,floor(value1)})
printf(1,"%.1f floor()'d gives %d\n",{value2,floor(value2)})
puts(1,"\n")

value1 = {35.3,-46.1,22.9,-.7345}
print(1, value1)
puts(1," floor()'d gives ")
print(1, floor(value1))
puts(1,"\n")

Euphoria has a library routine that may be of interest to those who want to write their own games. It involves the creation of random numbers, a key element in any game, whether it involves randomly generating a number to guess, or creating an unexpected malfunction aboard a spaceship during a critical moment in battle. Here is the syntax of the rand() library routine:

    ro = rand(o) 

rand() will return a randomly generated number. If o is an atom value, the number generated will be from 1 to o. If o is a sequence, the number generated will be from a sequence composed of 1's to o. A randomly generated sequence value will always have the same length as o. The largest integer value (either passed as a single atom or as one or more elements of a sequence) rand() will generate is 1,073,741,823. A demo program is available to show rand()'s use in a guess the number game.

Demo program 40
include get.e

atom random_number,guessed_number, end_program
sequence input_data

puts(1,"Guess any number between 1 and 10\n")

end_program = 'n'
random_number = rand(10)

while end_program = 'n' do
     input_data = get(0)
     if input_data[1] = 0 then
          if integer(input_data[2]) then
               guessed_number = input_data[2]
               if guessed_number = random_number then
                    end_program = 'y'
                    puts(1,"\nBingo!\n")
               elsif guessed_number < random_number then
                    puts(1,"\nYou're too low! Try again!\n")
               elsif guessed_number > random_number then
                    puts(1,"\nYou're too high! Try again!\n")
               end if
          end if
     end if
end while

Left on its own, rand() will generate a unpredictable random value every time it is called. However, some programs may need to repeat the same random values more than once. This is done by setting the random number generator's "seed" (a source value where all rand()-generated values are drawn from) to a certain value. You can do this by using the library routine set_rand():

   include machine.e
   set_rand(a) 

If you execute set_rand() to set the random number generator seed to a, execute rand() three times to generate three different random numbers (let's pretend we generated 51, 67, and 2), then execute set_rand() again using the same value of a, the next three executions of rand() will generate the same values of 51, 67, and 2. If you use the same value to set the random number generator seed, the following rand() executions will always produce the same random values, no matter how many times you re-run your program. A demo program is available showing how to generate the same set of random numbers based on a value from the keyboard.

Demo program 41
include get.e
include machine.e

atom seed, end_program
sequence input_data, prompt, line1, line2, line3
line1 = "\nYou entered "
line2 = " as the value to set the random number generator seed to.\n"
line3 = "The next 10 numbers generated by rand(100) will always be:\n"
prompt = "\nEnter any value or 0 to end this program program\n"

end_program = 'n'

while end_program = 'n' do
     puts(1,prompt)
     input_data = get(0)
     if input_data[1] = 0 then
          if integer(input_data[2]) then
               seed = input_data[2]
               if seed != 0 then
                    puts(1,line1)
                    print(1,seed)
                    puts(1,line2)
                    set_rand(seed)
                    puts(1,line3)
                    for i = 1 to 10 do
                         print(1,rand(100))
                         puts(1, " ")
                    end for
                    puts(1,"\n")
               else
                    end_program = 'y'
               end if
          end if
     end if
end while

To close this chapter, we will briefly introduce a series of library routines devoted to trigonometry:

     ro = sin(o)      - Returns the sine of an angle
     ro = cos(o)      - Returns the cosine of an angle
     ro = tan(o)      - Returns the tangent of an angle
     ro = arctan(o)   - Returns the angle of a tangent (opposite of tan())

The first three library routines accept an atom or a sequence value, o, that is an angle (in radians), and returns the appropriate value in variable o. The last accepts an atom or sequence value that represents a tangent and returns an angle atom or sequence, measured in radians. These library routines come in handy for work in trigonometry, such as using the law of sines and the law of cosines to determine the length of a side of a triangle, or to generate a sine wave on a plane graph. Because trigonometry is a subject out of the scope of this tutorial, we will focus on them long enough just to let you know about them. If you are not familiar with trigonometry, these library routines will not be of any interest to you. They are not mandatory to know in order to learn how to program in Euphoria. This concludes our introduction to math library routines in Euphoria. The next chapter will show you how to work with files and devices.

ToC