319 lines · 6.6 KB · Brainfuck
RawDownload
##       Software from the book "Inferno Programming with Limbo"#       published by John Wiley & Sons, January 2003.##       p. Stanley-Marbell <pip@gemusehaken.org>#implement Pong; include "sys.m";include "draw.m";include "keyring.m";include "security.m";include "daytime.m";include "rand.m"; sys : Sys;draw : Draw;rand : Rand;daytime : Daytime; Display, Screen, Image, Rect, Point, Font: import draw; MAXSPEED	: con 3;INITGAMEDELAY	: con 30; ZP		:= (0,0); gamedelay	: int = INITGAMEDELAY;gameover	: int = 0;leftscore, rightscore : int = 0;leftpaddlerect	: Rect;rightpaddlerect	: Rect;scoreboxrect	: Rect;ballimage	: ref Image;ballwin		: ref Image;ballrect	: ref Rect;scorebox	: ref Image;font		: ref Font;kbdpid		: int; Pong : module{	init : fn(ctxt : ref Draw->Context, args : list of string);}; init(ctxt : ref Draw->Context, nil : list of string){	kbdchan		:= chan of int;	cmdchan		:= chan of int;	paddlespeed	:= 10;	display 	: ref Display;	gamescreen	: ref Screen;	leftpaddle	: ref Image;	rightpaddle	: ref Image;  	sys = load Sys Sys->PATH;	draw = load Draw Draw->PATH;	daytime = load Daytime Daytime->PATH;	random := load Random Random->PATH;	rand = load Rand Rand->PATH;	rand->init(random->randomint(Random->ReallyRandom)); 	if (ctxt == nil)	{		display = Display.allocate(nil);		if (display == nil)		{			sys->raise(sys->sprint(				"fail:Cannot initialize display : %r"));		}	}	else	{		display = ctxt.display;	} 	ballimage = display.open("ball.bit");	if (ballimage == nil)	{		sys->print("Cannot read ball.bit : %r");		exit;	} 	spawn kbd(kbdchan); 	font = Font.open(display, "*default*");	leftpaddlerect = Rect((0, 0), (10, 100));	rightpaddlerect = Rect((display.image.r.dx() - 10, 0),				(display.image.r.dx(), 100));	scoreboxrect = Rect((display.image.r.dx() - 110, 10),				(display.image.r.dx() - 20, 30)); 	#	The game screen is a public screen	gamescreen = Screen.allocate(display.image, 			display.rgb(147, 221, 0), 1);	if (gamescreen == nil)	{		sys->raise(sys->sprint(			"fail:Cannot allocate gamescreen on display : %r"));	} 	#	Paint the display black	display.image.draw(display.image.r, display.rgb(147, 221, 0),		display.ones, display.image.r.min); 	#	Draw the scorebox	scorebox = gamescreen.newwindow(scoreboxrect, Draw->Red);	scorebox.draw(scoreboxrect, scorebox, scorebox,			scoreboxrect.min); 	#	Draw the paddles	leftpaddle = gamescreen.newwindow(leftpaddlerect, Draw->Black);	rightpaddle = gamescreen.newwindow(rightpaddlerect, Draw->Black); 	leftpaddle.draw(leftpaddlerect, leftpaddle, leftpaddle,			leftpaddlerect.min);	rightpaddle.draw(rightpaddlerect, rightpaddle, rightpaddle,			rightpaddlerect.min); 	#	Initial score	updatescore(); 	#	Spawn a new thread to handle ball	spawn	pongball(gamescreen, cmdchan); 	while (!gameover)	{		case (c := <- kbdchan)		{			'q'	=>			{				gameover = 1;				cmdchan <- = 'q';				endsplash(display); 				exit;			}			'x'	=>			{				leftpaddlerect = leftpaddlerect.addpt(					(0, paddlespeed));				leftpaddle.origin(ZP, leftpaddlerect.min);			}			'c'	=>			{				leftpaddlerect = leftpaddlerect.subpt(						(0, paddlespeed));				leftpaddle.origin(ZP, leftpaddlerect.min);			}			'a'	=>			{				rightpaddlerect = rightpaddlerect.addpt(						(0, paddlespeed));				rightpaddle.origin(ZP, rightpaddlerect.min);			}			's'	=>			{				rightpaddlerect = rightpaddlerect.subpt(						(0, paddlespeed));				rightpaddle.origin(ZP, rightpaddlerect.min);			}		}	}} pongball(gamescreen : ref Screen, cmdchan : chan of int){	vector		: ref Point;	midx		: int = 0;  	midx = gamescreen.image.r.dx()/2;	ballrect = ref Rect((midx, 0),			(midx+ballimage.r.dx(), ballimage.r.dy()));	ballwin = gamescreen.newwindow(*ballrect,			Draw->Yellow);	ballwin.draw(ballwin.r, ballimage, 			nil, ballimage.r.min);	vector = ref Point(rand->rand(MAXSPEED)+1,			rand->rand(MAXSPEED)+1); top:	while (1)	alt	{		cmd := <-cmdchan =>		{			break top;			} 		* =>		if (!(sys->millisec() % gamedelay))		{			if ((leftscore == 100) || (rightscore == 100))			{				endsplash(scorebox.display);				gameover = 1; 				break top;			}				moveball(gamescreen, vector);			ballwin.origin(ZP, ballrect.min);		}	}} moveball(gamescreen : ref Screen, vector : ref Point){	*ballrect = (*ballrect).addpt(*vector); 	#	If we hit bottom or top, reflect y-axis	if ((ballrect.max.y >= gamescreen.image.r.max.y) ||		(ballrect.min.y <= gamescreen.image.r.min.y))	{		*vector = (vector.x, -vector.y);		return;	} 	#	If we hit a paddle, reflect y-axis	if (((*ballrect).Xrect(leftpaddlerect)) || 		((*ballrect).Xrect(rightpaddlerect)))	{		*vector = (-vector.x, vector.y);		return;	} 	if (ballrect.max.x >= gamescreen.image.r.max.x)	{		leftscore++;		updatescore();		resetball(gamescreen, vector);	}	else if (ballrect.min.x <= gamescreen.image.r.min.x)	{		rightscore++;		updatescore();		resetball(gamescreen, vector);	}} resetball(gamescreen : ref Screen, vector : ref Point){	midx := gamescreen.image.r.dx()/2;	ballrect = ref Rect((midx, 0), 			(midx+ballimage.r.dx(), ballimage.r.dy())); 	ballwin.origin(ZP, ballrect.min); 	invert := 1;	if (rand->rand(2))	{		invert = -1;  	} 	*vector = Point(invert*(rand->rand(MAXSPEED)+1),			rand->rand(MAXSPEED)+1);} updatescore(){	scorestring := sys->sprint("L %2d: R %2d",			leftscore, rightscore);	textbox := scorebox.r.inset(5);		#	Wipe the scoreboard	scorebox.draw(scorebox.r, scorebox.display.color(Draw->Red),			scorebox.display.ones, scorebox.r.min);		#	Re-draw	scorebox.text(textbox.min, scorebox.display.color(Draw->White),			(0, 0), font, scorestring);	scorebox.draw(scorebox.r, scorebox, scorebox.display.ones, 			scorebox.r.min);		} endsplash(display : ref Display){	font = Font.open(display, "/fonts/lucida/unicode.32.font");	if (font == nil)	{		sys->print("Could not load font : %r");		return;	} 	display.image.text(display.image.r.inset(display.image.r.dx()/3).min,			display.color(Draw->Green), 			(0, 0), font, "Game Over"); 	display.image.draw(display.image.r, display.image,			display.ones, display.image.r.min); 	fd := sys->open("#p/"+string kbdpid+"/ctl", sys->OWRITE);	if (fd != nil)	{		sys->fprint(fd, "kill");	}} kbd(kbdchan : chan of int){	buf := array [1] of byte; 	#	Since this thread blocks on sys calls to read(), we will	#	have to kill it forcefully when the game ends:	kbdpid = sys->pctl(0,nil); 	kfd := sys->open("/dev/keyboard", sys->OREAD);	if (kfd == nil)	{		sys->raise(sys->sprint("fail:Could not open /dev/cons : %r"));	} 	while (sys->read(kfd, buf, 1) == 1)	{		kbdchan <-= int buf[0];	}	sys->raise(sys->sprint(		"fail:Could not read from /dev/cons or ctxt.ckbd: %r"));}