Plan 9 from Bell Labs’s /usr/web/sources/contrib/paurea/goban/ifc.c

Copyright © 2021 Plan 9 Foundation.
Distributed under the MIT License.
Download the Plan 9 distribution.


#include <u.h>
#include <libc.h>
#include <thread.h>
#include <draw.h>
#include <keyboard.h>
#include <mouse.h>
#include "igo.h"

enum {
	DGobrown=0xEE9E00FF,
	DSTbord=0x303030FF,
	Cmdmaxsz=128,
	↑=61454,
	↓=128,
	DELETEKEY=113,
	Stonesz=3,  //divider of Δ
	Thickln=25, //divider of Δ
	Pointsz=5,	//divider of Δ
	Countsz=5,	//divider of Δ
	Szmin=150,
	Szmax=1500
};

static int Δx,  Δy;
static int bpoints, wpoints, clk;
static Point pdr, pul;
static int visible;

Keyboardctl 	*keyboardctl;
Mousectl		*mousectl;


static int Δx,  Δy;
static Point pul,fontcorn;
static int bdead,wdead,clk;
static Image *pixbg,*pixfg,*pixko,*pixwht,*pixst, *pixyell, *pixbl;

static int drawstone(Point pos,char type);

static void 
drawgoban(void)
{
	int i,j;
	Point pos;

	for (i=0; i<Hcapsz; i++){
		pos=hcap[i];
		drawstone(pos,'p');
	}
	for (i=1; i<Bansz+1; i++){
			for (j=1; j<Bansz+1; j++){
				if(goban[i][j]!='d'){
					pos.x=i;
					pos.y=j;
					drawstone(pos, goban[i][j]);
				}
			}
	}
	if(moves)
		drawstone(lstone,'l');
}

static void
rmvlabel(void)
{
	Rectangle r;
	r.min=pul;
	r.max.x=fontcorn.x;
	r.max.y=pul.y+Δy-Pointsz;
	draw(screen, r, pixbg, nil, ZP);
}


static void
drwlabel(int bdead, int wdead, int time)
{
	Font *defont;
	Rune r[40];

	rmvlabel();
	defont = display->defaultfont;
	runesprint(r, "b: %d w: %d time: %d",bdead, wdead,time);
	fontcorn=runestring(screen, pul, pixfg,  ZP, defont,r);
}

static void
redraw(void)
{
	int i;
	Point pur, pdl, pdr, st,end; //up down left right (pul is global)
	 
	/* points on the corners of the goban*/
	
	pul=Pt(screen->r.min.x,screen->r.min.y);
	pdr=Pt(screen->r.max.x,screen->r.max.y);

	pur.y=pul.y;
	pur.x=pdr.x;
	pdl.x=pul.x;
	pdl.y=pdr.y;

	Δx=abs(pur.x-pul.x)/(Bansz+1);
	Δy=abs(pdl.y-pul.y)/(Bansz+1);

	draw(screen, screen->r, pixbg, nil, ZP);
	for (i=1; i<Bansz+1; i++){
		st=Pt(pul.x+i*Δx,pul.y+Δy);
		end=Pt(pdl.x+i*Δx,pul.y+Δy*Bansz);
		line(screen,st,end, Endsquare, Endsquare,1, pixfg, Pt(0,0));

		st=Pt(pul.x+Δx,pul.y+i*Δy);
		end=Pt(pul.x+Δx*Bansz,pur.y+i*Δy);
		line(screen,st,end, Endsquare, Endsquare,1, pixfg, Pt(0,0));
	}
	drawgoban();
	drwlabel(bdead,wdead,clk);
	flushimage(display,1);
}

void
resized(int new)
{
	if (new && getwindow(display, Refnone) < 0 )
		exits("getwindow failed");
	redraw();
}

static Point 
calcmove(Point p)
{
	Point pos;
	pos=Pt((Δx/2+p.x)/Δx,(Δy/2+p.y)/Δy);
    if(pos.x > Bansz)
		pos.x=-1;
    if(pos.y > Bansz)
		pos.y=-1;
    if(pos.x < 1)
		pos.x=-1;
    if(pos.y<1)
		pos.y=-1;
	return pos;
}

static void
initifc(void)
{
	bdead=0;
	wdead=0;
	clk=0;


	visible = 1;
	cleangoban();
	if (initdraw(nil, nil, "goifc") < 0)
		exits("initdraw failed");

	pixbl  = allocimage(display, Rect(0,0,1,1), screen->chan, 1, DBluegreen);
	pixbg  = allocimage(display, Rect(0,0,1,1), screen->chan, 1, DGobrown);
	pixfg  = allocimage(display, Rect(0,0,1,1), screen->chan, 1, DBlack);
	pixwht = allocimage(display, Rect(0,0,1,1), screen->chan, 1, DWhite);
	pixst  = allocimage(display, Rect(0,0,1,1), screen->chan, 1, DSTbord);
	pixko  = allocimage(display, Rect(0,0,1,1), screen->chan, 1, DRed);
	pixyell  = allocimage(display, Rect(0,0,1,1), screen->chan, 1, DYellow);
	if(!pixbg||!pixfg||!pixwht||!pixst)
		exits("out of image memory");
	redraw();
}


static int
drawstone(Point pos,char type)
{
	int xpos, ypos, radx ,rady, notup, notleft, notright, notdown, i;
	Point lpos, st, end;

	if(!visible)
		return 0;

	xpos = pos.x;
	ypos = pos.y;

	notright=!(xpos==19);
	notleft=!(xpos==1);
	notup=!(ypos==19);
	notdown=!(ypos==1);

	xpos = pul.x+xpos*Δx;
	ypos = pul.y+ypos*Δy;

	lpos = Pt(xpos, ypos);
	radx = Δx/Stonesz;
	rady = Δy/Stonesz;
	if(type!=Emptystone && type!='p' && type!=Lstone)
		drawstone(pos, Emptystone);
	switch(type){
		case Bstone:
			fillellipse(screen,  Pt(xpos,ypos),radx,rady, pixfg, Pt(0,0));
			ellipse(screen, Pt(xpos,ypos),radx-1,rady-1,1, pixst, Pt(0,0));
		break;
		case Wstone:
			fillellipse(screen, Pt(xpos,ypos),radx,rady, pixwht, Pt(0,0));
			ellipse(screen, Pt(xpos,ypos),radx-1,rady-1,1, pixfg, Pt(0,0));
		break;
		case 't':
		dprint("triangle...");
		break;
		case 'p':
			radx = Δx/Pointsz;
			rady = Δy/Pointsz;
			fillellipse(screen, Pt(xpos,ypos), radx,rady, pixfg, Pt(0,0));
		break;
		case Cntstone:
			radx = Δx/Countsz;
			rady = Δy/Countsz;
			fillellipse(screen, Pt(xpos,ypos),radx,rady, pixbl, Pt(0,0));
			//drawellipse("black", nil, lpos, Pt(radx, rady));
		break;
		case Wmarked:
			fillellipse(screen,  Pt(xpos,ypos),radx,rady, pixwht, Pt(0,0));
			ellipse(screen, Pt(xpos,ypos),radx-1,rady-1,1, pixfg, Pt(0,0));
			radx = Δx/Pointsz-1;
			rady = Δy/Pointsz-1;
			
			fillellipse(screen,  Pt(xpos,ypos),radx,rady, pixyell, Pt(0,0)); //yellow and black
			ellipse(screen, Pt(xpos,ypos),radx-1,rady-1,1, pixfg, Pt(0,0));
		break;
		case Bmarked:
			fillellipse(screen,  Pt(xpos,ypos),radx,rady, pixfg, Pt(0,0));
			ellipse(screen, Pt(xpos,ypos),radx-1,rady-1,1, pixst, Pt(0,0));
			radx = Δx/Pointsz-1;
			rady = Δy/Pointsz-1;
			fillellipse(screen,  Pt(xpos,ypos),radx,rady, pixyell, Pt(0,0)); 
		break;
		case Kou:
			radx = Δx/Pointsz;
			rady = Δy/Pointsz;
			fillellipse(screen,  Pt(xpos,ypos),radx,rady, pixko, Pt(0,0));
		break;
		
		case Lstone:
			radx = Δx/Countsz-1;
			rady = Δy/Countsz-1;
			fillellipse(screen,  Pt(xpos,ypos),radx,rady, pixko, Pt(0,0));
		break;
		case Emptystone:
			fillellipse(screen, Pt(xpos,ypos), radx,rady, pixbg, Pt(0,0));
			st=Pt(xpos+notright*radx+1,ypos);
			end=Pt(xpos-notleft*radx-1,ypos);
			line(screen,st,end, Endsquare, Endsquare,1, pixfg, Pt(0,0));
 
			st=Pt(xpos,ypos+notup*rady+1);
			end=Pt(xpos,ypos-notdown*rady-1);
			line(screen,st,end, Endsquare, Endsquare,1, pixfg, Pt(0,0));
			for(i=0;i<9;i++)
				if(pos.x==hcap[i].x && pos.y==hcap[i].y)
					drawstone(pos,'p');
		break;
		default:
			sysfatal("drawstone: weird stone: %d", type);
		break;
	}
	return 0;
}


void
opdraw(Move *m, char)
{
	drawstone(m->Point, goban[m->x][m->y]);
}



Channel *ifcchan;
int waskou;

void
ifcthread(void *)
{
	Move *mdead, *mv;
	int ndead;
	mdead=nil;

	while(mv=recvp(ifcchan)){
		if(moves && visible)
			drawstone(lstone, goban[lstone.x][lstone.y]);
		if(lkou.type)
			waskou++;
		ndead=move(mv,&mdead);

		dprint("ndead = %d\n", ndead);
		if(ndead >= 0 && visible && waskou){
			dprint("cleaning\n");
			drawstone(lkou, Emptystone);
			lkou.type = '\0';
		}
		waskou = 0;
		if(ndead>0){
			bdead+=ndead;
			if(visible)
				drwlabel(bdead,wdead,0);
		}
		if(ndead>=0){
			opdraw(mv, goban[mv->x][mv->y]);
			opgrp(mdead, '\0', opdraw);
		}
		if(lstone.type)
			drawstone(lstone, Lstone);
		sendp(ifcchan,mdead);
		mdead=nil;
		//flushimage(display,1);
	}
}

enum{
	Noev=0,
	Click1,
	Click2,
	Click3,
};


static int 
mouseevrd (Mouse *mev)
{
	int button;

	button=mev->buttons;
	if (button==1){
		return Click1;
    	}

	if (button==2){
		return Click2;
	}

	if (button==4){
		return Click3;
	}

	return 0;			
}

enum {
		Akeyboard,
		Areshape,
		Amouse,
		NALT
};


void
opsend(Move *m, char)
{
	Move *mdead;

	if(!m){
	dprint("nil\n");
		return;
	}
	m->next = nil;
	sendp(ifcchan,m);
	mdead=recvp(ifcchan);
	freegrp(mdead);
}

void
inthread(void *)
{
	int desvx,desvy, pressed, nw, nb, ndead;
	Point pos;
	static Alt alts[NALT+1];
	Rune	r;
	Mouse	m;
	Move *mv, *mdead;
	
	threadsetname("inthread");
	initifc();
	alts[Akeyboard].c = keyboardctl->c;
	alts[Akeyboard].v = &r;
	alts[Akeyboard].op = CHANRCV;
	alts[Areshape].c = mousectl->resizec;
	alts[Areshape].v = nil;
	alts[Areshape].op = CHANRCV;
	alts[Amouse].c = mousectl->c;
	alts[Amouse].v = &m;
	alts[Amouse].op = CHANRCV;
	alts[NALT].op = CHANEND;
	
	while(1){
		visible = 1;
		switch(alt(alts)) {
			case Akeyboard:
				if(r==DELETEKEY)
					threadexitsall(nil);
				else if(r=='q')
					threadexitsall(nil);
				else if(r=='c'){
					trycount(&nw, &nb);
					bdead += nb;
					wdead += nw;
					drwlabel(bdead,wdead,clk);
					drawgoban();
					flushimage(display,1);
				}
				else if(r=='u' && moves){
					visible = 0;
					mv = moves;
					mv = freelast(mv);
					moves = nil;
					bdead = 0;
					wdead = 0;
					cleangoban();
					if(mv)
						opgrp(mv, '\0', opsend);
					visible = 1;
					drwlabel(bdead,wdead,clk);
					drawgoban();
					flushimage(display,1);
				}
			break;	
			case Areshape:
				resized(1);
			break;
			case Amouse:
					//coordinates are global, relativice them
				desvx=(m.xy.x)-screen->r.min.x;  
				desvy=(m.xy.y)-screen->r.min.y;
				pos=calcmove(Pt(desvx,desvy));
				pressed=mouseevrd(&m);
				if(pressed && isvalidpos(pos)){
					mv=getmove(pos);
					if(pressed==Click1){
						mv->type='W';
						sendp(ifcchan,mv);
						mdead=recvp(ifcchan);
					}
					else if(pressed==Click2){
						mv->type='B';
						sendp(ifcchan,mv);
						mdead=recvp(ifcchan);
					}
					else if(pressed==Click3){
						if(strchr(emptytype, mv->type)!=nil)
							break;
						ndead = markdead(mv, &mdead);
						if(mdead->type=='B')
							wdead+=ndead;
						else if(mdead->type=='W')
							bdead+=ndead;
						drwlabel(bdead,wdead,clk);
						drawgoban();
					}
					else
						break;
					flushimage(display,1);
					opgrp(mdead,0,opprint);
					freegrp(mdead);
					freegrp(mv);
				}
			break;
		}
	}
}

Bell Labs OSI certified Powered by Plan 9

(Return to Plan 9 Home Page)

Copyright © 2021 Plan 9 Foundation. All Rights Reserved.
Comments to webmaster@9p.io.