Last active
March 30, 2018 09:08
-
-
Save shioken/e90b9fa3b43d8b067adde77a75768efd to your computer and use it in GitHub Desktop.
Reversi for M5Stack
This file contains 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
#include <M5Stack.h> | |
#define PIECE_BLANK 0 | |
#define PIECE_WHITE 1 | |
#define PIECE_BLACK 2 | |
#define BOARD_SIZE 64 | |
#define BOARD_WIDTH 8 | |
#define SQUARE_WIDTH 28 | |
#define PIECE_RADIUS 10 | |
#define BOARD_MARGIN 8 | |
#define GETX(i) ((i) % BOARD_WIDTH) | |
#define GETY(i) ((i) / BOARD_WIDTH) | |
#define INDEX(x, y) ((x) + (y) * BOARD_WIDTH) | |
enum Status { | |
WaitBlack, | |
WaitWhite, | |
NextBlack, | |
GameOver | |
}; | |
Status status; | |
boolean passed; | |
int board[BOARD_SIZE]; | |
int cursor_index; | |
int number_of_moves; | |
int moves[BOARD_SIZE - 4]; | |
int score[3]; | |
void setup() { | |
M5.begin(); | |
M5.Lcd.setBrightness(100); | |
M5.Lcd.fillScreen(BLACK); | |
initGame(); | |
} | |
void initGame() { | |
for (int i = 0; i < BOARD_SIZE; i++) { | |
board[i] = PIECE_BLANK; | |
} | |
board[INDEX(3, 3)] = PIECE_WHITE; | |
board[INDEX(4, 4)] = PIECE_WHITE; | |
board[INDEX(4, 3)] = PIECE_BLACK; | |
board[INDEX(3, 4)] = PIECE_BLACK; | |
score[PIECE_WHITE] = 2; | |
score[PIECE_BLACK] = 2; | |
drawBoard(); | |
drawPieces(); | |
drawScore(); | |
makeCanMove(); | |
cursor_index = 0; | |
drawCursor(); | |
status = WaitBlack; | |
passed = false; | |
} | |
void loop() { | |
if (status == WaitBlack) { | |
if (M5.BtnA.wasPressed()) { | |
eraseCursor(); | |
cursor_index = (cursor_index + 1) % number_of_moves; | |
drawCursor(); | |
} | |
if (M5.BtnB.wasPressed()) { | |
eraseCursor(); | |
cursor_index = (cursor_index + number_of_moves - 1) % number_of_moves; | |
drawCursor(); | |
} | |
if (M5.BtnC.wasPressed()) { | |
eraseCursor(); | |
putPiece(moves[cursor_index], PIECE_BLACK); | |
if (isGameOver()) { | |
status = GameOver; | |
} | |
else { | |
status = WaitWhite; | |
} | |
} | |
} | |
else if (status == WaitWhite) { | |
delay(1000); | |
compute(PIECE_WHITE); | |
} | |
else if (status == NextBlack) { | |
delay(1000); | |
makeCanMove(); | |
if (number_of_moves > 0) { | |
cursor_index = 0; | |
drawCursor(); | |
status = WaitBlack; | |
} | |
else { | |
if (passed) { | |
status = GameOver; | |
} | |
else { | |
passed = true; | |
status = WaitWhite; | |
} | |
} | |
} | |
else if (status == GameOver) { | |
if (M5.BtnC.wasPressed()) { | |
initGame(); | |
} | |
} | |
M5.update(); | |
} | |
void drawBoard() { | |
M5.Lcd.fillRect(0, 0, 240, 240, 0b000001111100000); | |
for (int i = 0; i < 9; i++) { | |
M5.Lcd.drawLine(i * SQUARE_WIDTH + BOARD_MARGIN, BOARD_MARGIN, i * SQUARE_WIDTH + BOARD_MARGIN, SQUARE_WIDTH * BOARD_WIDTH + BOARD_MARGIN, BLACK); | |
M5.Lcd.drawLine(BOARD_MARGIN, i * SQUARE_WIDTH + BOARD_MARGIN, SQUARE_WIDTH * BOARD_WIDTH + BOARD_MARGIN, i * SQUARE_WIDTH + BOARD_MARGIN, BLACK); | |
} | |
} | |
void drawPieces() { | |
for (int i = 0; i < BOARD_SIZE; i++) { | |
drawPiece(i); | |
} | |
} | |
void drawPiece(int index) { | |
if (board[index] != PIECE_BLANK) { | |
int x = GETX(index); | |
int y = GETY(index); | |
M5.Lcd.fillCircle(x * SQUARE_WIDTH + BOARD_MARGIN + SQUARE_WIDTH / 2, y * SQUARE_WIDTH + BOARD_MARGIN + SQUARE_WIDTH / 2, PIECE_RADIUS, board[index] == PIECE_BLACK ? BLACK : WHITE); | |
} | |
} | |
void makeCanMove() { | |
number_of_moves = 0; | |
for (int i = 0; i < BOARD_SIZE; i++) { | |
if (canMove(i, PIECE_BLACK)) { | |
moves[number_of_moves] = i; | |
number_of_moves++; | |
} | |
} | |
} | |
boolean canMove(int index, int piece) { | |
if (board[index] != PIECE_BLANK) return false; | |
int x = GETX(index); | |
int y = GETY(index); | |
for (int x1 = -1; x1 < 2; x1++) { | |
for (int y1 = -1; y1 < 2; y1++) { | |
if (canPut(x, y, x1, y1, piece)) { | |
return true; | |
} | |
} | |
} | |
return false; | |
} | |
boolean canPut(int x, int y, int x1, int y1, int piece) { | |
if (x1 == 0 && y1 == 0) return false; | |
int ax = x + x1; | |
int ay = y + y1; | |
if (ax < 0 || ax >= BOARD_WIDTH || ay < 0 || ay >= BOARD_WIDTH) return false; | |
boolean can_move = false; | |
if (board[INDEX(ax, ay)] == (PIECE_WHITE + PIECE_BLACK) - piece) { | |
while(true) { | |
ax += x1; | |
ay += y1; | |
if (ax < 0 || ax >= BOARD_WIDTH || ay < 0 || ay >= BOARD_WIDTH) break; | |
if (board[INDEX(ax, ay)] == PIECE_BLANK) break; | |
if (board[INDEX(ax, ay)] == piece) { | |
return true; | |
} | |
} | |
} | |
return false; | |
} | |
void putPiece(int index, int piece) { | |
board[index] = piece; | |
score[piece]++; | |
drawPiece(index); | |
passed = false; | |
int x = GETX(index); | |
int y = GETY(index); | |
for (int x1 = -1; x1 < 2; x1++) { | |
for (int y1 = -1; y1 < 2; y1++) { | |
if (canPut(x, y, x1, y1, piece)) { | |
int ax = x + x1; | |
int ay = y + y1; | |
while (board[INDEX(ax, ay)] != piece) { | |
board[INDEX(ax, ay)] = piece; | |
drawPiece(INDEX(ax, ay)); | |
score[piece]++; | |
score[PIECE_BLACK + PIECE_WHITE - piece]--; | |
ax += x1; | |
ay += y1; | |
} | |
} | |
} | |
} | |
drawScore(); | |
} | |
void drawCursor() { | |
int index = moves[cursor_index]; | |
int x = index % BOARD_WIDTH; | |
int y = index / BOARD_WIDTH; | |
M5.Lcd.drawCircle(x * SQUARE_WIDTH + BOARD_MARGIN + SQUARE_WIDTH / 2, y * SQUARE_WIDTH + BOARD_MARGIN + SQUARE_WIDTH / 2, PIECE_RADIUS, BLACK); | |
} | |
void eraseCursor() { | |
int index = moves[cursor_index]; | |
int x = index % BOARD_WIDTH; | |
int y = index / BOARD_WIDTH; | |
M5.Lcd.fillRect(x * SQUARE_WIDTH + BOARD_MARGIN + 1, y * SQUARE_WIDTH + BOARD_MARGIN + 1, SQUARE_WIDTH - 2, SQUARE_WIDTH - 2, 0b000001111100000); | |
} | |
int priority[4][15] = { | |
{ 0, 18, 16, 2, 10, 17, 11, 25, 19, 26, 3, 24, 1, 8, 9,}, | |
{ 7, 21, 23, 5, 13, 22, 12, 30, 20, 29, 4, 31, 6, 15, 14,}, | |
{56, 42, 40, 58, 50, 41, 51, 33, 43, 34, 59, 32, 57, 48, 49,}, | |
{63, 45, 47, 61, 53, 46, 52, 38, 44, 37, 60, 39, 62, 55, 54,}}; | |
void compute(int piece) { | |
int search[4] = {0, 1, 2, 3}; | |
for (int index = 0; index < 4; index++) { | |
int i = random(4); | |
int j = random(4); | |
int temp = search[i]; | |
search[i] = search[j]; | |
search[j] = temp; | |
} | |
for (int p = 0; p < 15; p++) { | |
for (int d = 0; d < 4; d++) { | |
int index = priority[search[d]][p]; | |
if (canMove(index, PIECE_WHITE)) { | |
putPiece(index, PIECE_WHITE); | |
if (isGameOver()) { | |
status = GameOver; | |
} | |
else { | |
status = NextBlack; | |
} | |
return; | |
} | |
} | |
} | |
// Pass | |
if (passed) { | |
status = GameOver; | |
} | |
else { | |
passed = true; | |
status = WaitBlack; | |
} | |
} | |
boolean isGameOver() { | |
return score[PIECE_BLACK] + score[PIECE_WHITE] == BOARD_SIZE; | |
} | |
void drawScore() { | |
M5.Lcd.setTextColor(WHITE); | |
M5.Lcd.setTextSize(1); | |
M5.Lcd.fillRect(240, 0, 80, 240, BLACK); | |
M5.Lcd.drawCircle(240 + 8 + PIECE_RADIUS, 120 - PIECE_RADIUS - 8, PIECE_RADIUS, WHITE); | |
M5.Lcd.fillCircle(240 + 8 + PIECE_RADIUS, 120 + PIECE_RADIUS + 8, PIECE_RADIUS, WHITE); | |
M5.Lcd.setCursor(240 + 8 + PIECE_RADIUS * 2 + 8, 120 - PIECE_RADIUS - 8); | |
M5.Lcd.printf("%d", score[PIECE_BLACK]); | |
M5.Lcd.setCursor(240 + 8 + PIECE_RADIUS * 2 + 8, 120 + PIECE_RADIUS + 8); | |
M5.Lcd.printf("%d", score[PIECE_WHITE]); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment