Last active
November 28, 2019 06:26
-
-
Save shiracamus/19b9d49664af3640025e432bd5afda1c to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import java.util.*; | |
import java.util.stream.*; | |
import java.awt.*; | |
import java.awt.Point; | |
import java.awt.event.*; | |
import javax.swing.*; | |
interface Disk { | |
public void paint(Graphics g, Point p, int size); | |
public String toString(); | |
} | |
class Disks { | |
static final Disk NONE, BLACK, WHITE; | |
static { | |
NONE = new Disk() { | |
public void paint(Graphics g, Point p, int size) { | |
} | |
public String toString() { | |
return "□"; | |
} | |
}; | |
BLACK = new Disk() { | |
public void paint(Graphics g, Point p, int size) { | |
int r = (size / 2) * 4 / 5; | |
g.setColor(Color.black); | |
g.fillOval(p.x - r, p.y - r, r * 2, r * 2); | |
} | |
public String toString() { | |
return "×"; | |
} | |
}; | |
WHITE = new Disk() { | |
public void paint(Graphics g, Point p, int size) { | |
int r = (size / 2) * 4 / 5; | |
g.setColor(Color.white); | |
g.fillOval(p.x - r, p.y - r, r * 2, r * 2); | |
} | |
public String toString() { | |
return "●"; | |
} | |
}; | |
} | |
private static final Map<Disk, Disk> OPPOSITE = new HashMap<Disk, Disk>() { | |
{ | |
put(NONE, NONE); | |
put(BLACK, WHITE); | |
put(WHITE, BLACK); | |
} | |
}; | |
static Disk opposite(Disk disk) { | |
return OPPOSITE.get(disk); | |
} | |
} | |
class Square { | |
private Disk disk; | |
Square() { | |
this.disk = Disks.NONE; | |
} | |
boolean is_used() { | |
return this.disk != Disks.NONE; | |
} | |
boolean is(Disk disk) { | |
return this.disk == disk; | |
} | |
void put(Disk disk) { | |
this.disk = disk; | |
} | |
void reverse() { | |
this.disk = Disks.opposite(this.disk); | |
} | |
void paint(Graphics g, Point p, int size) { | |
disk.paint(g, p, size); | |
} | |
public String toString() { | |
return disk.toString(); | |
} | |
} | |
class Board { | |
final Square[][] squares = new Square[8][8]; | |
final int[][] eval_black = new int[8][8]; | |
final int[][] eval_white = new int[8][8]; | |
private static final Color COLOR = new Color(0, 85, 0); | |
private static final Point[] DIRECTION = { | |
new Point(-1, -1), | |
new Point( 0, -1), | |
new Point( 1, -1), | |
new Point(-1, 0), | |
new Point( 1, 0), | |
new Point(-1, 1), | |
new Point( 0, 1), | |
new Point( 1, 1), | |
}; | |
Board() { | |
for (int x = 0; x < 8; x++) { | |
for (int y = 0; y < 8; y++) { | |
squares[x][y] = new Square(); | |
} | |
} | |
squares[3][3].put(Disks.WHITE); | |
squares[4][3].put(Disks.BLACK); | |
squares[3][4].put(Disks.BLACK); | |
squares[4][4].put(Disks.WHITE); | |
} | |
boolean isOnBoard(int x, int y) { | |
return 0 <= x && x < 8 && 0 <= y && y < 8; | |
} | |
long count(Disk disk) { | |
return Arrays.stream(squares) | |
.flatMap(Stream::of) | |
.filter(m -> m.is(disk)) | |
.count(); | |
} | |
class Reversible { | |
final ArrayList<Point> points = new ArrayList<Point>(); | |
void add(Point point) { | |
points.add(point); | |
} | |
void removeAll() { | |
points.clear(); | |
} | |
int count() { | |
return points.size(); | |
} | |
void reverse() { | |
points.forEach(p -> squares[p.x][p.y].reverse()); | |
} | |
} | |
Reversible getReversible(int x, int y, Point d, Disk s) { | |
Disk opposite = Disks.opposite(s); | |
Reversible reversible = new Reversible(); | |
x += d.x; | |
y += d.y; | |
while (isOnBoard(x, y) && squares[x][y].is(opposite)) { | |
reversible.add(new Point(x, y)); | |
x += d.x; | |
y += d.y; | |
} | |
if (!(isOnBoard(x, y) && squares[x][y].is(s))) | |
reversible.removeAll(); | |
return reversible; | |
} | |
int countReversible(int x, int y, Disk s) { | |
if (squares[x][y].is_used()) | |
return -1; | |
return Arrays.stream(DIRECTION) | |
.mapToInt(d -> getReversible(x, y, d, s).count()) | |
.sum(); | |
} | |
void putAndReverse(int x, int y, Disk s) { | |
squares[x][y].put(s); | |
Arrays.stream(DIRECTION).forEach(d -> getReversible(x, y, d, s).reverse()); | |
} | |
void evaluate() { | |
for (int x = 0; x < 8; x++) { | |
for (int y = 0; y < 8; y++) { | |
eval_black[x][y] = countReversible(x, y, Disks.BLACK); | |
eval_white[x][y] = countReversible(x, y, Disks.WHITE); | |
} | |
} | |
} | |
void printBoard() { | |
for (int y = 0; y < 8; y++) { | |
for (int x = 0; x < 8; x++) { | |
System.out.printf("%s ", squares[x][y]); | |
} | |
System.out.println(); | |
} | |
} | |
void printEvaluation() { | |
System.out.println("Black(" + Disks.BLACK + "):"); | |
for (int y = 0; y < 8; y++) { | |
for (int x = 0; x < 8; x++) { | |
System.out.printf("%2d ", eval_black[x][y]); | |
} | |
System.out.println(); | |
} | |
System.out.println("White(" + Disks.WHITE + "):"); | |
for (int y = 0; y < 8; y++) { | |
for (int x = 0; x < 8; x++) { | |
System.out.printf("%2d ", eval_white[x][y]); | |
} | |
System.out.println(); | |
} | |
} | |
void paint(Graphics g, int square_size) { | |
// Background | |
g.setColor(Color.black); | |
g.fillRect(0, 0, square_size * 10, square_size * 10); | |
// Board | |
g.setColor(Board.COLOR); | |
g.fillRect(square_size, square_size, square_size * 8, square_size * 8); | |
// Horizontal Lines | |
g.setColor(Color.black); | |
for (int x = 0; x < 9; x++) { | |
g.drawLine(square_size * (x + 1), square_size, square_size * (x + 1), square_size * 9); | |
} | |
// Vertical Lines | |
g.setColor(Color.black); | |
for (int y = 0; y < 9; y++) { | |
g.drawLine(square_size, square_size * (y + 1), square_size * 9, square_size * (y + 1)); | |
} | |
// Dots | |
for (int x = 0; x < 2; x++) { | |
for (int y = 0; y < 2; y++) { | |
g.fillRect(square_size * (3 + 4 * x) - (square_size / 16), | |
square_size * (3 + 4 * y) - (square_size / 16), | |
square_size / 8, | |
square_size / 8); | |
} | |
} | |
// Disks | |
Point p = new Point(); | |
for (int x = 0; x < 8; x++) { | |
for (int y = 0; y < 8; y++) { | |
p.x = square_size * (x + 1) + square_size / 2; | |
p.y = square_size * (y + 1) + square_size / 2; | |
squares[x][y].paint(g, p, square_size); | |
} | |
} | |
} | |
} | |
class Player { | |
private final String name; | |
private final Disk disk; | |
private final int[][] evaluation; | |
Player(String name, Disk disk, int[][] evaluation) { | |
this.name = name; | |
this.disk = disk; | |
this.evaluation = evaluation; | |
} | |
public String toString() { | |
return name; | |
} | |
boolean putable(Board board, int x, int y) { | |
return evaluation[x][y] >= 1; | |
} | |
void putAndReverse(Board board, int x, int y) { | |
board.putAndReverse(x, y, disk); | |
} | |
long count(Board board) { | |
return board.count(disk); | |
} | |
boolean pass() { | |
return Arrays.stream(evaluation) | |
.flatMapToInt(Arrays::stream) | |
.allMatch(n -> n <= 0); | |
} | |
} | |
public class Reversi extends JPanel { | |
private static final int SQUARE_SIZE = 80; | |
private final Board board = new Board(); | |
private final Player player1 = new Player("黒", Disks.BLACK, board.eval_black); | |
private final Player player2 = new Player("白", Disks.WHITE, board.eval_white); | |
private Player player = player1; | |
public Reversi() { | |
setPreferredSize(new Dimension(800, 800)); | |
addMouseListener(new MouseHandler()); | |
} | |
void turnPlayer() { | |
player = player == player1 ? player2 : player1; | |
} | |
public void paintComponent(Graphics g) { | |
board.paint(g, SQUARE_SIZE); | |
} | |
void showMessage(String message, String title) { | |
JOptionPane.showMessageDialog(this, message, title, JOptionPane.INFORMATION_MESSAGE); | |
} | |
void showMessage(String message) { | |
showMessage(message, "情報"); | |
} | |
void endGameAndExit() { | |
long num_player1 = player1.count(board); | |
long num_player2 = player2.count(board); | |
String message = "[" | |
+ player1 + ":" + num_player1 + "," | |
+ player2 + ":" + num_player2 + "]で"; | |
if (num_player1 > num_player2) { | |
message += player1 + "の勝ち"; | |
} else if (num_player1 <= num_player2) { | |
message += player2 + "の勝ち"; | |
} else { | |
message += "引き分け"; | |
} | |
showMessage(message, "ゲーム終了"); | |
System.exit(0); | |
} | |
class MouseHandler extends MouseAdapter { | |
public void mouseClicked(MouseEvent me) { | |
board.printBoard(); | |
Point point = me.getPoint(); | |
System.out.println("(" + point.x + "," + point.y + ")"); | |
int x = point.x / SQUARE_SIZE - 1; | |
int y = point.y / SQUARE_SIZE - 1; | |
if (!(0 <= x && x < 8 && 0 <= y && y < 8)) return; | |
System.out.println("[" + x + "]" + "[" + y + "]"); | |
int btn = me.getButton(); | |
if (player == player1 && btn == MouseEvent.BUTTON1 || | |
player == player2 && btn == MouseEvent.BUTTON3) { | |
put(x, y); | |
} | |
} | |
} | |
void put(int x, int y) { | |
board.evaluate(); | |
if (!player.putable(board, x, y)) { | |
System.out.println("そこに石を置けません"); | |
return; | |
} | |
player.putAndReverse(board, x, y); | |
repaint(); | |
board.printBoard(); | |
board.evaluate(); | |
board.printEvaluation(); | |
if (player1.pass() && player2.pass()) { | |
endGameAndExit(); | |
} | |
turnPlayer(); | |
if (player.pass()) { | |
showMessage(player + "はパスです"); | |
turnPlayer(); | |
} | |
showMessage(player + "の番です"); | |
} | |
public static void main(String[] args) { | |
JFrame f = new JFrame(); | |
f.getContentPane().setLayout(new FlowLayout()); | |
f.getContentPane().add(new Reversi()); | |
f.pack(); | |
f.setResizable(false); | |
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); | |
f.setVisible(true); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment