Skip to content

Instantly share code, notes, and snippets.

@shioken
Last active March 30, 2018 09:08
Show Gist options
  • Save shioken/e90b9fa3b43d8b067adde77a75768efd to your computer and use it in GitHub Desktop.
Save shioken/e90b9fa3b43d8b067adde77a75768efd to your computer and use it in GitHub Desktop.
Reversi for M5Stack
#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