Finnish lottery: pick 7 numbers out of 40.
See also Raiding the Lost Average.
Much guesswork here; I didn’t bother installing the (freely available) ABC interpreter on my computer but tried to figure out the syntax from the Quick Reference. See the Lost Average page for more information.
HOW TO RETURN
lottery
:PUT
{}
IN
line
WHILE
#line
<7
:PUT
random
*39
+1
IN
lot
IF
lot
NOT.IN
line
:PUT
lot
IN
line
WRITE
line
APL (where the abbreviation really means “a programming language”) is one of the oddest, if not the oddest, programming language ever created. It doesn’t use words in any sense of the word (pun not intended) but mathematical symbols. It is extremely concise for the knowledgeable few and horrendously cryptic for the rest of us.
Anyway, the following code, which I stole from Wikipedia (changing just the values to apply to Finnish lottery) is actually picking up 7 numbers out of 40, and since the result is not stored in a variable, APL by its basic rule displays it.
x[⍋x←
7
?
40
]
This is not really a task for AWK whose forte is in reading and parsing
text files. Here the whole body of a normal AWK program is left empty and only
the “BEGIN
” and “END
” sections, intended for pre-
and postformatting respectively, stand. But it works―as soon as you give the
end-of-file character from the keyboard…
# Drawing the lottery line in AWK
BEGIN
{while
(selected
<7
) {lot
=int
(rand
() *40
) +1
if
(!lottery
[lot
]) {lottery
[lot
] =1
selected
++ } } }END
{for
(i
in
lottery
)i
" "
"\n"
}
This solution is in very primitive BASIC to give the feel of the language as it once was. (Those days are far gone―and we are no poorer for that!)
First a table of 40 cells is defined; this automatically sets the value of the cells to 0. Next we get a random number. If the cell in the table whose index is this number is still 0, the number can be used; otherwise we try another number. When 7 numbers are selected, we can print the results and quit.
100
REM Drawing the lottery line in BASIC
110
REM
120
DIM
L
(40
)130
A
=INT
(RND
(1
)*40
)+1
140
IF
L
(A
)=1
THEN GOTO
130
150
L
(A
)=1
160
N
=N
+1
170
IF
N
<7
THEN GOTO
130
180
FOR
I
=1
TO
40
190
IF
L
(I
)=1
THEN PRINT
I
;200
NEXT
I
210
220
END
Follows the lines of the strategy given in the BASIC example above, the control structures are just a bit more advanced.
/* Drawing the lottery line in C */
#include
<stdio.h>
#include
<stdlib.h>
#define
RAND_MAX
40
void
main(void
) {char
lottery
[40
];int
lot
,selected
=0
,i
;while
(selected
<7
) {lot
=rand
();if
(!lottery
[lot
]) {lottery
[lot
] =1
;selected
++; } }for
(i
=0
;i
<40
;i
++) {if
(lottery
[i
])printf
("%n "
,i
+1
);printf
("\n"
); } }
No object-orientedness here: this follows the C solution closely but utilises the new features of C++ (as compared to C).
// Drawing the lottery line in C++
#include
<iostream>void
main(void
) {char
lottery
[40
];int
lot
,selected
=0
;while
(selected
<7
) {lot
=rand
();if
(!lottery
[lot
]) {lottery
[lot
] =1
;selected
++; } }for
(int
i
=0
;i
<40
;i
++) {if
(lottery
[i
])std
::cout
<<i
;std
::cout
<<std
:endl
; } }
We could follow the model of C/C++ here but—like Go—D has a strong standard
library with which to do various things. Here we utilize slices, a
dynamic form of arrays. The find
function from the
std.algorithm
module is used in a similar way to Python’s
in
operator or Lisp’s member
function to find out if
a randomly selected number has already been added to the line.
// Drawing the lottery line in D
import
std.stdio
;import
std.format
;import
std.random
;import
std.algorithm
;void
main() {int
[]selected
;while
(selected
.length
<7
) {auto
lot
=uniform
(1
,40
);if
(find
(selected
,lot
) ==[]
)selected
~=lot
; }sort
(selected
);writefln
("%(%s, %)"
,selected
); }
In a functional language the biggest hurdle to overcome is how to collect a sequence of seven numbers when you cannot change the values of any of the variables. Well, by collecting the list recursively. I have absolutely no idea if this is idiomatic Erlang or not but it works.
%% Drawing the lottery line in Erlang
-module
(lottery
).
-export
([lottery
/0
]).lottery
() ->lottery
([]
).lottery
(Selected
)when
length
(Selected
) <7
->Lot
=random
:uniform
(40
),Updated
=case
lists
:member
(Lot
,Selected
)of
false
-> [Lot
|Selected
];true
->Selected
end
,lottery
(Updated
);lottery
(Selected
) ->lists
:sort
(Selected
).
By contrast to C/C++, here we can do something smarter by utilizing the Go
standard library. First we seed the random number generator with current time
to obtain real (although pseudo-) randomness. Then we
(As the program stands, this is really erroneous: it generates seven random numbers in the range of [0, 40], not [1, 40]. My next task will be to find a simple enough correction for this. Since there seems to be no function in the rand package that allows to set a minimum, I guess the easiest way is to let this stand but correct the numbers by + 1 when displayed to the user.)
// Drawing the lottery line in Go
package
main
import
("fmt"
"math/rand"
"sort"
"time"
)func
main
() {generator
:=rand
.New
(rand
.NewSource
(time
.Now
().UnixNano
()))lottery
:=generator
.Perm
(40
)[:7
]sort
.Ints
(lottery
)fmt
.Println
(lottery
) }
These examples are intended to illustrate the peculiarities―and the power―of Icon.
In the first example we first create a list of 40 elements. Then we set the
elements to consecutive numerical values from 1 to 40. Next, we randomize the
whole list. Note some operators: the asterisk “*
” returns the
length of a list; the exclamation mark “!
” returns the elements
from the list one by one (or generates the list); the question mark
“?
” returns a random element. Icon also allows reversal
assignment (e.g., “a :=: b
” swaps the values of the
variables). Finally, we just print out the first seven numbers of the now
randomized list.
# Drawing the lottery line in Icon
link
random
procedure
main() randomize()lottery
:= list(40
)every
!lottery
:=1
to
40
every
i
:= *lottery
to
2
by
-1
do
lottery
[?i
] :=:lottery
[i
]every
write(lottery
[1
to
7
])end
The second example here uses sets, one of the sequential data types in Icon: it is like a list but the elements are unique. In a way this approximates the working of a real lottery machine.
# Drawing the lottery line in Icon
link
random
procedure
main() randomize()lottery
:= set(1
to
40
)selected
:= set()every
i
:=1
to
7
do
{lot
:= ?lottery
insert(selected
,lot
) delete(lottery
,lot
) }every
i
:= !selected
do
write(i
)end
Julia is a newish language specialized in high-performance computing. There are obvious influences from Python and Scala, and less obvious ones from Lisp (Julia is object-oriented, for example, but its object-orientedness is much more in the vein of Common Lisp than C++ or Ruby.)
# Drawing the lottery line in Julia
lottery
=Int64
[]while
length
(lottery
) <7
lot
=rand
(1
:40
)if
!in
(lot
,lottery
)push!
(lottery
,lot
)end end
println
(join
(sort
(lottery
),", "
))
Here each selected number goes to a list. When drawing the lots again, we just test whether the number already is a member of the list.
;;; Drawing the lottery line in Common LISP
(defun
lottery
() (do
((selected
(list
))) ((=
(length
selected
)7
) (sort
selected
#'<
)) (let
((lot
(random
40
))) (if
(not
(member
lot selected
)) (push
lot selected
)))))
I had actually forgot that Pascal had sets; for a long time the what I had in here followed the “BASIC strategy” but sets make it a bit easier. Not very much though, since outputting sets is clumsy.
The include
procedure and the ability to loop over items in a
set (
) are
FreePascal-specific, otherwise the code should compile on almost any
Pascal.for
elem_var
in
set_var
{ Drawing the lottery line in Pascal }
program
MakeLottery
;type
LotteryNumber
=1
..40
;var
lot
:LotteryNumber
;lottery
:set of
LotteryNumber
;count
:integer
;begin
randomize
;lottery
:=[]
;count
:=0
;repeat
lot
:=random
(40
);if not
(lot
in
lottery
)then begin
include
(lottery
,lot
);count
:=count
+1
end
until
count
=7
;count
:=0
;for
lot
inlottery
do begin
write
(lot
);count
:=count
+1
;if
count
<7
then
write
(', '
)end
;writeln
end
.
Although Perl has lists (well, kind of), there has been no simple way of
checking the existence of an element in one (like Lisp has the
member
function or Python the in
operator). There
are
several workarounds
depending on the version of Perl, and the “smart match” operator
(~~
) in versions 5.10 and newer is almost as the real thing.
It seems to labelled as experimental still in 5.26.1 I’m having on my current
openSUSE box.
The first sample, however, relies on the
“BASIC strategy”.
I’m using the idiosyncratic Perlisms here intentionally. For instance,
there is no real need for the “if
” and “unless
”
clauses to be tailing the statements they control and often it would be best
if they didn’t, but Perl allows that to save you from an extra brace pair.
The next version uses the “smart match” operator mentioned above:# Drawing the lottery line in Perl
my
$selected
=0
;my
@lottery
=()
;while
($selected
<7
) {my
$lot
=int
(rand
(40
)) +1
; $lottery
[$lot
] =1
, $selected
++unless
($lottery
[$lot
]); }for
(my
$i
=1
; $i
<40
; $i
++) {i
+1
." "
if
($lottery
[$i
]); }"\n"
;
# Drawing the lottery line in Perl, the “smart match” version
my
@lottery
=()
;do
{my
$lot
=int
(rand
(40
)) +1
;push
@lottery
, $lot
unless
($lot
~~ @lottery
); }until
($#lottery
==6
); @lottery
=sort
{ $a
<=> $b
} @lottery
;foreach
$lot
(@lottery
) {"$lot\n"
; }
Since Python implemented sets, this exercise became a lot easier: there’s no need to check whether a drawn lottery number is already used, since elements in sets are unique by definition.
# Drawing the lottery line in Python
import
random
lottery
=set
()while
len
(lottery
) <7
:lottery
.add
(random
.randint
(1
,40
))sort
(lottery
)', '
.join
(lottery
))
Racket is an extension of Scheme. While Scheme is a “purist” language mostly intended for teaching computer programming, Racket is designed to be a general-purpose programming language like Common LISP but with a cleaner, Scheme-based syntax and only one namespace for all symbols (Common LISP has two: one for functions and another for everything else).
Since random
returns a
value between [0, 39], the map add1
adds 1 to make
it [1, 40]. Finally the resulting list is (ascendingly) sorted for prettier
output.
#lang racket
;;; Drawing the lottery line in Racket
(require
racket/set
) (define
(lottery-engine selected
) (if
(=
(set-count
selected
)7
)selected
(let
([updated
(set-add
selected
(random
40
))]) (lottery-engine updated
)))) (define
(make-lottery
) (define
lottery
(lottery-engine
(set
))) (sort
(map
add1
(set->list
lottery
))<
))
Standard REXX does not have array variables. The so-called “stem variables”
can sometimes do the trick, as in here, but even though lottery.1
is pretty much equivalent to lottery[1]
in some other programming
languages, there’s a catch: it is no error for the “index” (which is not
really an index in REXX but rather a “key”) to be an arbitrary name, such as
an erroneously uninitialized variable. When numeric indices are used it’s
customary to use index 0 as a tally to keep track of the largest index.
/* Drawing the lottery line in REXX */
lottery
.0
=0
do until
lottery
.0
=7
lot
=random
(40
) +1
if
lottery
.lot
=0
then do
lottery
.lot
=1
lottery
.0
=lottery
.0
+1
end end do
i
=1
to
40
if
lottery
.i
=1
then
say
i
end
This is very close to identical to the code in (Common)
Lisp,
the only differences being (a) instead of nil
, the empty list
is always written ()
in Scheme, and (b) there no handy
push
macro with which to use lists as stacks; instead it is
necessary to use append
.
;;; Drawing the lottery line in Scheme
(define
lottery
() (do
((selected
())) ((=
(length
selected
)7
) (sort
selected
<
)) (let
((lot
(random
40
))) (if
(not
(member
lot selected
)) (append
'(lot
)selected
)))))
Tcl is a silly language. You can do almost anything with it, but for a non-adherent it sure requires some keen studying with the manual. Shell-like syntax makes some simple things―like setting a variable to a nonliteral value―needlessly complicated.
# Drawing the lottery line in TCL
package require
math
while
{ [llength
$selected
] <7
} {set
lot
[ ::math::random
1 40
]if
{ [lsearch
selected
$lot
] ==-1
} {lappend
selected
$lot
} }foreach
i
$selected
{puts
$i
}