Last active
December 14, 2019 12:39
-
-
Save shiracamus/c2b09af21e50c4fde86ab73a251ca113 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.Scanner; | |
enum Cell { | |
EMPTY("[ ]"), | |
PLAYER1("[O]"), | |
PLAYER2("[X]"); | |
private final String text; | |
private Cell(final String text) { | |
this.text = text; | |
} | |
public String toString() { | |
return text; | |
} | |
} | |
class Board { | |
public final int width; | |
public final int height; | |
private final Cell[][] cells; | |
Board(int width, int height) { | |
this.width = width; | |
this.height = height; | |
this.cells = new Cell[height][width]; | |
for (int y = 0; y < height; y++) { | |
for (int x = 0; x < width; x++) { | |
cells[y][x] = Cell.EMPTY; | |
} | |
} | |
} | |
void put(int x, int y, Cell cell) { | |
cells[y][x] = cell; | |
} | |
boolean isInside(int x, int y) { | |
return 0 <= x && x < width && 0 <= y && y < height; | |
} | |
boolean isCell(int x, int y, Cell cell) { | |
return isInside(x, y) && cells[y][x] == cell; | |
} | |
boolean isEmpty(int x, int y) { | |
return isCell(x, y, Cell.EMPTY); | |
} | |
void print() { | |
for (int x = 0; x < width; x++) { | |
System.out.printf("[%2d]", x); | |
} | |
System.out.println(); | |
for (int y = 0; y < height; y++) { | |
for (int x = 0; x < width; x++) { | |
System.out.print(cells[y][x]); | |
} | |
System.out.println(); | |
} | |
System.out.println(); | |
} | |
} | |
class Rule { | |
public final Board board; | |
public final int connectionsToWin; | |
public final int minColumn; | |
public final int maxColumn; | |
private static final int[][] DIRECTIONS = new int[][] { | |
{1, 0}, {0, 1}, {1, 1}, {-1, 1} | |
}; | |
Rule(Board board, int connectionsToWin) { | |
this.board = board; | |
this.connectionsToWin = connectionsToWin; | |
minColumn = 0; | |
maxColumn = board.width - 1; | |
} | |
boolean isValid(int column) { | |
return board.isInside(column, 0); | |
} | |
boolean isAvailable(int column) { | |
return board.isEmpty(column, 0); | |
} | |
boolean put(int column, Cell cell) { | |
int row = fall(column); | |
board.put(column, row, cell); | |
return isWin(column, row, cell); | |
} | |
int fall(int column) { | |
int row = 0; | |
while (board.isEmpty(column, row)) { | |
row++; | |
} | |
return row - 1; | |
} | |
boolean isWin(int x, int y, Cell cell) { | |
for (var d : DIRECTIONS) { | |
int dx = d[0], dy = d[1]; | |
int connections = 1; | |
for (int cx = x - dx, cy = y - dy; board.isCell(cx, cy, cell); cx -= dx, cy -= dy) { | |
connections++; | |
} | |
for (int cx = x + dx, cy = y + dy; board.isCell(cx, cy, cell); cx += dx, cy += dy) { | |
connections++; | |
} | |
if (connections >= connectionsToWin) { | |
return true; | |
} | |
} | |
return false; | |
} | |
} | |
interface Strategy { | |
boolean put(Cell cell, Rule rule); // return ture if win | |
} | |
class Player { | |
public final String name; | |
public final Cell cell; | |
private String text; | |
private Strategy strategy; | |
Player(String name, Cell cell, Strategy strategy) { | |
this.name = name; | |
this.cell = cell; | |
this.text = name + cell; | |
this.strategy = strategy; | |
} | |
public String toString() { | |
return text; | |
} | |
boolean play(Rule rule) { | |
return strategy.put(cell, rule); | |
} | |
} | |
class InteractiveStrategy implements Strategy { | |
private final Scanner keyboard = new Scanner(System.in); | |
{ | |
keyboard.useDelimiter(System.lineSeparator()); | |
} | |
public boolean put(Cell cell, Rule rule) { | |
return rule.put(selectColumn(rule), cell); | |
} | |
public int selectColumn(Rule rule) { | |
while (true) { | |
System.out.printf("番号(%d〜%d)を入力してください: ", rule.minColumn, rule.maxColumn); | |
String text = keyboard.next().trim(); | |
if (text.length() != 1 || !Character.isDigit(text.charAt(0))) { | |
System.out.println("入力が不正です。"); | |
continue; | |
} | |
int column = Integer.parseInt(text); | |
if (!rule.isValid(column)) { | |
System.out.println("入力が不正です。"); | |
continue; | |
} | |
if (!rule.isAvailable(column)) { | |
System.out.println("[ " + column + "]にはこれ以上入れられません。"); | |
continue; | |
} | |
return column; | |
} | |
} | |
} | |
public class ConnectFour { | |
private final Rule rule; | |
private final Board board; | |
private final Player player1, player2; | |
ConnectFour() { | |
this(7, 6, 4); | |
} | |
ConnectFour(int width, int height, int connectionsToWin) { | |
board = new Board(width, height); | |
rule = new Rule(board, connectionsToWin); | |
Strategy interactive = new InteractiveStrategy(); | |
player1 = new Player("player1", Cell.PLAYER1, interactive); | |
player2 = new Player("player2", Cell.PLAYER2, interactive); | |
} | |
void start() { | |
char num = "零一二三四五六七八九十".charAt(rule.connectionsToWin); | |
System.out.println("重力付き" + num + "目並べ開始"); | |
play(); | |
System.out.println("終了"); | |
} | |
void play() { | |
Player player = player1; | |
board.print(); | |
for (int turn = 0; turn < board.width * board.height; turn++) { | |
System.out.println(player + "の番です。"); | |
boolean win = player.play(rule); | |
System.out.println(); | |
board.print(); | |
if (win) { | |
System.out.println(player + "の勝ち!!"); | |
return; | |
} | |
player = player == player1 ? player2 : player1; | |
} | |
System.out.println("引き分け"); | |
} | |
public static void main(String[] args) { | |
new ConnectFour().start(); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment