Technical Musings

Thoughts, Ideas, and Experimentation

View on GitHub
21 September 2021

Guessing Game in ATS

by Timmy Jose

Here is the quintessential guessing game as implemented in ATS.

The SATS file (the public external specification)

(* guessing_game.sats *)

fun play(): void

and the DATS file (the implementation):

(* guessing_game.dats *)

#include "share/atspre_define.hats"
#include "share/atspre_staload.hats"

staload "guessing_game.sats"

staload STDLIB = "libats/libc/SATS/stdlib.sats"
staload UN = "prelude/SATS/unsafe.sats"
staload TIME = "libats/libc/SATS/time.sats"

fun generate_secret
  (lower: int, upper: int): int =
  let 
    val () = $STDLIB.srand48($UN.cast{lint}($TIME.time_get()))
    val range = $UN.cast{lint}(upper - lower + 1)
    val random = $STDLIB.lrand48() mod range + $UN.cast{lint}(lower)
  in
    $UN.cast{int}(random)
  end

fun read_guess(): int = 
  let
    macdef MAXLEN = 20
    var inp = @[char][MAXLEN]()
    val () = print!("Enter guess: ")
    val bc = $extfcall(int, "scanf", "%s", addr@inp)
    val () = assertloc(bc != 0)
  in
    g0string2int($UN.cast{string}(addr@inp))
  end

fun play_aux
  (secret: int, guesses: int): void = 
  let
    val guess = read_guess()
  in
    ifcase
      | guess < secret => (println!("Too small! Try again..."); play_aux(secret, guesses + 1))
      | guess > secret => (println!("Too big! Try again..."); play_aux(secret, guesses + 1))
      | _ => 
          let
            val guesses = guesses + 1
          in
            println!("You win! You took ", guesses, " guesses.")
          end
  end

implement play() = 
  let
    val secret = generate_secret(1, 100)
    val guesses = 0
  in
    play_aux(secret, guesses)
  end

implement main0() = play()

and finally, the Makefile:

ATSFLAGS := -DGNU_SOURCE -DATS_MEMALLOC_LIBC -cleanaft -flto -O3 -latslib

GUESSING_GAME_SRC := guessing_game.sats guessing_game.dats
GUESSING_GAME_OBJ := ${GUESSING_GAME_SRC}
GUESSING_GAME_OBJ := ${patsubst %.sats, %_sats.o, ${GUESSING_GAME_OBJ}}
GUESSING_GAME_OBJ := ${patsubst %.dats, %_dats.o, ${GUESSING_GAME_OBJ}}

guessing_game: ${GUESSING_GAME_OBJ}
	acc pc ${ATSFLAGS} -o $@ $^

%_sats.o: %.sats
	acc pc -c $< || touch $@

%_dats.o: %.dats
	acc pc -DATS_MEMALLOC_LIBC -c $< || touch $@

clean:
	rm -f *.o *_?ats.c guessing_game

Running it:

$ make clean && make && ./guessing_game
rm -f *.o *_?ats.c guessing_game
acc pc -c guessing_game.sats || touch guessing_game_sats.o

------------------ C COMPILER MESSAGES ------------------

clang: warning: argument unused during compilation: '-L/Users/z0ltan/dev/forks/ATS2-Postiats/ccomp/atslib/lib' [-Wunused-command-line-argument]

-------------- END C COMPILER MESSAGES ------------------

acc pc -DATS_MEMALLOC_LIBC -c guessing_game.dats || touch guessing_game_dats.o

------------------ C COMPILER MESSAGES ------------------

clang: warning: argument unused during compilation: '-L/Users/z0ltan/dev/forks/ATS2-Postiats/ccomp/atslib/lib' [-Wunused-command-line-argument]

-------------- END C COMPILER MESSAGES ------------------

acc pc -DGNU_SOURCE -DATS_MEMALLOC_LIBC -cleanaft -flto -O3 -latslib -o guessing_game guessing_game_sats.o guessing_game_dats.o
Enter guess: 50
Too small! Try again...
Enter guess: 75
Too small! Try again...
Enter guess: 88
Too big! Try again...
Enter guess: 82
Too big! Try again...
Enter guess: 78
Too small! Try again...
Enter guess: 80
Too small! Try again...
Enter guess: 81
You win! You took 7 guesses.

< Home