MODULE Board; IMPORT VBT; IMPORT Region; IMPORT PaintOp; IMPORT Axis; IMPORT Path, Point, Rect; IMPORT VBTClass; REVEAL T = Public BRANDED OBJECT scheme : PaintOp.ColorQuad; state : REF ARRAY OF ARRAY OF Piece; METHODS spotRegion(p : Point.T) : Region.T := SpotRegion; OVERRIDES init := Init; repaint := Repaint; shape := Shape; setState := SetState; getState := GetState; mouse := Mouse END; (* default size for board *) CONST Offset = 100; SpotSize = 40; Pitch = SpotSize + 10; PROCEDURE Init(r : T; xsize, ysize : CARDINAL) : T = BEGIN r.scheme := Quad; r.state := NEW(REF ARRAY OF ARRAY OF Piece, xsize, ysize); FOR i := FIRST(r.state^) TO LAST(r.state^) DO FOR j := FIRST(r.state[0]) TO LAST(r.state[0]) DO r.state[i,j] := Piece.None END END; RETURN r END Init; PROCEDURE Shape(r: T; ax : Axis.T; <*UNUSED*>n : CARDINAL) : VBT.SizeRange = VAR size : CARDINAL; BEGIN CASE ax OF | Axis.T.Hor => size := NUMBER(r.state^)*Pitch + 2*Offset | Axis.T.Ver => size := NUMBER(r.state[0])*Pitch + 2*Offset END; RETURN VBT.SizeRange { size, size, 99999 } END Shape; PROCEDURE LinePath(from : Point.T; to : Point.T) : Path.T = VAR r := NEW(Path.T); BEGIN Path.Reset(r); Path.MoveTo(r,from); Path.LineTo(r,to); RETURN r END LinePath; VAR TheSpot := Circle(FLOAT(SpotSize)/2.0); PROCEDURE Repaint(v : T; READONLY rgn : Region.T) = BEGIN VBT.PaintTint(v, rgn.r, v.scheme.bg); (* paint quit button *) WITH path1 = LinePath( Point.T {0,Offset DIV 2}, Point.T{Offset DIV 2, Offset DIV 2} ), path2 = LinePath( Point.T {Offset DIV 2,0}, Point.T{Offset DIV 2, Offset DIV 2} ) DO VBT.Stroke(v,rgn.r,path1, width := 3, op := White); VBT.Stroke(v,rgn.r,path2, width := 3, op := White); VBT.PaintText(v,pt :=Point.T {Offset DIV 10,Offset DIV 4}, t:="QUIT!", op := White) END; (* paint verticals *) FOR i := 0 TO NUMBER(v.state^) DO WITH path = LinePath( Point.T { Offset + i * Pitch, Offset }, Point.T { Offset + i * Pitch, Offset + NUMBER(v.state[0])*Pitch }) DO VBT.Stroke(v,rgn.r,path, width := 3, op := White) END END; (* horizontals *) FOR i := 0 TO NUMBER(v.state[0]) DO WITH path = LinePath( Point.T { Offset, Offset + i * Pitch }, Point.T { Offset + NUMBER(v.state^)*Pitch, Offset + i * Pitch }) DO VBT.Stroke(v,rgn.r,path, width := 3, op := White) END END; (* paint the state *) FOR i := FIRST(v.state^) TO LAST(v.state^) DO FOR j := FIRST(v.state[0]) TO LAST(v.state[0]) DO CASE v.state[i,j] OF | Piece.None => (* skip *) | Piece.Black => VBT.PaintRegion(v, Region.Meet(v.spotRegion(Point.T{i,j}),rgn), Black) | Piece.White => VBT.PaintRegion(v, Region.Meet(v.spotRegion(Point.T{i,j}),rgn), White) END END END END Repaint; PROCEDURE SpotRegion(<*UNUSED*>s : T; p : Point.T) : Region.T = BEGIN RETURN Region.Add(TheSpot, Point.T { Offset + p.h * Pitch + Pitch DIV 2, Offset + p.v * Pitch + Pitch DIV 2}) END SpotRegion; PROCEDURE Circle(r: REAL): Region.T = (* from SRC *) VAR res := Region.Empty; BEGIN FOR h := FLOOR(-r) TO CEILING(r) DO FOR v := FLOOR(-r) TO CEILING(r) DO IF h * h + v * v <= FLOOR(r * r) THEN WITH rect = Rect.FromPoint(Point.T{h, v}) DO res := Region.JoinRect(rect, res) END END END END; RETURN res END Circle; VAR Green := PaintOp.FromRGB(0.0,0.45,0.0, mode:=PaintOp.Mode.Stable); White := PaintOp.FromRGB(1.0,1.0,1.0); Black := PaintOp.FromRGB(0.0,0.0,0.0); Quad := PaintOp.MakeColorScheme(Green,White); PROCEDURE SetState(s : T; p : Point.T; state : Piece) = BEGIN s.state[p.h,p.v] := state; VBTClass.Repaint(s,s.spotRegion(p)) END SetState; PROCEDURE GetState(s : T; p : Point.T) : Piece = BEGIN RETURN s.state[p.h,p.v] END GetState; PROCEDURE Mouse(s : T; READONLY cd : VBT.MouseRec) = BEGIN IF cd.clickType = VBT.ClickType.FirstDown THEN IF cd.cp.pt.h < Offset DIV 2 AND cd.cp.pt.v < Offset DIV 2 THEN s.quit(); END; WITH h = (cd.cp.pt.h - Offset) DIV Pitch, v = (cd.cp.pt.v - Offset) DIV Pitch DO IF h >= 0 AND h <= LAST(s.state^) AND v >= 0 AND v <= LAST(s.state[0]) THEN s.click(Point.T { h,v }) END END END END Mouse; BEGIN END Board.