def setstore(self, store): self.store = store self.container.x() self.pieces = {} for pieceletter in self.store.split(""): p = piecelettertopiece(pieceletter) if p.color == self.color: if p.kind in self.pieces: self.pieces[p.kind]["mul"] += 1 else: pcdiv = Div().pr().w(self.piecesize).h(self.piecesize) pdiv = Div().pa().cp().ac(getclassforpiece(p, self.parent.piecestyle)).w(self.piecesize).h(self.piecesize) pdivcopy = Div().pa().cp().ac(getclassforpiece(p, self.parent.piecestyle)).w(self.piecesize).h(self.piecesize) pdiv.t(0).l(0).sa("draggable", True).ae("dragstart", self.dragstartfactory(p, pdiv, pdivcopy)) pcdiv.a(pdiv) self.pieces[p.kind] = { "mul": 1, "p": p, "pcdiv": pcdiv } for pkind, pdesc in self.pieces.items(): muldiv = Div().pa().w(self.muldivsize).h(self.muldivsize).fs(self.muldivsize * 1.3).html("{}".format(pdesc["mul"])) muldiv.l(self.piecesize - self.muldivsize).t(0).ac("storemuldiv") pdesc["pcdiv"].a(muldiv) self.container.a(pdesc["pcdiv"]) return self
class BasicBoard(e): def clearcanvases(self): self.movecanvas.clear() self.piececanvashook.x() self.arrowdiv.x() def ucitosquare(self, squci): try: file = squci.charCodeAt(0) - "a".charCodeAt(0) rank = self.lastrank - ( squci.charCodeAt(1) - "1".charCodeAt(0) ) return Square(file, rank) except: return None def ucitomove(self, moveuci): if "@" in moveuci: try: parts = moveuci.split("@") sq = self.ucitosquare(parts[1]) move = Move(sq, sq, Piece(parts[0].toLowerCase(), self.turn())) return move except: return None else: try: move = Move(self.ucitosquare(moveuci[0:2]), self.ucitosquare(moveuci[2:4])) try: if len(moveuci) > 4: move.prompiece = Piece(moveuci[4].toLowerCase(), self.turn()) except: print("could not parse prompiece") return move except: return None def resize(self, width, height): self.squaresize = 35 self.calcsizes() while self.totalheight() < height: self.squaresize += 1 self.calcsizes() self.squaresize -= 1 self.calcsizes() self.build() def totalheight(self): th = self.outerheight + cpick(self.showfen, self.fendivheight, 0) if self.variantkey == "crazyhouse": th += 2 * self.squaresize return th def squareuci(self, sq): fileletter = String.fromCharCode(sq.file + "a".charCodeAt(0)) rankletter = String.fromCharCode(self.lastrank - sq.rank + "1".charCodeAt(0)) return fileletter + rankletter def moveuci(self, move): fromuci = self.squareuci(move.fromsq) touci = self.squareuci(move.tosq) promuci = cpick(move.prompiece.isempty(), "", move.prompiece.kind) return fromuci + touci + promuci def islightfilerank(self, file, rank): return ( ( ( file + rank ) % 2 ) == 0 ) def islightsquare(self, sq): return self.islightfilerank(sq.file, sq.rank) def squarelist(self): squarelist = [] for file in range(self.numfiles): for rank in range(self.numranks): squarelist.append(Square(file, rank)) return squarelist def squarecoordsvect(self, sq): return Vect(sq.file * self.squaresize, sq.rank * self.squaresize) def squarecoordsmiddlevect(self, sq): return self.squarecoordsvect(sq).p(Vect(self.squaresize / 2, self.squaresize / 2)) def piececoordsvect(self, sq): return self.squarecoordsvect(sq).p(Vect(self.squarepadding, self.squarepadding)) def flipawaresquare(self, sq): if self.flip: return Square(self.lastfile - sq.file, self.lastrank - sq.rank) return sq def piecedragstartfactory(self, sq, pdiv): def piecedragstart(ev): if self.promoting or self.show: ev.preventDefault() return self.dragkind = "move" self.draggedsq = sq self.draggedpdiv = pdiv self.movecanvashook.x() pdiv.op(0.1) return piecedragstart def piecedragfactory(self): def piecedrag(ev): pass return piecedrag def piecedragendfactory(self, sq, pdiv): def piecedragend(ev): pdiv.op(0.5) return piecedragend def piecedragoverfactory(self, sq): def piecedragover(ev): ev.preventDefault() return piecedragover def ismovepromotion(self, move): fromp = self.getpieceatsquare(move.fromsq) if ( fromp.kind == "p" ) and ( fromp.color == self.turn() ): if self.iswhitesturn(): if move.tosq.rank == 0: return True else: if move.tosq.rank == self.lastrank: return True return False def piecedropfactory(self, sq): def piecedrop(ev): ev.preventDefault() self.draggedpdiv.pv(self.piececoordsvect(self.flipawaresquare(sq))) self.draggedpdiv.zi(100) if self.dragkind == "move": self.dragmove = Move(self.draggedsq, sq) if self.ismovepromotion(self.dragmove): self.promoting = True self.build() elif not ( self.movecallback is None ): self.movecallback(self.variantkey, self.fen, self.moveuci(self.dragmove)) elif self.dragkind == "set": self.container.a(self.draggedpdiv) if not ( self.movecallback is None ): setuci = "{}@{}".format(self.draggedsetpiece.kind, self.squareuci(sq)) self.movecallback(self.variantkey, self.fen, setuci) return piecedrop def buildsquares(self): self.container.x() self.sqdivs = {} self.sqhdivs = {} for sq in self.squarelist(): sqclass = cpick(self.islightsquare(sq), "boardsquarelight", "boardsquaredark") sqdiv = Div().ac(["boardsquare", sqclass]).w(self.squaresize).h(self.squaresize) sqhdiv = Div().pa().w(self.squaresize).h(self.squaresize) self.sqdivs[sq.hashkey()] = sqdiv self.sqhdivs[sq.hashkey()] = { "div": sqhdiv, "cumop": 0.0 } fasq = self.flipawaresquare(sq) sqdiv.pv(self.squarecoordsvect(fasq)) sqhdiv.pv(self.squarecoordsvect(fasq)) sqdiv.ae("dragover", self.piecedragoverfactory(sq)) sqdiv.ae("drop", self.piecedropfactory(sq)) sqhdiv.ae("dragover", self.piecedragoverfactory(sq)) sqhdiv.ae("drop", self.piecedropfactory(sq)) self.container.a([sqdiv, sqhdiv]) p = self.getpieceatsquare(sq) if p.ispiece(): pdiv = Div().ac("boardpiece").w(self.piecesize).h(self.piecesize).pv(self.piececoordsvect(fasq)) pdiv.ac(getclassforpiece(p, self.piecestyle)).sa("draggable", True) pdiv.ae("dragstart", self.piecedragstartfactory(sq, pdiv)) pdiv.ae("drag", self.piecedragfactory()) pdiv.ae("dragend", self.piecedragendfactory(sq, pdiv)) pdiv.ae("dragover", self.piecedragoverfactory(sq)) pdiv.ae("drop", self.piecedropfactory(sq)) pdiv.zi(10) if self.variantkey == "threeCheck": if ( p.kind == "k" ): mul = self.getthreelifesforcolor(p.color) lifesdiv = Div().pa().t(- self.squaresize / 10).l(self.squaresize / 2 + self.squaresize / 10).w(self.squaresize / 2).h(self.squaresize / 2) lifesdiv.ac("boardthreechecklifesdiv").fs(self.squaresize / 1.5).html("{}".format(mul)) lifesdiv.c(["#ff0", "#ff0"][p.color]) pdiv.a(lifesdiv) self.container.a(pdiv) def getthreelifesforcolor(self, color): parts = self.threefen.split("+") mul = 3 if color == WHITE: try: mul = int(parts[2]) except: print("warning, could not parse white lifes from", self.threefen) if color == BLACK: try: mul = int(parts[0]) except: print("warning, could not parse black lifes from", self.threefen) return mul def prompiececlickedfactory(self, prompiecekind): def prompiececlicked(): self.dragmove.prompiece = Piece(prompiecekind, self.turn()) self.movecallback(self.variantkey, self.fen, self.moveuci(self.dragmove)) return prompiececlicked def buildprominput(self): promkinds = prompiecekindsforvariantkey(self.variantkey) promsq = self.dragmove.tosq.copy() dir = cpick(promsq.rank >= ( self.numranks / 2 ), -1, 1) ppks = prompiecekindsforvariantkey(self.variantkey) for ppk in ppks: fapromsq = self.flipawaresquare(promsq) pp = Piece(ppk, self.turn()) psqdiv = Div().pa().cp().zi(150).w(self.squaresize).h(self.squaresize).ac("boardpromotionsquare") psqdiv.pv(self.squarecoordsvect(fapromsq)) ppdiv = Div().pa().cp().zi(200).w(self.piecesize).h(self.piecesize).ac(getclassforpiece(pp, self.piecestyle)) ppdiv.pv(self.piececoordsvect(fapromsq)).ae("mousedown", self.prompiececlickedfactory(ppk)) self.container.a([psqdiv, ppdiv]) promsq = promsq.p(Square(0, dir)) def promotecancelclick(self): self.promoting = False self.build() def drawmovearrow(self, move, args = {}): if move is None: return strokecolor = args.get("strokecolor", "#FFFF00") linewidth = args.get("linewidth", 0.2) * self.squaresize headwidth = args.get("headwidth", 0.2) * self.squaresize headheight = args.get("headheight", 0.2) * self.squaresize tomv = self.squarecoordsmiddlevect(self.flipawaresquare(move.tosq)) frommv = self.squarecoordsmiddlevect(self.flipawaresquare(move.fromsq)) if False: self.movecanvas.lineWidth(linewidth) self.movecanvas.strokeStyle(strokecolor) self.movecanvas.fillStyle(strokecolor) self.movecanvas.drawline(frommv, tomv) dv = Vect(headwidth, headheight) self.movecanvas.fillRect(tomv.m(dv), tomv.p(dv)) if not ( move.prompiece.isempty() ): pf = 4 dvp = Vect(linewidth * pf, linewidth * pf) move.prompiece.color = self.turn() ppdiv = Div().pa().cp().ac(getclassforpiece(move.prompiece, self.piecestyle)).w(linewidth * 2 * pf).h(linewidth * 2 * pf) ppdiv.pv(tomv.m(dvp)) self.piececanvashook.a(ppdiv) arrow = Arrow(frommv, tomv, { "linewidth": linewidth, "pointwidth": headheight * 4, "pointheight": headheight * 4, "color": strokecolor }) self.arrowdiv.a(arrow) def drawuciarrow(self, uci, args = {}): self.drawmovearrow(self.ucitomove(uci), args) def highlightsquare(self, sq, bc, op): if op == 0: return margin = self.squaresize * 0.1 hsize = self.squaresize - 2 * margin sqhdiv = self.sqhdivs[sq.hashkey()] if op > sqhdiv["cumop"]: sqhdiv["cumop"] = op sqhdiv["div"].x().a(Div().pa().t(margin).l(margin).w(hsize).h(hsize).bc(bc).op(sqhdiv["cumop"])) def highlightmove(self, move, bc, op): self.highlightsquare(move.fromsq, bc, op) self.highlightsquare(move.tosq, bc, op) def highlightucimove(self, uci, bc, op): self.highlightmove(self.ucitomove(uci), bc, op) def buildgenmove(self): if "genmove" in self.positioninfo: if not ( genmove == "reset" ): genmoveuci = self.positioninfo["genmove"]["uci"] genmove = self.ucitomove(genmoveuci) if not ( genmove is None ): genmove.prompiece = Piece() self.drawmovearrow(genmove) def fentextchanged(self): if self.fentextchangedcallback: self.fentextchangedcallback(self.fentext.getText()) def build(self): self.sectioncontainer = Div().ac("boardsectioncontainer").w(self.outerwidth) self.sectioncontainer.bci(self.background) self.outercontainer = Div().ac("boardoutercontainer").w(self.outerwidth).h(self.outerheight) self.outercontainer.bci(self.background) self.container = Div().ac("boardcontainer").w(self.width).h(self.height).t(self.margin).l(self.margin) self.container.bci(self.background) self.outercontainer.a(self.container) self.buildsquares() self.turndiv = Div().pa().w(self.turndivsize).h(self.turndivsize).bc(cpick(self.iswhitesturn(), "#fff", "#000")) if self.variantkey == "racingKings": self.turndiv.t(cpick(self.flip, 0, self.outerheight - self.turndivsize)) if xor(self.isblacksturn(), self.flip): self.turndiv.l(0) else: self.turndiv.l(self.outerwidth - self.turndivsize) else: self.turndiv.l(self.outerwidth - self.turndivsize).t(cpick(xor(self.isblacksturn(), self.flip), 0, self.outerheight - self.turndivsize)) self.outercontainer.a(self.turndiv) if self.promoting: self.buildprominput() self.container.ae("mousedown", self.promotecancelclick) self.fentext = TextInput({}).w(self.width).fs(10).setText(self.fen) self.fentext.changecallback = self.fentextchanged self.fendiv = Div().ac("boardfendiv").h(self.fendivheight).a(self.fentext) if self.variantkey == "crazyhouse": self.whitestorediv = Div().ac("boardstorediv").h(self.squaresize).w(self.outerwidth) self.whitestorediv.bci(self.background) self.blackstorediv = Div().ac("boardstorediv").h(self.squaresize).w(self.outerwidth) self.blackstorediv.bci(self.background) self.whitestore = PieceStore({ "show": self.show, "parent": self, "color": WHITE, "store": self.crazyfen, "containerdiv": self.whitestorediv }) self.blackstore = PieceStore({ "show": self.show, "parent": self, "color": BLACK, "store": self.crazyfen, "containerdiv": self.blackstorediv }) if self.flip: self.sectioncontainer.a([self.whitestorediv, self.outercontainer, self.blackstorediv]) else: self.sectioncontainer.a([self.blackstorediv, self.outercontainer, self.whitestorediv]) else: self.sectioncontainer.a([self.outercontainer]) if self.showfen: self.sectioncontainer.a(self.fendiv) self.x().a(self.sectioncontainer) self.movecanvas = Canvas(self.width, self.height).pa().t(0).l(0) self.movecanvashook = Div().pa().t(0).l(0).zi(5).op(0.5) self.piececanvashook = Div().pa().t(0).l(0).zi(11).op(0.5) self.arrowdiv = Div().pa() self.container.a([self.movecanvashook, self.arrowdiv, self.piececanvashook]) self.movecanvashook.a(self.movecanvas) self.buildgenmove() return self def setflip(self, flip): self.flip = flip self.build() def calcsizes(self): self.lastfile = self.numfiles - 1 self.lastrank = self.numranks - 1 self.area = self.numfiles * self.numranks self.width = self.numfiles * self.squaresize self.height = self.numranks * self.squaresize self.avgsize = ( self.width + self.height ) / 2 self.margin = self.marginratio * self.avgsize self.squarepadding = self.squarepaddingratio * self.squaresize self.piecesize = self.squaresize - 2 * self.squarepadding self.outerwidth = self.width + 2 * self.margin self.outerheight = self.height + 2 * self.margin self.turndivsize = self.margin self.fendivheight = 25 def parseargs(self, args): self.fentextchangedcallback = args.get("fentextchangedcallback", None) self.positioninfo = args.get("positioninfo", {}) self.show = args.get("show", False) self.showfen = args.get("showfen", True) self.squaresize = args.get("squaresize", 45) self.squarepaddingratio = args.get("squarepaddingratio", 0.04) self.marginratio = args.get("marginratio", 0.02) self.numfiles = args.get("numfiles", 8) self.numranks = args.get("numranks", 8) self.piecestyle = args.get("piecestyle", "alpha") self.flip = args.get("flip", False) self.movecallback = args.get("movecallback", None) self.background = "/static/img/backgrounds/" + args.get("background", "wood.jpg") self.calcsizes() def setpieceati(self, i, p): if ( i >= 0 ) and ( i < self.area ): self.rep[i] = p else: print("warning, rep index out of range", i) def getpieceati(self, i): if ( i >= 0 ) and ( i < self.area ): return self.rep[i] return Piece() def getpieceatfilerank(self, file, rank): i = rank * self.numfiles + file return self.getpieceati(i) def getpieceatsquare(self, sq): return self.getpieceatfilerank(sq.file, sq.rank) def setrepfromfen(self, fen): self.fen = fen self.crazyfen = None self.threefen = None self.rep = [Piece() for i in range(self.area)] fenparts = self.fen.split(" ") self.rawfen = fenparts[0] rawfenparts = self.rawfen.split("/") if self.variantkey == "crazyhouse": self.crazyfen = "" if "[" in self.rawfen: cfenparts = self.rawfen.split("[") self.rawfen = cfenparts[0] rawfenparts = self.rawfen.split("/") cfenparts = cfenparts[1].split("]") self.crazyfen = cfenparts[0] i = 0 for rawfenpart in rawfenparts: pieceletters = rawfenpart.split("") for pieceletter in pieceletters: if isvalidpieceletter(pieceletter): self.setpieceati(i, piecelettertopiece(pieceletter)) i+=1 else: mul = 0 try: mul = int(pieceletter) except: print("warning, multiplicity could not be parsed from", pieceletter) for j in range(mul): self.setpieceati(i, Piece()) i += 1 if i < self.area: print("warning, raw fen did not fill board") elif i > self.area: print("warning, raw fen exceeded board") self.turnfen = "w" if len(fenparts) > 1: self.turnfen = fenparts[1] else: print("warning, no turn fen") self.castlefen = "-" if len(fenparts) > 2: self.castlefen = fenparts[2] else: print("warning, no castle fen") self.epfen = "-" if len(fenparts) > 3: self.epfen = fenparts[3] else: print("warning, no ep fen") moveclocksi = cpick(self.variantkey == "threeCheck", 5, 4) self.halfmoveclock = 0 if len(fenparts) > moveclocksi: try: self.halfmoveclock = int(fenparts[moveclocksi]) except: print("warning, half move clock could not be parsed from", fenparts[4]) else: print("warning, no half move fen") self.fullmovenumber = 1 if len(fenparts) > ( moveclocksi + 1 ): try: self.fullmovenumber = int(fenparts[moveclocksi + 1]) except: print("warning, full move number could not be parsed from", fenparts[5]) else: print("warning, no full move fen") if self.variantkey == "threeCheck": if len(fenparts) > 4: self.threefen = fenparts[4] self.promoting = False def turn(self): if self.turnfen == "w": return WHITE return BLACK def iswhitesturn(self): return self.turn() == WHITE def isblacksturn(self): return self.turn() == BLACK def initrep(self, args): self.variantkey = args.get("variantkey", "standard") self.setrepfromfen(args.get("fen", getstartfenforvariantkey(self.variantkey))) def setfromfen(self, fen, positioninfo = {}): self.positioninfo = positioninfo self.setrepfromfen(fen) self.build() def reset(self): self.setfromfen(getstartfenforvariantkey(self.variantkey)) def __init__(self, args): super().__init__("div") self.positioninfo = {} self.parseargs(args) self.initrep(args) self.build()