shithub: battleship

Download patch

ref: 8285721acfc247d57e0831503543dd29290ac4c5
parent: 7b76e7467822316b699847cbd61a0ecb985882d3
author: rodri <rgl@antares-labs.eu>
date: Sat Aug 12 01:35:54 EDT 2023

latest try of player mgmt procedure. (not working)

--- a/bts.c
+++ b/bts.c
@@ -13,6 +13,7 @@
 char deffont[] = "/lib/font/bit/pelm/unicode.9.font";
 char winspec[32];
 Channel *drawchan;
+Channel *ingress, *egress;
 RFrame worldrf;
 Image *screenb;
 Image *tiletab[NTILES];
@@ -19,7 +20,11 @@
 Board alienboard;
 Board localboard;
 
+struct {
+	int state;
+} game;
 
+
 Point
 fromworld(Point2 p)
 {
@@ -177,13 +182,41 @@
 	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.bx = Vec2(TW,0);
+	localboard.bx = Vec2(TW,0);
+	alienboard.by = Vec2(0,TH);
+	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
+lmb(Mousectl *mc)
+{
+	Board *b;
+	Point2 cell;
+
+	b = nil;
+	if(ptinrect(mc->xy, alienboard.bbox))
+		b = &alienboard;
+	else if(ptinrect(mc->xy, localboard.bbox))
+		b = &localboard;
+
+	if(b != nil){
+		cell = toboard(b, mc->xy);
+		switch(game.state){
+		case Outlaying:
+			settile(b, cell, Tship);
+		case Playing:
+			settile(b, cell, Tmiss);
+			chanprint(egress, "shoot %d-%d", (int)cell.x, (int)cell.y);
+			break;
+		}
+	}
+	send(drawchan, nil);
+}
+
+void
 mouse(Mousectl *mc)
 {
 	mc->xy = subpt(mc->xy, screen->r.min);
@@ -190,15 +223,13 @@
 
 	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);
+		lmb(mc);
 		break;
 	case 2:
+		//mmb(mc);
 		break;
-	case 3:
+	case 4:
+		//rmb(mc);
 		break;
 	}
 }
@@ -233,13 +264,15 @@
 
 	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[0].c = in->mc->c; a[0].v = &in->mc->Mouse; a[0].op = CHANRCV;
+	a[1].c = in->mc->resizec; a[1].v = nil; a[1].op = CHANRCV;
+	a[2].c = in->kc->c; a[2].v = &r; a[2].op = CHANRCV;
 	a[3].op = CHANEND;
 
 	for(;;)
 		switch(alt(a)){
+		case -1:
+			sysfatal("input thread interrupted");
 		case 0:
 			mouse(in->mc);
 			break;
@@ -253,6 +286,51 @@
 }
 
 void
+netrecvthread(void *arg)
+{
+	Ioproc *io;
+	char buf[256];
+	int n, fd;
+
+	threadsetname("netrecvthread");
+
+	fd = *(int*)arg;
+	io = ioproc();
+
+	while((n = ioread(io, fd, buf, sizeof(buf)-1)) > 0){
+		buf[n] = 0;
+		if(debug)
+			fprint(2, "rcvd '%s'\n", buf);
+		if(strcmp(buf, "wait") == 0)
+			game.state = Waiting1;
+		else if(strcmp(buf, "play") == 0)
+			game.state = Playing;
+//		chanprint(ingress, "%s", buf);
+	}
+	closeioproc(io);
+	threadexitsall("connection lost");
+}
+
+void
+netsendthread(void *arg)
+{
+	char *s;
+	int fd;
+
+	threadsetname("netsendthread");
+
+	fd = *(int*)arg;
+
+	while(recv(egress, &s) > 0){
+		if(write(fd, s, strlen(s)) != strlen(s))
+			break;
+		if(debug)
+			fprint(2, "sent '%s'\n", s);
+	}
+	threadexitsall("connection lost");
+}
+
+void
 usage(void)
 {
 	fprint(2, "usage: %s [-d] addr\n", argv0);
@@ -286,6 +364,9 @@
 	else if(debug)
 		fprint(2, "line established\n");
 
+	if(write(fd, "join", 4) != 4)
+		sysfatal("whoops: %r");
+
 	snprint(winspec, sizeof winspec, "-dx %d -dy %d", SCRW, SCRH);
 	if(newwindow(winspec) < 0)
 		sysfatal("newwindow: %r");
@@ -306,10 +387,15 @@
 
 	inittiles();
 	initboards();
+	game.state = Waiting0;
 
 	drawchan = chancreate(sizeof(void*), 0);
+	ingress = chancreate(sizeof(char*), 0);
+	egress = chancreate(sizeof(char*), 0);
 	proccreate(showproc, nil, mainstacksize);
 	threadcreate(inputthread, &in, mainstacksize);
+	threadcreate(netrecvthread, &fd, mainstacksize);
+	threadcreate(netsendthread, &fd, mainstacksize);
 	send(drawchan, nil);
 	yield();
 }
--- a/btsd.c
+++ b/btsd.c
@@ -1,6 +1,5 @@
 #include <u.h>
 #include <libc.h>
-#include <bio.h>
 #include <thread.h>
 #include <draw.h>
 #include <mouse.h>
@@ -10,44 +9,182 @@
 #include "fns.h"
 
 int debug;
+int mainstacksize = 16*KB;
 
+Playerq playerq;
 
+
 void
+pushplayer(Player *p)
+{
+	qlock(&playerq);
+	if(++playerq.nplayers > playerq.cap){
+		playerq.cap = playerq.nplayers;
+		playerq.players = erealloc(playerq.players, playerq.cap * sizeof p);
+	}
+	playerq.players[playerq.nplayers-1] = p;
+	qunlock(&playerq);
+}
+
+Player *
+popplayer(void)
+{
+	Player *p;
+
+	p = nil;
+	if(playerq.nplayers > 0){
+		qlock(&playerq);
+		p = playerq.players[--playerq.nplayers];
+		qunlock(&playerq);
+	}
+	return p;
+}
+
+void
+netrecvthread(void *arg)
+{
+	Chanpipe *cp;
+	Ioproc *io;
+	char buf[256];
+	int n;
+
+	cp = arg;
+	io = ioproc();
+
+	while((n = ioread(io, cp->fd, buf, sizeof(buf)-1)) > 0){
+		buf[n] = 0;
+		chanprint(cp->c, "%s", buf);
+	}
+	chanclose(cp->c);
+	if(debug)
+		fprint(2, "[%d] %d lost connection\n", threadpid(threadid()), threadid());
+}
+
+void
 serveproc(void *arg)
 {
-	Biobuf *bin, *bout;
-	NetConnInfo *nci;
-	char *line;
-	int fd, linelen;
+	NetConnInfo *nci[2];
+	Player **m;
+	Chanpipe *cp;
+	Alt a[3];
+	int i, n0;
+	char *s;
 
-	fd = *(int*)arg;
-	nci = getnetconninfo(nil, fd);
-	if(nci == nil)
+	threadsetname("serveproc ");
+
+	m = arg;
+	s = nil;
+
+	nci[0] = getnetconninfo(nil, m[0]->fd);
+	nci[1] = getnetconninfo(nil, m[1]->fd);
+	if(nci[0] == nil || nci[1] == nil)
 		sysfatal("getnetconninfo: %r");
-	threadsetname("serveproc %s", nci->raddr);
-	freenetconninfo(nci);
+	threadsetname("serveproc %s ↔ %s", nci[0]->raddr, nci[1]->raddr);
+	freenetconninfo(nci[0]);
+	freenetconninfo(nci[1]);
 
-	bin = Bfdopen(fd, OREAD);
-	bout = Bfdopen(fd, OWRITE);
-	if(bin == nil || bout == nil)
-		sysfatal("Bfdopen: %r");
+	cp = emalloc(2*sizeof(Chanpipe));
+	cp[0].c = chancreate(sizeof(char*), 1);
+	cp[0].fd = m[0]->fd;
+	cp[1].c = chancreate(sizeof(char*), 1);
+	cp[1].fd = m[1]->fd;
 
-	while((line = Brdline(bin, '\n')) != nil){
-		linelen = Blinelen(bin);
-		Bwrite(bout, line, linelen);
-		Bflush(bout);
-		print("%.*s", linelen, line);
+	a[0].c = cp[0].c; a[0].v = &s; a[0].op = CHANRCV;
+	a[1].c = cp[1].c; a[1].v = &s; a[1].op = CHANRCV;
+	a[2].op = CHANEND;
+
+	threadcreate(netrecvthread, &cp[0], mainstacksize);
+	threadcreate(netrecvthread, &cp[1], mainstacksize);
+
+	n0 = truerand();
+	write(m[n0%2]->fd, "wait", 4);
+	write(m[(n0+1)%2]->fd, "play", 4);
+
+	while((i = alt(a)) >= 0){
+		if(debug)
+			fprint(2, "[%d] %d said '%s'\n", threadpid(threadid()), threadid(), s);
+		if(a[i].err != nil){
+			write(m[i^1]->fd, "won", 3);
+			/* TODO free the player */
+			pushplayer(m[i^1]);
+			goto out;
+		}
+		if(write(m[i^1]->fd, s, strlen(s)) != strlen(s)){
+			write(m[i]->fd, "won", 3);
+			/* TODO free the player */
+			pushplayer(m[i]);
+			goto out;
+		}
+		free(s);
 	}
+out:
+	if(debug)
+		fprint(2, "[%d] serveproc ending\n", threadpid(threadid()));
+	chanclose(cp[0].c);
+	chanclose(cp[1].c);
+	/* TODO make sure this is the last thread to exit */
+//	recv(cp[0].done)
+//	recv(cp[1].done)
+	free(m);
+}
 
-	Bterm(bin);
-	Bterm(bout);
+void
+reaper(void *)
+{
+	Ioproc *io;
+	char buf[8];
+	ulong i;
+	int n;
+
+	threadsetname("reaper");
+
+	io = ioproc();
+
+	for(;;){
+		for(i = 0; i < playerq.nplayers; i++){
+			n = read(playerq.players[i]->sfd, buf, sizeof buf);
+			if(n < 0 || strncmp(buf, "Closed", 6) == 0){
+				qlock(&playerq);
+				close(playerq.players[i]->fd);
+				close(playerq.players[i]->sfd);
+				free(playerq.players[i]);
+				memmove(&playerq.players[i], &playerq.players[i+1], (--playerq.nplayers-i)*sizeof(Player*));
+				qunlock(&playerq);
+			}
+		}
+		iosleep(io, HZ2MS(3));
+	}
 }
 
 void
+matchmaker(void *)
+{
+	Player **match;
+
+	threadsetname("matchmaker");
+
+	for(;;){
+		if(playerq.nplayers < 2){
+			sleep(100);
+			continue;
+		}
+
+		match = emalloc(2*sizeof(Player*));
+		match[0] = popplayer();
+		match[1] = popplayer();
+		match[1]->o = match[0];
+		match[0]->o = match[1];
+
+		proccreate(serveproc, match, mainstacksize);
+	}
+}
+
+void
 listenthread(void *arg)
 {
-	char *addr, adir[40], ldir[40];
-	int acfd, lcfd, dfd;
+	char *addr, adir[40], ldir[40], aux[128], *s;
+	int acfd, lcfd, dfd, sfd;
+	Player *p;
 
 	addr = arg;
 
@@ -57,11 +194,21 @@
 
 	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);
+			fd2path(dfd, aux, sizeof aux);
+			s = strrchr(aux, '/');
+			*s = 0;
+			snprint(aux, sizeof aux, "%s/status", aux);
+			sfd = open(aux, OREAD);
+			if(sfd < 0)
+				sysfatal("open: %r");
+
+			p = emalloc(sizeof *p);
+			p->fd = dfd;
+			p->sfd = sfd;
+			pushplayer(p);
 		}
 		close(lcfd);
 	}
@@ -94,5 +241,7 @@
 		usage();
 
 	threadcreate(listenthread, addr, mainstacksize);
+	proccreate(matchmaker, nil, mainstacksize);
+	proccreate(reaper, nil, mainstacksize);
 	yield();
 }
--- a/dat.h
+++ b/dat.h
@@ -5,6 +5,11 @@
 	Tmiss,
 	NTILES,
 
+	Waiting0 = 0,
+	Outlaying,
+	Waiting1,
+	Playing,
+
 	Boardmargin = 50,
 	TW = 16,
 	TH = TW,
@@ -12,10 +17,16 @@
 	MAPH = MAPW,
 	SCRW = Boardmargin+MAPW*TW+Boardmargin,
 	SCRH = Boardmargin+MAPH*TH+TH+MAPH*TH+Boardmargin,
+
+	KB = 1024,
 };
 
 typedef struct Input Input;
 typedef struct Board Board;
+typedef struct Ship Ship;
+typedef struct Player Player;
+typedef struct Playerq Playerq;
+typedef struct Chanpipe Chanpipe;
 
 struct Input
 {
@@ -28,4 +39,32 @@
 	RFrame;
 	char map[17][17];
 	Rectangle bbox;
+};
+
+struct Ship
+{
+	RFrame;
+	int ncells;
+	int sunk;
+};
+
+struct Player
+{
+	int fd;
+	int sfd;
+	Player *o; /* opponent */
+};
+
+struct Playerq
+{
+	QLock;
+	Player **players;
+	ulong cap;
+	ulong nplayers;
+};
+
+struct Chanpipe
+{
+	Channel *c;
+	int fd;
 };