[m-rev.] for review: curses games

Peter Wang wangp at students.cs.mu.OZ.AU
Wed Feb 22 15:54:59 AEDT 2006


Estimated hours taken: 10
Branches: main

extras/curs/samples/frogger.m:
extras/curs/samples/nibbles.m:
extras/curs/samples/sleep.m:
	Add two curses games I wrote in December 2004.

Index: extras/curs/samples/frogger.m
===================================================================
RCS file: extras/curs/samples/frogger.m
diff -N extras/curs/samples/frogger.m
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ extras/curs/samples/frogger.m	10 Feb 2006 04:35:55 -0000
@@ -0,0 +1,354 @@
+%-----------------------------------------------------------------------------%
+%
+% A frogger clone, by Peter Wang.
+% This source file is hereby placed in the public domain.
+%
+% Missing features: colour, fly, turtles don't submerge, timeout.
+%
+%-----------------------------------------------------------------------------%
+
+:- module frogger.
+
+:- interface.
+
+:- import_module io.
+
+:- pred main(io::di, io::uo) is det.
+
+%-----------------------------------------------------------------------------%
+
+:- implementation.
+
+:- import_module bool, char, int, list, string.
+
+:- use_module curs, sleep.
+
+:- type world
+	--->	world(
+			lives		:: int,
+			remaining_goals	:: int,
+			frog		:: frog,
+			level		:: level
+		).
+
+:- type frog
+	--->	frog(
+			frog_x	:: int,
+			frog_y	:: int
+		).
+
+:- type level	== list(row).
+
+:- type row
+        --->    row(
+			scroll	:: scroll,
+			str   	:: string
+		).
+
+:- type scroll
+	--->	stationary
+	;	leftwards(int, leftwards_counter::int, bool)
+	;	rightwards(int, rightwards_counter::int, bool)
+	.
+
+:- func initial_world = world.
+
+initial_world = world(
+	3,	% lives
+	5,	% remaining_goals
+	initial_frog,
+	initial_level
+).
+
+:- func width = int.
+:- func height = int.
+
+width = string.length(list.det_head(initial_level) ^ str).
+height = list.length(initial_level).
+
+:- func initial_frog = frog.
+
+initial_frog = frog(width/2, height-1).
+
+:- func initial_level = level.
+
+initial_level = [
+	row(stationary,			"............................"),
+	row(stationary,			":gg::::gg::::gg::::gg::::gg:"),
+	row(rightwards(5, 0, yes),	"~LLLLLL~~~~LLLLLLL~~~LLLLLL~"),
+	row(leftwards(4, 0, yes),	"~~~TtTt~~~~TtTt~~TtTt~~~TtTt"),
+	row(rightwards(6, 0, yes),	"L~~~~~LLLLLLLLLL~~~~~~LLLLLL"),
+	row(leftwards(7, 0, yes),	"TtTt~~~TtTt~~~TtTt~~~~TtTt~~"),
+	row(stationary,			"============================"),
+	row(leftwards(5, 0, no),	"	      Cccc	 Cccc"),
+	row(rightwards(1, 0, no),	"		    cC	     "),
+	row(leftwards(7, 0, no),	"   Cc	    Cc		   Cc"),
+	row(rightwards(6, 0, no),	" cC	  cC		 cC  "),
+	row(leftwards(8, 0, no),	"Cc	 Cc	   Cc	     "),
+	row(stationary,			"============================")
+].
+
+:- pred goal_char(char::in) is semidet.
+
+goal_char('g').
+
+	% Frog cannot touch even a single one of these chars.
+	%
+:- pred frog_cant_touch_1(char::in) is semidet.
+
+frog_cant_touch_1('<').
+frog_cant_touch_1('>').
+frog_cant_touch_1('.').
+frog_cant_touch_1(':').
+frog_cant_touch_1('C').
+frog_cant_touch_1('c').
+
+	% Frog can touch at most one of these chars.
+	%
+:- pred frog_cant_touch_2(char::in) is semidet.
+
+frog_cant_touch_2('~').
+
+:- func game_loop_rate = int.
+
+game_loop_rate = 1000000 / 40.
+
+%-----------------------------------------------------------------------------%
+%-----------------------------------------------------------------------------%
+
+main(!IO) :-
+	curs.start(!IO),
+	curs.nodelay(yes, !IO),
+	curs.flushinp(!IO),
+	game_loop(initial_world, !IO),
+	curs.stop(!IO).
+
+:- pred game_loop(world::in, io::di, io::uo) is det.
+
+game_loop(!.World, !IO) :-
+	(if !.World ^ lives < 1 then
+		end_game(" G A M E   O V E R ", !IO)
+	else if !.World ^ remaining_goals < 1 then
+		end_game(" Y O U   W O N ! ", !IO)
+	else
+		handle_input(!World, !IO, Quit),
+		(
+			Quit = no,
+			handle_logic(!World),
+			draw_world(!.World, !IO),
+			sleep.usleep(game_loop_rate, !IO),
+			move_world(!World),
+			game_loop(!.World, !IO)
+		;
+			Quit = yes
+		)
+	).
+
+%-----------------------------------------------------------------------------%
+
+:- pred draw_world(world::in, io::di, io::uo) is det.
+:- pred draw_level(level::in, io::di, io::uo) is det.
+:- pred draw_level_2(int::in, level::in, io::di, io::uo) is det.
+:- pred draw_row(int::in, string::in, io::di, io::uo) is det.
+:- pred draw_frog(frog::in, io::di, io::uo) is det.
+:- pred draw_status(int::in, io::di, io::uo) is det.
+
+draw_world(World, !IO) :-
+	curs.clear(!IO),
+	draw_level(World ^ level, !IO),
+	draw_frog(World ^ frog, !IO),
+	draw_status(World ^ lives, !IO).
+
+draw_level(Level, !IO) :-
+	draw_level_2(0, Level, !IO).
+
+draw_level_2(_RowNumber, [], !_IO).
+draw_level_2(RowNumber, [Row | Rows], !IO) :-
+	curs.move(RowNumber, 0, !IO),
+	draw_row(0, Row ^ str, !IO),
+	draw_level_2(RowNumber+1, Rows, !IO).
+
+draw_row(N, Str, !IO) :-
+	(if string.index(Str, N, C) then
+		curs.addch(curs.normal, char.to_int(visualise(C)), !IO),
+		draw_row(N+1, Str, !IO)
+	else
+		true
+	).
+
+draw_frog(frog(X, Y), !IO) :-
+	curs.move(Y, X, !IO),
+	curs.addstr(curs.standout, "<>", !IO).
+
+draw_status(Lives, !IO) :-
+	curs.move(height, 0, !IO),
+	curs.addstr(curs.normal, String, !IO),
+	String = string.format(" Lives: %d ", [i(Lives)]). 
+
+	% On screen the 'g' goal tiles are drawn as blanks.
+        %
+:- func visualise(char) = char.
+
+visualise(Char) = (if Char = 'g' then ' ' else Char).
+
+%-----------------------------------------------------------------------------%
+
+:- pred end_game(string::in, io::di, io::uo) is det.
+
+end_game(Message, !IO) :-
+	curs.rows_cols(Rows, Cols, !IO),
+	curs.move(Rows/2, (Cols/2) - string.length(Message)/2, !IO),
+	curs.addstr(curs.normal, Message, !IO),
+	curs.refresh(!IO),
+	sleep.usleep(1000000, !IO).
+
+%-----------------------------------------------------------------------------%
+
+:- pred handle_input(world::in, world::out, io::di, io::uo, bool::out) is det.
+
+handle_input(!World, !IO, Quit) :-
+	curs.getch(K, !IO),
+	(if is_quit(K) then
+		Quit = yes
+	else
+		Quit = no,
+		(if K = curs.key_left then
+			move_frog_left(!World)
+		else if K = curs.key_right then
+			move_frog_right(!World)
+		else if K = curs.key_up then
+			move_frog_up(!World)
+		else if K = curs.key_down then
+			move_frog_down(!World)
+		else 
+			true
+		)
+	).
+
+:- pred is_quit(int::in) is semidet.
+
+is_quit(char.to_int('q')).
+is_quit(27).  % escape
+
+:- pred move_frog_left(world::in, world::out) is det.
+:- pred move_frog_right(world::in, world::out) is det.
+:- pred move_frog_up(world::in, world::out) is det.
+:- pred move_frog_down(world::in, world::out) is det.
+
+move_frog_left(World0, World) :-
+	World0 ^ frog = frog(X, Y),
+	World = World0 ^ frog := frog(max(0, X-1), Y).
+
+move_frog_right(World0, World) :-
+	World0 ^ frog = frog(X, Y),
+	World = World0 ^ frog := frog(min(width-2, X+1), Y).
+
+move_frog_up(World0, World) :-
+	World0 ^ frog = frog(X, Y),
+	World = World0 ^ frog := frog(X, max(0, Y-1)).
+
+move_frog_down(World0, World) :-
+	World0 ^ frog = frog(X, Y),
+	World = World0 ^ frog := frog(X, min(height-1, Y+1)).
+
+%-----------------------------------------------------------------------------%
+
+:- pred move_world(world::in, world::out) is det.
+:- pred move_world_2(int::in, level::in, level::out, frog::in, frog::out)
+	is det.
+:- pred move_row(int::in, row::in, row::out, frog::in, frog::out) is det.
+
+move_world(World0, World) :-
+	move_world_2(0, World0 ^ level, Level, World0 ^ frog, Frog),
+	World = ((World0 ^ level := Level)
+			 ^ frog := Frog).
+
+move_world_2(_, [], [], Frog, Frog).
+move_world_2(RowNumber, [Row0 | Rows0], [Row | Rows], Frog0, Frog) :-
+	move_row(RowNumber, Row0, Row, Frog0, Frog1),
+	move_world_2(RowNumber+1, Rows0, Rows, Frog1, Frog).
+
+move_row(_RowNumber, Row @ row(stationary, _String), Row, Frog, Frog).
+
+move_row(RowNumber, row(leftwards(Speed, Counter, DragFrog), String), Row,
+		Frog0 @ frog(FrogX, FrogY), Frog) :-
+	(if Counter = Speed then
+		string.split(String, 1, Prefix, Suffix),
+		Row = row(leftwards(Speed, 0, DragFrog), Suffix ++ Prefix),
+		(if	DragFrog = yes,
+			RowNumber = FrogY 
+		then
+			Frog = frog(max(0, FrogX-1), FrogY)
+		else
+			Frog = Frog0
+		)
+	else
+		Row = row(leftwards(Speed, Counter+1, DragFrog), String),
+		Frog = Frog0
+	).
+
+move_row(RowNumber, row(rightwards(Speed, Counter, DragFrog), String), Row, 
+		Frog0 @ frog(FrogX, FrogY), Frog) :-
+	(if Counter = Speed then
+		string.split(String, width-1, Prefix, Suffix),
+		Row = row(rightwards(Speed, 0, DragFrog), Suffix ++ Prefix),
+		(if	DragFrog = yes,
+			RowNumber = FrogY 
+		then
+			Frog = frog(min(width-2, FrogX+1), FrogY)
+		else
+			Frog = Frog0
+		)
+	else
+		Row = row(rightwards(Speed, Counter+1, DragFrog), String),
+		Frog = Frog0
+	).
+
+%-----------------------------------------------------------------------------%
+
+:- pred handle_logic(world::in, world::out) is det.
+:- pred check_frog_in_goal(world::in, world::out) is semidet.
+:- pred check_frog_went_splat(world::in, world::out) is semidet.
+:- pred chars_at_frog(world::in, char::out, char::out) is det.
+:- pred stamp_frog_in_goal(world::in, world::out) is det.
+
+handle_logic(!World) :-
+	( check_frog_in_goal(!World) -> true
+	; check_frog_went_splat(!World) -> true
+	; true
+	).
+
+check_frog_in_goal(World0, World) :-
+	chars_at_frog(World0, C1, C2),
+	goal_char(C1),
+	goal_char(C2),
+	stamp_frog_in_goal(World0, World1),
+	World = ((World1 ^ remaining_goals := World0 ^ remaining_goals-1)
+			 ^ frog := initial_frog).
+
+check_frog_went_splat(World0, World) :-
+	chars_at_frog(World0, C1, C2),
+	( frog_cant_touch_1(C1)
+	; frog_cant_touch_1(C2)
+	; frog_cant_touch_2(C1), frog_cant_touch_2(C2) 
+	),
+	World = ((World0 ^ lives := World0 ^ lives - 1)
+			 ^ frog := initial_frog).
+
+chars_at_frog(World, C1, C2) :-
+	frog(X, Y) = World ^ frog,
+	Row = list.index0_det(World ^ level, Y),
+	C1 = string.index_det(Row ^ str, X),
+	C2 = string.index_det(Row ^ str, X+1).
+
+stamp_frog_in_goal(World0, World) :-
+	frog(X, Y) = World0 ^ frog,
+	Level = World0 ^ level,
+	Row = list.index0_det(Level, Y),
+	NewStr = string.set_char_det('<', X,
+		string.set_char_det('>', X+1, Row ^ str)),
+	NewRow = Row ^ str := NewStr,
+	NewLevel = list.replace_nth_det(Level, Y+1, NewRow),
+	World = World0 ^ level := NewLevel.
+
+%-----------------------------------------------------------------------------%
Index: extras/curs/samples/nibbles.m
===================================================================
RCS file: extras/curs/samples/nibbles.m
diff -N extras/curs/samples/nibbles.m
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ extras/curs/samples/nibbles.m	7 Feb 2006 12:40:23 -0000
@@ -0,0 +1,333 @@
+%-----------------------------------------------------------------------------%
+%
+% A nibbles clone by Peter Wang.
+% This source file is hereby placed in the public domain.
+%
+%-----------------------------------------------------------------------------%
+
+:- module nibbles.
+
+:- interface.
+
+:- import_module io.
+
+:- pred main(io::di, io::uo) is det.
+
+%-----------------------------------------------------------------------------%
+
+:- implementation.
+
+:- import_module assoc_list, bool, char, int, list, random, require.
+:- import_module std_util, string, time.
+:- use_module curs, sleep.
+
+:- type rs == random.supply.
+
+:- type world
+	--->	world(
+			cols		:: int,
+			rows		:: int,
+			snake		:: snake,
+			next_apple_num	:: int,
+			apple		:: apple,
+			score		:: int
+		).
+
+:- type snake
+	--->	snake(
+			direction	:: direction,
+			head		:: segment,
+			tail		:: list(segment),
+			growth		:: int
+		).
+
+:- type direction
+	--->	up
+	;	down
+	;	left
+	;	right.
+
+:- type segment == {int, int}.	
+
+:- type apple
+	--->	no_apple
+	;	apple(
+			x	:: int,
+			y	:: int,
+			repr	:: int
+		).
+
+%-----------------------------------------------------------------------------%
+
+main(!IO) :-
+	time.time(Now, !IO),
+	time.localtime(Now) = LocalNow,
+	random.init(LocalNow ^ tm_min * 60 + LocalNow ^ tm_sec, RS),
+	curs.start(!IO),
+	curs.nodelay(yes, !IO),
+	curs.rows_cols(Rows, Cols, !IO),
+	curs.flushinp(!IO),
+	play_game(Cols, Rows, !IO, RS, _RS1),
+	curs.stop(!IO).
+
+:- pred play_game(int::in, int::in, io::di, io::uo, rs::mdi, rs::muo) is det.
+
+play_game(Cols, Rows, !IO, !RS) :-
+	Snake = snake(right, {Cols/2, Rows/2}, [], 10),
+	World = world(Cols, Rows, Snake, 1, no_apple, 0),
+	game_loop(World, !IO, !RS).
+
+:- pred game_loop(world::in, io::di, io::uo, rs::mdi, rs::muo) is det.
+
+game_loop(!.World, !IO, !RS) :-
+	handle_input(!World, !IO, Quit),
+	(
+		Quit = no,
+		move_snake(!World),
+		maybe_eat_apple(!World),
+		draw_world(!.World, !IO),
+		(if snake_is_dead(!.World) then 
+			show_game_over(!IO)
+		else 
+			sleep.usleep(50000, !IO),
+			maybe_replenish_apple(!World, !RS),
+			game_loop(!.World, !IO, !RS)
+		)
+	;
+		Quit = yes
+	).
+
+%-----------------------------------------------------------------------------%
+
+:- pred handle_input(world::in, world::out, io::di, io::uo, bool::out) is det.
+
+handle_input(!World, !IO, Quit) :-
+	curs.getch(Key, !IO),
+	(if quit_key(Key) then
+		Quit = yes
+	else
+		Quit = no,
+		(if direction_key(Key, Dir) then
+			change_snake_direction(Dir, !World)
+		else
+			true
+		)
+	).
+
+:- pred quit_key(int::in) is semidet.
+
+quit_key(char.to_int('q')).
+quit_key(27).	% escape
+
+:- pred direction_key(int::in, direction::out) is semidet.
+:- pred direction_key_2(int::in, direction::out) is cc_nondet.
+
+direction_key(Key, promise_only_solution(direction_key_2(Key))).
+
+direction_key_2(curs.key_up, up).
+direction_key_2(curs.key_down, down).
+direction_key_2(curs.key_left, left).
+direction_key_2(curs.key_right, right).
+
+:- pred change_snake_direction(direction::in, world::in, world::out) is det.
+
+change_snake_direction(NewDir, World0, World) :-
+	(if valid_direction_change(World0 ^ snake ^ direction, NewDir) then
+		World = World0 ^ snake ^ direction := NewDir
+	else 
+		World = World0
+	).
+
+:- pred valid_direction_change(direction::in, direction::in) is semidet.
+
+valid_direction_change(up, left).
+valid_direction_change(up, right).
+valid_direction_change(down, left).
+valid_direction_change(down, right).
+valid_direction_change(left, up).
+valid_direction_change(left, down).
+valid_direction_change(right, up).
+valid_direction_change(right, down).
+
+%-----------------------------------------------------------------------------%
+
+:- pred move_snake(world::in, world::out) is det.
+
+move_snake(World0, World) :-
+	World0 ^ snake = snake(Dir, Head @ {HeadX, HeadY}, Tail, Growth),
+	( Dir = up,	NewHead = {HeadX, HeadY-1}
+	; Dir = down,	NewHead = {HeadX, HeadY+1}
+	; Dir = left,	NewHead = {HeadX-1, HeadY}
+	; Dir = right,  NewHead = {HeadX+1, HeadY}
+	),
+	Result = ordering(Growth, 0),
+	( Result = (>),
+		World = World0 ^ snake := 
+			snake(Dir, NewHead, [Head | Tail], Growth-1)
+	; Result = (=),
+		NewTail = list.take_upto(length(Tail)-1, Tail),
+		World = World0 ^ snake := 
+			snake(Dir, NewHead, [Head | NewTail], Growth)
+	; Result = (<),
+		error("move_snake/2: Growth should be >= 0")
+	).
+
+%-----------------------------------------------------------------------------%
+
+:- pred maybe_eat_apple(world::in, world::out) is det.
+
+maybe_eat_apple(World0, World) :-
+	(
+		World0 ^ apple = no_apple,
+		World = World0
+	;
+		World0 ^ apple = apple(X, Y, _),
+		(if World0 ^ snake ^ head = {X, Y} then
+			World = (((World0
+				 ^ apple := no_apple)
+				 ^ snake ^ growth := inc_growth(World0))
+				 ^ score := World0 ^ score + 10)
+		else
+			World = World0
+		)
+	).
+
+:- func inc_growth(world) = int.
+
+inc_growth(World) = NewGrowth :-
+	Area = (World ^ cols-2) * (World ^ rows-2),
+	Limit = Area/4,
+	Snake = World ^ snake,
+	CurrLength = length(Snake ^ tail) + Snake ^ growth,
+	NewLength = CurrLength + 5,
+	NewGrowth = (if NewLength > Limit 
+			then max(0, Limit - CurrLength)
+			else NewLength - CurrLength).
+
+%-----------------------------------------------------------------------------%
+
+:- pred snake_is_dead(world::in) is semidet.
+
+snake_is_dead(World) :-
+	Head @ {HeadX, HeadY} = World ^ snake ^ head,
+	( HeadX = 0
+	; HeadY = 0
+	; HeadX = World ^ cols-1
+	; HeadY = World ^ rows-1
+	; Head `member` World ^ snake ^ tail
+	).
+
+%-----------------------------------------------------------------------------%
+
+:- pred maybe_replenish_apple(world::in, world::out, rs::mdi, rs::muo) is det.
+
+maybe_replenish_apple(World0, World, !RS) :-
+	(if World0 ^ apple = no_apple then
+		new_apple(World0, !RS, NewApple),
+		NextAppleNum = inc_apple_num(World0 ^ next_apple_num),
+		World = ((World0
+			^ apple := NewApple)
+			^ next_apple_num := NextAppleNum)
+	else 
+		World = World0
+	).
+
+:- pred new_apple(world::in, rs::mdi, rs::muo, apple::out) is det.
+
+new_apple(World, !RS, Apple) :-
+	random.random(1, World ^ cols-2, X, !RS),
+	random.random(1, World ^ rows-2, Y, !RS),
+	(if touches_snake(X, Y, World) then
+		new_apple(World, !RS, Apple)
+	else
+		Apple = apple(X, Y, apple_char(World ^ next_apple_num))
+	).
+
+:- pred touches_snake(int::in, int::in, world::in) is semidet.
+
+touches_snake(X, Y, World) :- {X, Y} = World ^ snake ^ head.
+touches_snake(X, Y, World) :- {X, Y} `member` World ^ snake ^ tail.
+
+:- func inc_apple_num(int) = int.
+
+inc_apple_num(N) = (if N < 9 then N+1 else 1).
+
+:- func apple_char(int) = int.
+
+apple_char(N) = char.to_int('0') + N.
+
+%-----------------------------------------------------------------------------%
+
+:- pred draw_world(world::in, io::di, io::uo) is det.
+:- pred draw_walls(world::in, io::di, io::uo) is det.
+:- pred draw_score(int::in, io::di, io::uo) is det.
+:- pred draw_snake(snake::in, io::di, io::uo) is det.
+:- pred draw_snake_segment(segment::in, io::di, io::uo) is det.
+:- pred draw_apple(apple::in, io::di, io::uo) is det.
+:- pred rect(int::in, int::in, int::in, int::in, char::in, io::di, io::uo)
+	is det.
+
+:- func wall_char = int.
+:- func head_char = int.
+:- func tail_char = int.
+
+wall_char = char.to_int('+').
+head_char = char.to_int('0').
+tail_char = char.to_int('O').
+
+draw_world(World, !IO) :-
+	curs.clear(!IO),
+	draw_walls(World, !IO),
+	draw_score(World ^ score, !IO),
+	draw_snake(World ^ snake, !IO),
+	draw_apple(World ^ apple, !IO).
+
+draw_walls(World, !IO) :-
+	Cols = World ^ cols,
+	Rows = World ^ rows,
+	rect(0, 0, Cols-1, Rows-1, '+', !IO).
+
+draw_score(Score, !IO) :-
+	curs.move(0, 5, !IO),
+	curs.addstr(curs.normal, String, !IO),
+	String = string.format(" Score: %d ", [i(Score)]).
+
+draw_snake(Snake, !IO) :-
+	list.foldl(draw_snake_segment, Snake ^ tail, !IO),
+	Snake ^ head = {HeadX, HeadY},
+	curs.move(HeadY, HeadX, !IO),
+	curs.addch(curs.bold, head_char, !IO).
+
+draw_snake_segment({X,Y}, !IO) :-
+	curs.move(Y, X, !IO),
+	curs.addch(curs.normal, tail_char, !IO).
+
+draw_apple(no_apple, !IO).
+draw_apple(apple(X, Y, Char), !IO) :-
+	curs.move(Y, X, !IO),
+	curs.addch(curs.standout, Char, !IO).
+
+rect(X1,Y1, X2,Y2, Char, !IO) :-
+	char.to_int(Char, C),
+	curs.move(Y1, X1, !IO), curs.hline(C, X2-X1, !IO),
+	curs.move(Y2, X1, !IO), curs.hline(C, X2-X1, !IO),
+	curs.move(Y1, X1, !IO), curs.vline(C, Y2-Y1, !IO),
+	curs.move(Y1, X2, !IO), curs.vline(C, Y2-Y1, !IO).
+
+%-----------------------------------------------------------------------------%
+
+:- pred show_game_over(io::di, io::uo) is det.
+
+show_game_over(!IO) :-
+	Message = " You died, press a key... ",
+	curs.rows_cols(Rows, Cols, !IO),
+	curs.move(Rows/2, (Cols/2) - string.length(Message)/2, !IO),
+	curs.addstr(curs.normal, Message, !IO),
+	curs.refresh(!IO),
+	sleep.usleep(500000, !IO),
+	curs.nodelay(no, !IO),
+	curs.flushinp(!IO),
+	curs.getch(_, !IO),
+	curs.nodelay(yes, !IO).
+
+%-----------------------------------------------------------------------------%
Index: extras/curs/samples/sleep.m
===================================================================
RCS file: extras/curs/samples/sleep.m
diff -N extras/curs/samples/sleep.m
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ extras/curs/samples/sleep.m	7 Feb 2006 12:40:30 -0000
@@ -0,0 +1,36 @@
+%-----------------------------------------------------------------------------%
+
+:- module sleep.
+
+:- interface.
+
+:- import_module io.
+
+	% usleep(MSec, !IO)
+	%
+	% Sleep for MSec microseconds.
+	% Only implemented for Unix-like systems so far.
+	% 
+:- pred usleep(int::in, io::di, io::uo) is det.
+
+%-----------------------------------------------------------------------------%
+
+:- implementation.
+
+:- pragma foreign_decl("C",
+"
+	#include <sys/time.h>
+	#include <sys/types.h>
+	#include <unistd.h>
+").
+
+:- pragma foreign_proc("C",
+	usleep(N::in, IO0::di, IO::uo),
+	[will_not_call_mercury, promise_pure],
+"{
+	struct timeval tv = {0, N};
+	select(0, NULL, NULL, NULL, &tv);
+	IO = IO0;
+}").
+
+%-----------------------------------------------------------------------------%
--------------------------------------------------------------------------
mercury-reviews mailing list
post:  mercury-reviews at cs.mu.oz.au
administrative address: owner-mercury-reviews at cs.mu.oz.au
unsubscribe: Address: mercury-reviews-request at cs.mu.oz.au Message: unsubscribe
subscribe:   Address: mercury-reviews-request at cs.mu.oz.au Message: subscribe
--------------------------------------------------------------------------



More information about the reviews mailing list