shithub: battleship

Download patch

ref: 7b76e7467822316b699847cbd61a0ecb985882d3
author: rodri <rgl@antares-labs.eu>
date: Tue Aug 8 04:35:17 EDT 2023

initial commit.

--- /dev/null
+++ b/alloc.c
@@ -1,0 +1,44 @@
+#include <u.h>
+#include <libc.h>
+#include <draw.h>
+
+void*
+emalloc(ulong n)
+{
+	void *p;
+
+	p = malloc(n);
+	if(p == nil)
+		sysfatal("malloc: %r");
+	setmalloctag(p, getcallerpc(&n));
+	return p;
+}
+
+void*
+erealloc(void *p, ulong n)
+{
+	void *np;
+
+	np = realloc(p, n);
+	if(np == nil){
+		if(n == 0)
+			return nil;
+		sysfatal("realloc: %r");
+	}
+	if(p == nil)
+		setmalloctag(np, getcallerpc(&p));
+	else
+		setrealloctag(np, getcallerpc(&p));
+	return np;
+}
+
+Image*
+eallocimage(Display *d, Rectangle r, ulong chan, int repl, ulong col)
+{
+	Image *i;
+
+	i = allocimage(d, r, chan, repl, col);
+	if(i == nil)
+		sysfatal("allocimage: %r");
+	return i;
+}
--- /dev/null
+++ b/bts.c
@@ -1,0 +1,315 @@
+#include <u.h>
+#include <libc.h>
+#include <thread.h>
+#include <draw.h>
+#include <mouse.h>
+#include <keyboard.h>
+#include <geometry.h>
+#include "dat.h"
+#include "fns.h"
+
+int debug;
+
+char deffont[] = "/lib/font/bit/pelm/unicode.9.font";
+char winspec[32];
+Channel *drawchan;
+RFrame worldrf;
+Image *screenb;
+Image *tiletab[NTILES];
+Board alienboard;
+Board localboard;
+
+
+Point
+fromworld(Point2 p)
+{
+	p = invrframexform(p, worldrf);
+	return Pt(p.x,p.y);
+}
+
+Point2
+toworld(Point p)
+{
+	return rframexform(Pt2(p.x,p.y,1), worldrf);
+}
+
+Point
+fromboard(Board *b, Point2 p)
+{
+	p = invrframexform(invrframexform(p, *b), worldrf);
+	return Pt(p.x,p.y);
+}
+
+Point2
+toboard(Board *b, Point p)
+{
+	return rframexform(rframexform(Pt2(p.x,p.y,1), worldrf), *b);
+}
+
+Image *
+gettileimage(int type)
+{
+	if(type < 0 || type > nelem(tiletab))
+		return nil;
+	return tiletab[type];
+}
+
+void
+settile(Board *b, Point2 cell, int type)
+{
+	Point p;
+
+	p.x = cell.x;
+	p.y = cell.y;
+	b->map[p.x][p.y] = type;
+}
+
+void
+drawtile(Image *dst, Board *b, Point2 cell, int type)
+{
+	Point p;
+	Image *ti;
+
+	p = fromboard(b, cell);
+	ti = gettileimage(type);
+	if(ti == nil)
+		return;
+
+	draw(dst, Rpt(p, addpt(p, Pt(TW,TH))), ti, nil, ZP);
+}
+
+void
+drawboard(Image *dst, Board *b)
+{
+	int i, j;
+
+	for(i = 0; i < MAPW; i++)
+		for(j = 0; j < MAPH; j++)
+			drawtile(dst, b, Pt2(i,j,1), b->map[i][j]);
+}
+
+void
+redraw(void)
+{
+	lockdisplay(display);
+
+	draw(screenb, screenb->r, display->black, nil, ZP);
+	drawboard(screenb, &alienboard);
+	drawboard(screenb, &localboard);
+
+	draw(screen, screen->r, screenb, nil, ZP);
+
+	flushimage(display, 1);
+	unlockdisplay(display);
+}
+
+void
+resize(void)
+{
+	lockdisplay(display);
+	if(getwindow(display, Refnone) < 0)
+		sysfatal("resize failed");
+	unlockdisplay(display);
+
+	freeimage(screenb);
+	screenb = eallocimage(display, rectsubpt(screen->r, screen->r.min), screen->chan, 0, DNofill);
+	send(drawchan, nil);
+}
+
+void
+inittiles(void)
+{
+	Image *brush;
+	int i, x, y;
+	Point pts[2];
+
+	for(i = 0; i < nelem(tiletab); i++){
+		tiletab[i] = eallocimage(display, Rect(0,0,TW,TH), screen->chan, 0, DNofill);
+		switch(i){
+		case Twater:
+			brush = eallocimage(display, Rect(0,0,1,1), screen->chan, 1, DPalegreyblue);
+			draw(tiletab[i], tiletab[i]->r, brush, nil, ZP);
+			freeimage(brush);
+			brush = eallocimage(display, Rect(0,0,1,1), screen->chan, 1, DPalebluegreen);
+			for(pts[0] = ZP, x = 0; x < TW; x++){
+				y = sin(x)*TH/2;
+				pts[1] = Pt(x,y+TH/2);
+				line(tiletab[i], pts[0], pts[1], Endsquare, Endsquare, 0, brush, ZP);
+				pts[0] = pts[1];
+			}
+			freeimage(brush);
+			break;
+		case Tship:
+			brush = eallocimage(display, Rect(0,0,1,1), screen->chan, 1, 0x333333FF);
+			draw(tiletab[i], tiletab[i]->r, brush, nil, ZP);
+			freeimage(brush);
+			brush = eallocimage(display, Rect(0,0,1,1), screen->chan, 1, DBlack);
+			fillellipse(tiletab[i], Pt(TW/2,TH/2), 2, 2, brush, ZP);
+			freeimage(brush);
+			break;
+		case Thit:
+			brush = eallocimage(display, Rect(0,0,1,1), screen->chan, 1, DRed);
+			draw(tiletab[i], tiletab[i]->r, brush, nil, ZP);
+			freeimage(brush);
+			brush = eallocimage(display, Rect(0,0,1,1), screen->chan, 1, DBlack);
+			pts[0] = Pt(TW/2-TW/4,TH/2-TH/4);
+			pts[1] = Pt(TW/2+TW/4,TH/2+TH/4);
+			line(tiletab[i], pts[0], pts[1], Endsquare, Endsquare, 1, brush, ZP);
+			pts[0].y += TH/2;
+			pts[1].y -= TH/2;
+			line(tiletab[i], pts[0], pts[1], Endsquare, Endsquare, 1, brush, ZP);
+			freeimage(brush);
+			break;
+		case Tmiss:
+			draw(tiletab[i], tiletab[i]->r, tiletab[Twater], nil, ZP);
+			brush = eallocimage(display, Rect(0,0,1,1), screen->chan, 1, DWhite);
+			ellipse(tiletab[i], Pt(TW/2,TH/2), 6, 6, 1, brush, ZP);
+			freeimage(brush);
+			break;
+		}
+	}
+}
+
+void
+initboards(void)
+{
+	memset(alienboard.map, Twater, MAPW*MAPH);
+	alienboard.p = Pt2(Boardmargin,Boardmargin,1);
+	memset(localboard.map, Twater, MAPW*MAPH);
+	localboard.p = addpt2(alienboard.p, Vec2(0,MAPH*TH+TH));
+	alienboard.bx = localboard.bx = Vec2(TW,0);
+	alienboard.by = localboard.by = Vec2(0,TH);
+	alienboard.bbox = Rpt(fromworld(alienboard.p), fromworld(addpt2(alienboard.p, Pt2(TW*MAPW,TH*MAPH,1))));
+	localboard.bbox = Rpt(fromworld(localboard.p), fromworld(addpt2(localboard.p, Pt2(TW*MAPW,TH*MAPH,1))));
+}
+
+void
+mouse(Mousectl *mc)
+{
+	mc->xy = subpt(mc->xy, screen->r.min);
+
+	switch(mc->buttons){
+	case 1:
+		if(ptinrect(mc->xy, alienboard.bbox))
+			settile(&alienboard, toboard(&alienboard, mc->xy), Tmiss);
+		if(ptinrect(mc->xy, localboard.bbox))
+			settile(&localboard, toboard(&localboard, mc->xy), Tmiss);
+		send(drawchan, nil);
+		break;
+	case 2:
+		break;
+	case 3:
+		break;
+	}
+}
+
+void
+key(Rune r)
+{
+	switch(r){
+	case Kdel:
+	case 'q':
+		threadexitsall(nil);
+	}
+}
+
+void
+showproc(void *)
+{
+	threadsetname("showproc");
+
+	while(recv(drawchan, nil) > 0)
+		redraw();
+
+	sysfatal("showproc died");
+}
+
+void
+inputthread(void *arg)
+{
+	Input *in;
+	Rune r;
+	Alt a[4];
+
+	in = arg;
+
+	a[0].op = CHANRCV; a[0].c = in->mc->c; a[0].v = &in->mc->Mouse;
+	a[1].op = CHANRCV; a[1].c = in->mc->resizec; a[1].v = nil;
+	a[2].op = CHANRCV; a[2].c = in->kc->c; a[2].v = &r;
+	a[3].op = CHANEND;
+
+	for(;;)
+		switch(alt(a)){
+		case 0:
+			mouse(in->mc);
+			break;
+		case 1:
+			resize();
+			break;
+		case 2:
+			key(r);
+			break;
+		}
+}
+
+void
+usage(void)
+{
+	fprint(2, "usage: %s [-d] addr\n", argv0);
+	threadexitsall("usage");
+}
+
+void
+threadmain(int argc, char *argv[])
+{
+	char *addr;
+	int fd;
+	Input in;
+
+	GEOMfmtinstall();
+	ARGBEGIN{
+	case 'd':
+		debug++;
+		break;
+	default: usage();
+	}ARGEND
+	if(argc != 1)
+		usage();
+
+	addr = netmkaddr(argv[0], "tcp", "3047");
+	if(debug)
+		fprint(2, "connecting to %s\n", addr);
+
+	fd = dial(addr, nil, nil, nil);
+	if(fd < 0)
+		sysfatal("dial: %r");
+	else if(debug)
+		fprint(2, "line established\n");
+
+	snprint(winspec, sizeof winspec, "-dx %d -dy %d", SCRW, SCRH);
+	if(newwindow(winspec) < 0)
+		sysfatal("newwindow: %r");
+	if(initdraw(nil, deffont, "bts") < 0)
+		sysfatal("initdraw: %r");
+	if((in.mc = initmouse(nil, screen)) == nil)
+		sysfatal("initmouse: %r");
+	if((in.kc = initkeyboard(nil)) == nil)
+		sysfatal("initkeyboard: %r");
+
+	display->locking = 1;
+	unlockdisplay(display);
+
+	screenb = eallocimage(display, rectsubpt(screen->r, screen->r.min), screen->chan, 0, DNofill);
+	worldrf.p = Pt2(0,0,1);
+	worldrf.bx = Vec2(1,0);
+	worldrf.by = Vec2(0,1);
+
+	inittiles();
+	initboards();
+
+	drawchan = chancreate(sizeof(void*), 0);
+	proccreate(showproc, nil, mainstacksize);
+	threadcreate(inputthread, &in, mainstacksize);
+	send(drawchan, nil);
+	yield();
+}
--- /dev/null
+++ b/btsd.c
@@ -1,0 +1,98 @@
+#include <u.h>
+#include <libc.h>
+#include <bio.h>
+#include <thread.h>
+#include <draw.h>
+#include <mouse.h>
+#include <keyboard.h>
+#include <geometry.h>
+#include "dat.h"
+#include "fns.h"
+
+int debug;
+
+
+void
+serveproc(void *arg)
+{
+	Biobuf *bin, *bout;
+	NetConnInfo *nci;
+	char *line;
+	int fd, linelen;
+
+	fd = *(int*)arg;
+	nci = getnetconninfo(nil, fd);
+	if(nci == nil)
+		sysfatal("getnetconninfo: %r");
+	threadsetname("serveproc %s", nci->raddr);
+	freenetconninfo(nci);
+
+	bin = Bfdopen(fd, OREAD);
+	bout = Bfdopen(fd, OWRITE);
+	if(bin == nil || bout == nil)
+		sysfatal("Bfdopen: %r");
+
+	while((line = Brdline(bin, '\n')) != nil){
+		linelen = Blinelen(bin);
+		Bwrite(bout, line, linelen);
+		Bflush(bout);
+		print("%.*s", linelen, line);
+	}
+
+	Bterm(bin);
+	Bterm(bout);
+}
+
+void
+listenthread(void *arg)
+{
+	char *addr, adir[40], ldir[40];
+	int acfd, lcfd, dfd;
+
+	addr = arg;
+
+	acfd = announce(addr, adir);
+	if(acfd < 0)
+		sysfatal("announce: %r");
+
+	if(debug)
+		fprint(2, "listening on %s\n", addr);
+	
+	while((lcfd = listen(adir, ldir)) >= 0){
+		if((dfd = accept(lcfd, ldir)) >= 0){
+			proccreate(serveproc, &dfd, mainstacksize);
+			close(dfd);
+		}
+		close(lcfd);
+	}
+
+	threadexitsall("listen: %r");
+}
+
+void
+usage(void)
+{
+	fprint(2, "usage: %s [-d] [-a addr]\n", argv0);
+	threadexitsall("usage");
+}
+
+void
+threadmain(int argc, char *argv[])
+{
+	char *addr;
+
+	addr = "tcp!*!3047";
+	ARGBEGIN{
+	case 'd':
+		debug++;
+		break;
+	case 'a':
+		addr = EARGF(usage());
+		break;
+	}ARGEND
+	if(argc != 0)
+		usage();
+
+	threadcreate(listenthread, addr, mainstacksize);
+	yield();
+}
--- /dev/null
+++ b/dat.h
@@ -1,0 +1,31 @@
+enum {
+	Twater,
+	Tship,
+	Thit,
+	Tmiss,
+	NTILES,
+
+	Boardmargin = 50,
+	TW = 16,
+	TH = TW,
+	MAPW = 17,
+	MAPH = MAPW,
+	SCRW = Boardmargin+MAPW*TW+Boardmargin,
+	SCRH = Boardmargin+MAPH*TH+TH+MAPH*TH+Boardmargin,
+};
+
+typedef struct Input Input;
+typedef struct Board Board;
+
+struct Input
+{
+	Mousectl *mc;
+	Keyboardctl *kc;
+};
+
+struct Board
+{
+	RFrame;
+	char map[17][17];
+	Rectangle bbox;
+};
--- /dev/null
+++ b/fns.h
@@ -1,0 +1,8 @@
+#define HZ2MS(hz)	(1000/(hz))
+
+/*
+ * alloc
+ */
+void *emalloc(ulong);
+void *erealloc(void*, ulong);
+Image *eallocimage(Display*, Rectangle, ulong, int, ulong);
--- /dev/null
+++ b/mkfile
@@ -1,0 +1,24 @@
+</$objtype/mkfile
+
+MAN=/sys/man/1
+BIN=/$objtype/bin/games
+TARG=\
+	bts\
+	btsd\
+
+OFILES=\
+	alloc.$O\
+
+HFILES=\
+	dat.h\
+	fns.h\
+
+</sys/src/cmd/mkmany
+
+install:V: man
+
+uninstall:V:
+	for(i in $TARG){
+		rm -f $BIN/$i
+		rm -f $MAN/$i
+	}