Take the 2-minute tour ×
Game Development Stack Exchange is a question and answer site for professional and independent game developers. It's 100% free, no registration required.

I'm currently making a GO game and I am stuck on the most basic functionality. That functionality is being able to click on the intersections of the grid and ONLY the intersections to place a stone, either can be black or white. I have made a 2D array to represent the board but what I don't really understand is:

  • How do I draw the stones on the grid?
  • How do I reference the GUI grid to the 2D array?
share|improve this question
    
it really depends on what GUI features you are using, for example are you using standard java GUi, or is it some library? –  Ali.S Feb 3 '12 at 0:00
    
Yeah, we need more information, particularly for your first question. –  stephelton Feb 3 '12 at 0:01
    
I'm using the JFrame class, to show a window. –  user1048606 Feb 3 '12 at 0:02
1  
Highly disappointed when I realized that GO wasn't the language being used –  ClassicThunder Feb 3 '12 at 23:19
add comment

3 Answers 3

up vote 1 down vote accepted

i added some more stuff:

import java.awt.*;
import java.awt.event.*;
import java.awt.geom.*;
import java.util.*;
import java.util.List;
import javax.swing.*;
enum Stone {
    vacant, black, white; // maybe add edge?
    Stone otherColor() {
        if (this == black) return white;
        else if (this == white) return black;
        else
            return vacant;
    }
}
interface Board {
    int size();
    Stone at(int x, int y);
}
interface MutableBoard extends Board {
    int size();
    Stone at(int x, int y);
    void setAt(int x, int y, Stone color);
}
class BoardImpl implements MutableBoard {
    BoardImpl(int n) {
        this.n = n;
        stones = new Stone[n][n];
        clear(n);
    }
    private void clear(int n) {
        for (int i = 0; i < n; i++)
            for (int j = 0; j < n; j++)
                stones[i][j] = Stone.vacant;
    }
    @Override public int size() {
        return n;
    }
    @Override public Stone at(int x, int y) {
        return stones[x][y];
    }
    @Override public void setAt(int x, int y, Stone color) {
        stones[x][y] = color;
    }
    final int n;
    private final Stone[][] stones;
}
class Block {
    Block(Board b, int i, int j, boolean[][] processed) {
        this.b = b;
        this.processed = processed;
        n = b.size();
        this.who = b.at(i, j);
        points = new LinkedList<Point>();
        grow(i, j);
        countLiberties();
    }
    int liberties() {
        return l;
    }
    Stone color() {
        return who;
    }
    public String toString() {
        return who + " " + points.size() + " stone(s), " + l + " liberties" + points;
    }
    static List<List<Block>> findBlocks(Board b) {
        int n = b.size();
        boolean[][] processed = new boolean[n][n];
        List<Block> blackBlocks = new LinkedList<Block>();
        List<Block> whiteBlocks = new LinkedList<Block>();
        for (int i = 0; i < n; i++)
            for (int j = 0; j < n; j++) {
                Stone who = b.at(i, j);
                if (!who.equals(Stone.vacant) && processed[i][j] == false) {
                    Block g = new Block(b, i, j, processed);
                    switch (who) {
                        case black:
                            blackBlocks.add(g);
                            break;
                        case white:
                            whiteBlocks.add(g);
                            break;
                        default:
                            System.out.println("findGroups " + b + g + who);
                    }
                }
            }
        List<List<Block>> blocks = new LinkedList<List<Block>>();
        blocks.add(blackBlocks);
        blocks.add(whiteBlocks);
        return blocks;
    }
    private void grow(int i, int j) {
        if (!(0 <= i && i < n && 0 <= j && j < n)) return;
        if (!processed[i][j]) {
            Stone who = b.at(i, j);
            if (who.equals(this.who) || who.equals(Stone.vacant)) processed[i][j] = true;
            if (who == this.who) {
                points.add(new Point(i, j));
                grow(i - 1, j);
                grow(i, j - 1);
                grow(i, j + 1);
                grow(i + 1, j);
            }
        }
    }
    private void countLiberties() {
        l = 0;
        processed = new boolean[n][n];
        for (int k = 0; k < points.size(); k++) {
            Point p = (Point) points.get(k);
            count(p.x - 1, p.y);
            count(p.x, p.y - 1);
            count(p.x, p.y + 1);
            count(p.x + 1, p.y);
        }
    }
    private void count(int i, int j) {
        if (0 <= i && i < n && 0 <= j && j < n && !processed[i][j]) {
            if (b.at(i, j) == Stone.vacant) l++;
            processed[i][j] = true;
        }
    }
    static List<Block> capturedStones(List<List<Block>> blockLists) {
        List<Block> dead = new LinkedList<Block>();
        List<Block> blocks = blockLists.get(0);
        if (blocks != null) for (int i = 0; i < blocks.size(); i++) {
            Block g = (Block) blocks.get(i);
            // System.out.println(g);
            if (g.liberties() == 0) dead.add(g);
        }
        blocks = blockLists.get(1);
        if (blocks != null) for (int i = 0; i < blocks.size(); i++) {
            Block g = (Block) blocks.get(i);
            // System.out.println(g);
            if (g.liberties() == 0) dead.add(g);
        }
        return dead;
    }
    private Stone who;
    List<Point> points;
    private int n;
    private int l;
    transient private Board b;
    transient private boolean[][] processed;
}
class Move {
    Move(Stone stone, Point point) {
        if (stone.equals(Stone.vacant)) throw new RuntimeException("bad move");
        this.stone = stone;
        this.point = point;
    }
    Move(Stone stone, int x, int y) {
        this(stone, new Point(x, y));
    }
    void make(MutableBoard board) {
        board.setAt(point.x, point.y, stone);
        List<List<Block>> blockLists = Block.findBlocks(board);
        List<Block> capturedBlocks = Block.capturedStones(blockLists);
        if (capturedBlocks != null && capturedBlocks.size() > 0) {
            Block fromThisMove = null;
            for (Block block : capturedBlocks)
                if (block.points.contains(point) && block.points.size() == 1) {
                    fromThisMove = block;
                    break;
                }
            if (fromThisMove != null) capturedBlocks.remove(fromThisMove);
            for (Block block : capturedBlocks) {
                captured = capturedBlocks;
                for (Point point2 : block.points)
                    board.setAt(point2.x, point2.y, Stone.vacant);
            }
        }
    }
    void unmake(MutableBoard board) {
        if (captured != null) for (Block block : captured) {
            Stone who = block.color();
            for (Point point : block.points)
                board.setAt(point.x, point.y, who);
        }
        board.setAt(point.x, point.y, Stone.vacant);
    }
    final Point point;
    final Stone stone;
    List<Block> captured;
}
class Line {
    Line(Point p1, Point p2) {
        this.p1 = p1;
        this.p2 = p2;
    }
    public void paint(Graphics g) {
        g.drawLine(p1.x, p1.y, p2.x, p2.y);
    }
    final Point p1, p2;
}
class Gui extends JPanel {
    Gui(TopPanel game, MutableBoard board, int width, int height) {
        this.game = game;
        this.board = board;
        x0 = 10;
        y0 = 10;
        this.n = board.size();
        rectangle = new Rectangle(1, 1, n, n);
        dx = width / n;
        dy = height / n;
        for (int i = 0; i < n; i++)
            addLine(x0, y0 + i * dy, x0 + (n - 1) * dx, y0 + i * dy);
        for (int j = 0; j < n; j++)
            addLine(x0 + j * dx, y0, x0 + j * dx, y0 + (n - 1) * dy);
        addMouseListener(new MouseListener() {
            @Override public void mouseReleased(MouseEvent e) {}
            @Override public void mousePressed(MouseEvent e) {}
            @Override public void mouseExited(MouseEvent e) {}
            @Override public void mouseEntered(MouseEvent e) {}
            @Override public void mouseClicked(MouseEvent e) {
                Point2D.Float point = toBoardCoordinates(e.getPoint());
                Point closest = new Point(Math.round(point.x), Math.round(point.y));
                if (ispointOnBoard(closest)) {
                    double distance = point.distance(closest);
                    if (distance < .35) if (Gui.this.board.at(closest.x, closest.y) == Stone.vacant) Gui.this.game.makeMove(closest);
                    else
                        System.out.println(closest + " is occupied!");
                } else
                    System.out.println(closest + " is off the board!");
            }
        });
    }
    private Point2D.Float toBoardCoordinates(Point screen) {
        return new Point2D.Float((screen.x - x0) / (float) dx + 1, (screen.y - y0) / (float) dy + 1);
    }
    private Point toScreenCoordinates(Point board) {
        return new Point(x0 + (board.x - 1) * dx, y0 + (board.y - 1) * dy);
    }
    private boolean ispointOnBoard(Point point) {
        return rectangle.contains(point);
    }
    Move createMove(Stone stone, Point point) {
        if (ispointOnBoard(point)) return new Move(stone, point);
        else
            throw new RuntimeException(point + " is off the board!");
    }
    void makeMove(Move move) { // currently we do not allow vacant moves
        repaint(); // use the long form!
    }
    void unmove(Move move) {
        repaint();
    }
    private void addLine(int x1, int y1, int x2, int y2) {
        this.lines.add(new Line(new Point(x1, y1), new Point(x2, y2)));
    }
    private void addLine(Point p1, Point p2) {
        this.lines.add(new Line(p1, p2));
    }
    private Image blackStone(int width, int height, Color color) {
        Image img = createImage(width, height);
        Graphics g = img.getGraphics();
        g.setColor(color);
        g.fillRect(0, 0, width, height);
        g.setColor(Color.black);
        g.fillOval(0, 0, width - 1, height - 1);
        g.drawOval(0, 0, width - 1, height - 1);
        // these two are different from
        // either g.fillOval(-1, -1, width+1, height+1);
        // or g.fillOval(0, 0, width-1, height-1);
        g.setColor(Color.white);
        g.drawArc(width / 5, height / 5, width * 3 / 5, height * 3 / 5, -20, -60);
        return img;
    }
    private Image whiteStone(int width, int height, Color color) {
        Image img = createImage(width, height);
        Graphics g = img.getGraphics();
        g.setColor(color);
        g.fillRect(0, 0, width, height);
        g.setColor(Color.white);
        g.fillOval(0, 0, width - 1, height - 1);
        g.setColor(Color.black);
        g.drawOval(0, 0, width - 1, height - 1);
        g.drawArc(width / 5, height / 5, width * 3 / 5, height * 3 / 5, -20, -60);
        return img;
    }
    private void paintStone(Graphics g, int i, int j) {
        if (board.at(i, j) != Stone.vacant) {
            if (board.at(i, j) == Stone.black) g.setColor(Color.black);
            else if (board.at(i, j) == Stone.white) g.setColor(Color.white);
            else
                throw new RuntimeException("oops");
            Point screen = toScreenCoordinates(new Point(i, j));
            if (black == null || white == null) g.fillOval(screen.x - dx / 2, screen.y - dy / 2, dx, dx);
            else {
                if (board.at(i, j) == Stone.black) g.drawImage(black, screen.x - dx / 2, screen.y - dy / 2, dx, dy, null);
                else
                    g.drawImage(white, screen.x - dx / 2, screen.y - dy / 2, dx, dy, null);
            }
        }
    }
    public void paintComponent(Graphics g) {
        super.paintComponent(g);
        if (game != null) {
            black = blackStone(dx, dy, getBackground());
            white = whiteStone(dx, dy, getBackground());
            Color color = g.getColor();
            for (Line line : lines) {
                line.paint(g);
            }
            for (int i = 0; i < n; i++)
                for (int j = 0; j < n; j++)
                    paintStone(g, i, j);
            g.setColor(color);
        }
    }
    private final TopPanel game;
    private final int n;
    final MutableBoard board;
    private final int x0, y0;
    private final int dx, dy;
    private final Rectangle rectangle;
    private final Set<Line> lines = new LinkedHashSet<Line>();
    private Image black, white;
    private static final long serialVersionUID = 1L;
}
class Game {
    Game(int n) {
        board = new BoardImpl(n);
    }
    Move makeMove(Point point) {
        Move move = new Move(turn, point);
        move.make(board);
        moves.add(move);
        turn = turn.otherColor();
        return move;
    }
    Move unmove() {
        if (moves.size() > 0) {
            Move move = moves.remove(moves.size() - 1);
            move.unmake(board);
            turn = turn.otherColor();
            return move;
        } else {
            System.out.println("no moves to undo!");
            return null;
        }
    }
    final MutableBoard board;
    Stone turn = Stone.black;
    final java.util.List<Move> moves = new LinkedList<Move>();
}
class TopPanel extends JPanel {
    static final String unmove = "Unmove";
    static final String newgame = "New Game";
    TopPanel(Game game) {
        init();
        this.game = game;
        gui = new Gui(this, game.board, 500, 520);
        Dimension d = new Dimension(510, 530);
        gui.setSize(d);
        gui.setPreferredSize(d);
        gui.setMaximumSize(d);
        gui.setMinimumSize(d);
        gui.setOpaque(true);
        gui.setBackground(Color.orange);
        add(gui);
    }
    void makeMove(Point point) {
        Move move = game.makeMove(point);
        if (move != null) gui.makeMove(move);
    }
    void unmove() {
        Move move = game.unmove();
        if (move != null) gui.unmove(move);
        else
            System.out.println("no moves to undo!");
    }
    private void init() {
        setLayout(new BoxLayout(this, BoxLayout.Y_AXIS));
        JButton jButton = new JButton(newgame);
        jButton.setName(newgame);
        add(jButton);
        jButton = new JButton(unmove);
        jButton.setName(unmove);
        add(jButton);
        jButton.addActionListener(new ActionListener() {
            @Override public void actionPerformed(ActionEvent e) {
                Object object = e.getSource();
                if (object instanceof JButton) if (((JButton) object).getName().equals(unmove)) unmove();
                else if (((JButton) object).getName().equals(newgame)) {
                    //
                }
            }
        });
    }
    final Gui gui;
    Game game;
    private static final long serialVersionUID = 1L;
}
class Main {
    private static void build(Container c) {
        c.add(new TopPanel(new Game(19)));
    }
    private static void createAndShowGUI() {
        JFrame frame = new JFrame("Board");
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        build(frame.getContentPane());
        frame.setPreferredSize(new Dimension(520, 600));
        frame.pack();
        frame.setVisible(true);
    }
    public static void main(String[] args) {
        javax.swing.SwingUtilities.invokeLater(new Runnable() {
            public void run() {
                createAndShowGUI();
            }
        });
    }
}
share|improve this answer
    
cleaned up and adder nicer stones –  Ray Tayek Feb 6 '12 at 3:01
    
added code to capture stones –  Ray Tayek Feb 6 '12 at 9:42
add comment

I have made a 2D array to represent the board

For GO, think of the 2D array as array of placement/intersection points, instead of array of grid (rectangle) on the board. Then to draw the board, just draw normal grids based on that array length, but offset it.

How do I draw the stones on the grid?

Pick a number, say "size", as the size of a grid. Define the top left position of the board in the window, say "boardX" and "boardY". the 2d array you defined earlier should be an array of byte or char or int or whatever that able to represent stones on the grid. You will look up the array to find out whether a given position has stone or not. for example, array[2][2] == 1 checks whether player 1's stone is on position 2,2.

size = 10;
stoneSize = 10;
boardX = 20; boardY = 20

void drawStone(col, row, color) {
 x = col * size + boardX;
 y = row * size + boardY;
 drawCircle(x, y, color);
}

void drawStones(array) {
 for(int i = 0; i < array.length; ++i) {
  rowArr = array[i];
  for(int j = 0; j < rowArr.length; ++j) {
   if(array[i][j] == 0) { /* nothing here */ }
   else if(array[i][j] == 1) { drawStone(i, j, Color.WHITE); }
   else { drawStone(i, j, Color.BLACK); }
  }
 }
}

How do I reference the GUI grid to the 2D array?

You should have the information of the click's position.

gridX = (clickPositionX - boardX) / (size * gridColumnCount);
gridY = (clickPositionY - boardY) / (size * gridRowCount);
array[gridX][gridY] // <- this is the clicked grid in 2d array

The code is pretty sloppy, but I hope you get the idea.

share|improve this answer
add comment

You can override the JFrame's paint() method. Use the Graphics that it gives you to call methods like drawLine and fillRect to do your drawing. Then when you get a mouse or touch events, you'll calculate which grid point it's nearest and whether it's close enough to count.

share|improve this answer
    
Should I manually place the point objects on the grid? –  user1048606 Feb 3 '12 at 13:11
    
You'll need to draw them. You could create an image that looks like the piece you want, then call drawImage(). You'll also want to keep up with them in some data structure so that you can perform game logic periodically. –  stephelton Feb 3 '12 at 17:42
add comment

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.