#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;
}
}
}
|