<* PRAGMA LL *> MODULE; IMPORT MinimaxViewClass, Filter, RefList, GraphVBT, PaintOp, R2, VBT, View, ZeusPanel, GameBoard, Rect, MinimaxIE, Thread; TYPE T = MinimaxViewClass.T BRANDED OBJECT graph: GraphVBT.T; (* set by Setup *) cells: ARRAY [0 .. GameBoard.BoardSize], [0 .. GameBoard.BoardSize] OF GraphVBT.Vertex; contents: ARRAY [0 .. GameBoard.BoardSize], [0 .. GameBoard.BoardSize] OF GraphVBT.Vertex; selected : GraphVBT.Vertex; message : GraphVBT.Vertex; messagePlayer: GraphVBT.Vertex; OVERRIDES <* LL = VBT.mu *> startrun := DoStartRun; <* LL = 0 *> oeSetup := DoSetup; oePlayerMove := DoPlayerMove; oeHumanCellSelected := DoHumanCellSelected; oeHumanIllegalMove := DoHumanIllegalMove; oeFinished := DoFinished; oePlayerThinking := DoPlayerThinking; END; Graph = GraphVBT.T BRANDED OBJECT OVERRIDES <* LL = VBT.mu *> mouse := Mouse; END; PROCEDURE ViewGameBoard New (): View.T = BEGIN RETURN NEW(T).init(NIL) END New; PROCEDUREDoStartRun (view: T) = BEGIN view.graph := NEW(Graph).init(); EVAL Filter.Replace(view, view.graph); END DoStartRun; PROCEDUREMouse (g: Graph; READONLY cd: VBT.MouseRec) = <*FATAL Thread.Alerted *> VAR view := NARROW(VBT.Parent(g), T); vList: RefList.T; BEGIN IF cd.clickType # VBT.ClickType.FirstDown THEN RETURN; END; LOCK g.mu DO vList := g.verticesAt(Rect.FromPoint(cd.cp.pt)) END; FOR x := 0 TO GameBoard.BoardSize - 1 DO FOR y := 0 TO GameBoard.BoardSize - 1 DO IF RefList.Member(vList, view.cells[x, y]) THEN MinimaxIE.HumanSelection(view, x, y); END; END; END; END Mouse; PROCEDUREDoSetup (view: T) = BEGIN LOCK view.graph.mu DO view.graph.setWorld(GraphVBT.WorldRectangle{ w := 0.0, s := FLOAT(GameBoard.BoardSize + 1), e := FLOAT(GameBoard.BoardSize), n := 0.0}); view.graph.setAspect( FLOAT(GameBoard.BoardSize + 1) / FLOAT(GameBoard.BoardSize)); END; FOR x := 0 TO GameBoard.BoardSize - 1 DO FOR y := 0 TO GameBoard.BoardSize - 1 DO view.cells[x, y] := NEW(GraphVBT.Vertex, graph := view.graph, pos := R2.T{FLOAT(x) + 0.5, FLOAT(y) + 0.5}, size := R2.T{0.95, 0.95}, color := PaintOp.FromRGB(1.0, 1.0, 1.0)).init(); view.cells[x, y].toBack(GraphVBT.ZOrder.Background); END; END; (* draw lines *) FOR line := 1 TO GameBoard.BoardSize - 1 DO EVAL NEW(GraphVBT.Edge, vertex0 := NEW(GraphVBT.Vertex, graph := view.graph, pos := R2.T{0.0, FLOAT(line)}, size := R2.T{0.0, 0.0}).init(), vertex1 := NEW(GraphVBT.Vertex, graph := view.graph, pos := R2.T{FLOAT(GameBoard.BoardSize), FLOAT(line)}, size := R2.T{0.0, 0.0}).init(), width := 0.1, color := PaintOp.FromRGB(0.0, 0.0, 0.0)).init(); EVAL NEW(GraphVBT.Edge, vertex0 := NEW(GraphVBT.Vertex, graph := view.graph, pos := R2.T{FLOAT(line), 0.0}, size := R2.T{0.0, 0.0}).init(), vertex1 := NEW(GraphVBT.Vertex, graph := view.graph, pos := R2.T{FLOAT(line), FLOAT(GameBoard.BoardSize)}, size := R2.T{0.0, 0.0}).init(), width := 0.1, color := PaintOp.FromRGB(0.0, 0.0, 0.0)).init(); END; FOR x := 0 TO GameBoard.BoardSize - 1 DO view.contents[x, 0] := NEW(GraphVBT.Vertex, graph := view.graph, pos := R2.T{FLOAT(x) + 0.5, 0.5}, shape := GraphVBT.VertexShape.Ellipse, size := R2.T{0.7, 0.7}, color := PaintOp.FromRGB(0.0, 1.0, 0.0), label := "A", font := view.graph.font( "Helvetica", 0.2, GraphVBT.Slant.Roman, "bold", "*"), fontColor := PaintOp.FromRGB(0.0, 0.0, 0.0)).init(); view.contents[x, GameBoard.BoardSize - 1] := NEW(GraphVBT.Vertex, graph := view.graph, pos := R2.T{FLOAT(x) + 0.5, FLOAT(GameBoard.BoardSize) - 0.5}, shape := GraphVBT.VertexShape.Ellipse, size := R2.T{0.7, 0.7}, color := PaintOp.FromRGB(0.0, 0.0, 1.0), label := "B", font := view.graph.font( "Helvetica", 0.2, GraphVBT.Slant.Roman, "bold", "*"), fontColor := PaintOp.FromRGB(0.0, 0.0, 0.0)).init(); END; FOR y := 1 TO GameBoard.BoardSize - 2 DO FOR x := 0 TO GameBoard.BoardSize - 1 DO view.contents[x, y] := NIL; END; view.message := NEW(GraphVBT.Vertex, graph := view.graph, pos := R2.T{1.0, FLOAT(GameBoard.BoardSize) + 0.5}, size := R2.T{2.0, 0.8}, color := PaintOp.FromRGB(1.0, 1.0, 1.0), label := "", font := view.graph.font( "Helvetica", 0.2, GraphVBT.Slant.Roman, "bold", "*"), fontColor := PaintOp.FromRGB(0.0, 0.0, 0.0)).init(); END; view.graph.redisplay(); END DoSetup; PROCEDUREDoHumanCellSelected (view: T; xPos, yPos: INTEGER) = BEGIN view.selected := view.cells[xPos, yPos]; LOCK view.graph.mu DO view.selected.setColor(PaintOp.FromRGB(0.5, 0.5, 0.5)); END; view.graph.redisplay(); END DoHumanCellSelected; PROCEDUREDoHumanIllegalMove (view: T) = BEGIN LOCK view.graph.mu DO view.selected.setColor(PaintOp.FromRGB(1.0, 1.0, 1.0)); END; view.graph.redisplay(); END DoHumanIllegalMove; PROCEDUREDoPlayerMove ( view : T; <*UNUSED*> player : INTEGER; fromX, fromY, toX, toY: INTEGER ) RAISES {Thread.Alerted} = BEGIN IF view.contents[toX, toY] # NIL THEN view.contents[toX, toY].remove(); END; LOCK view.graph.mu DO IF view.selected # NIL THEN view.selected.setColor(PaintOp.FromRGB(1.0, 1.0, 1.0)); END; view.contents[fromX, fromY].move( R2.T{FLOAT(toX) + 0.5, FLOAT(toY) + 0.5}, animated := TRUE); END; view.selected := NIL; view.contents[toX, toY] := view.contents[fromX, fromY]; view.contents[fromX, fromY] := NIL; view.graph.animate(0.0, 1.0); END DoPlayerMove; PROCEDUREMakePiece (view: T; player: INTEGER; x, y: REAL): GraphVBT.Vertex = BEGIN IF player = 0 THEN RETURN NEW(GraphVBT.Vertex, graph := view.graph, pos := R2.T{x, y}, shape := GraphVBT.VertexShape.Ellipse, size := R2.T{0.7, 0.7}, color := PaintOp.FromRGB(0.0, 1.0, 0.0), label := "A", font := view.graph.font( "Helvetica", 0.2, GraphVBT.Slant.Roman, "bold", "*"), fontColor := PaintOp.FromRGB(0.0, 0.0, 0.0)).init(); ELSE RETURN NEW(GraphVBT.Vertex, graph := view.graph, pos := R2.T{x, y}, shape := GraphVBT.VertexShape.Ellipse, size := R2.T{0.7, 0.7}, color := PaintOp.FromRGB(0.0, 0.0, 1.0), label := "B", font := view.graph.font( "Helvetica", 0.2, GraphVBT.Slant.Roman, "bold", "*"), fontColor := PaintOp.FromRGB(0.0, 0.0, 0.0)).init(); END; END MakePiece; PROCEDUREDoFinished (view: T; player: INTEGER) = BEGIN IF view.messagePlayer # NIL THEN LOCK view.graph.mu DO view.messagePlayer.remove(); END; END; IF player = 2 THEN LOCK view.graph.mu DO view.message.setLabel("Game is tied."); END; ELSE LOCK view.graph.mu DO view.message.setLabel("Winner is "); END; view.messagePlayer := MakePiece(view, player, 2.5, FLOAT(GameBoard.BoardSize) + 0.5); END; view.graph.redisplay(); END DoFinished; PROCEDUREDoPlayerThinking ( view : T; player: INTEGER; <*UNUSED*> board : GameBoard.T) = BEGIN IF view.messagePlayer # NIL THEN LOCK view.graph.mu DO view.messagePlayer.remove(); END; END; LOCK view.graph.mu DO view.message.setLabel("Player to move: "); END; view.messagePlayer := MakePiece(view, player, 2.5, FLOAT(GameBoard.BoardSize) + 0.5); view.graph.redisplay(); END DoPlayerThinking; BEGIN ZeusPanel.RegisterView(New, "Game Board", "Minimax"); END ViewGameBoard.