Online Gaming With mbed - Tic Tac Toe

Team Members

  • Jonathon Deriso
  • Evgeniy Vinogradov
  • Benjamin Smith
  • Hongyao Shi

Project Description

We have developed an online gaming system that allows two or more users to play simple games online using their mbed. A simple game of Tic Tac Toe has been implemented to demonstrate the system. The user will need an mbed, a uLCD-144-G2 128x128 pixel LCD breakout, and a method with which to connect to the internet. In this demo, we have included instructions for connecting over ethernet using an RJ45 Ethernet MagJack Breakout.

There is also a PC interface so that someone on a PC can play someone on an mbed.

Compontents

mbed pinuLCD Cable
p27Rx
p28Tx
p30RES
Vu5V
GndGnd
mbed pinRJ45 Ethernet Pin
TD+p1
TD-p2
RD+p7
RD-p8

System Architecture

The online gaming system is broken into two logical components: the server and the clients. Communication is in the form of http requests initiated by the clients. State of games and validation is done both on the server and on the clients to protect against invalid input (such as player 1 submitting a move when it is player 2’s turn). To begin playing, clients must try to start a new game, or join an existing game by sending appropriate http requests to the server. If the clients attempts to join an existing game, and there are no games currently available, it returns an error message and the client is responsible for handling the error and allowing the user to start a new game or try again. The clients then continually query the server for the current player, game state, and board state to display the appropriate UI and allow user input. Once the game is over, the clients also query the winner to display to the user.

/media/uploads/bsmit170/mbedonline.png

Library

Import programFinal_test

change to final_test

Code

#iGamePlay

#include "mbed.h"
#include "uLCD_4DGL.h"
#include "board.h"
#include "rtos.h"
#include "EthernetInterface.h"
#include "HTTPClient.h"
#include <sstream>
#include <string>
#include <iostream>

uLCD_4DGL lcd(p28,p27,p30); // serial tx, serial rx, reset pin;
Serial pc(USBTX, USBRX);
DigitalIn in0(p11);
DigitalIn in1(p12);
DigitalIn in2(p13);
DigitalIn in3(p14);
DigitalIn in4(p15);
DigitalIn in5(p16);
DigitalIn in6(p17);
DigitalIn in7(p18);
DigitalIn in8(p19);




int player1=1;
int player2=2;
int turn =1;
int printout = 0;


void printBoard(int ** board)
{
    lcd.cls();
    lcd.line(0, 42 , 127, 42 , 0xFF0000);
    lcd.line(0, 84 , 127, 84 , 0xFF0000);
    lcd.line(42, 0 , 42, 127, 0xFF0000);
    lcd.line(84, 0, 84, 127, 0xFF0000);
    for(int i=0; i<3; i++) {
        for(int j=0; j<3; j++) {
            if(board[i][j] == 0) {
                lcd.line( j*42+2 , i*42 + 2 ,(j+1)*42-2 , (i+1)*42-2 , GREEN);
                lcd.line( j*42+2 , (i+1)*42 - 2 ,(j+1)*42-2 , (i)*42+2 , GREEN);
            } else if(board[i][j] == 1) {
                lcd.circle(42*j+21, 42*i+21, 19, BLUE);
            }
        }
    }
}
typedef enum GAME_STATE {
    STARTING, PLAYING, OVER, RETURN_ERROR = -1
} GAME_STATE;
HTTPClient http;
EthernetInterface eth;
char str[1024];
int StartNewGame()
{
    char* url = "http://4180.azurewebsites.net/api/TicTacToeGames/New\0";
    HTTPResult ret = http.get(url, str, 1024);
    if (ret > 0) {
        pc.printf("HTTP Error return in StartNewGame\n");
        return -1;
    }
    return atoi(str);
}
int JoinGame()
{
    char* url = "http://4180.azurewebsites.net/api/TicTacToeGames/Join\0";
    HTTPResult ret = http.get(url, str, 1024);
    if (ret > 0) {
        pc.printf("HTTP Error return in JoinGame\n");
        return -1;
    }
    return atoi(str);
}
GAME_STATE GetGameState(int gameId)
{
    string s;
    stringstream host;
    host.clear();
    host  << "http://4180.azurewebsites.net/odata/TicTacToeGames(" << gameId << ")?$select=GameState";
    //printf("**** HOST IS  %s\n", host.str().c_str());
    
    HTTPResult ret = http.get(host.str().c_str(), str, 1024, 15000);
    if (ret > 0) {
        pc.printf("HTTP Error return in GetGameState\n");
        return (GAME_STATE)-1;
    }
    s = string(str);
    if (s.find("\"GameState\":\"STARTING\"") != string::npos)
        return STARTING;
    else if(s.find("\"GameState\":\"PLAYING\"") != string::npos)
        return PLAYING;
    else if(s.find("\"GameState\":\"OVER\"") != string::npos)
        return OVER;
    else
        return RETURN_ERROR;

  //  return (GAME_STATE)atoi(str);
}
void ParseBoard(string str, int** board)
{

    // printf("Entering ParseBoard, got %s\n", str.c_str());
    for (int i = 0; i < str.length(); i++) {
        if (str[i] == '[' || str[i] == ']' || str[i] == ',' || str[i] == '"')
            str[i] = ' ';
    }
    string temp;
    for (int i = 0; i < str.length() - 1; i++) {
        if (!(str[i] == ' ' && str[i+1] == ' ')) {
            temp += str[i];
        }

    }

    str = temp;
    // printf("With changed delimiters %s\n", str.c_str());
    stringstream stream(str);
    int t = 0;
    for (int i = 0; i < 3; i++) {
        for (int j = 0; j < 3; j++) {
            stream >> board[i][j];
            //printf("%d\n", board[i][j]);
        }
    }

    /*  for (int i = 0; i < 3; i++) {
        printf("\n[");
        for (int j = 0; j < 3; j++)
            printf("%d ", board[i][j]);
        printf("]");
    }*/
}
int PostMove(int playerId,int gameId, int x, int y)
{
    stringstream host;
    host  << "http://4180.azurewebsites.net/api/TicTacToeGames?gameId=" << gameId << "&playerId=" << playerId << "&moveX=" << x << "&moveY=" << y;
    string s = host.str();
    HTTPText datain("");
    HTTPMap dataout;
    HTTPResult ret = http.post(s.c_str(), dataout, &datain, 10000);
    if (ret > 0) {
        pc.printf("HTTP Error in PostMove");
        return -1;
    }
    return 0;

}
int GetCurrentPlayer(int gameId)
{

    stringstream host;
    host  << "http://4180.azurewebsites.net/odata/TicTacToeGames(" << gameId << ")?$select=CurrentPlayer";
    string s = host.str();
    int retry_count = 5;
    HTTPResult ret = (HTTPResult)1;
    while (ret > 0 & retry_count-- > 0)
        ret = http.get(s.c_str(), str, 1024);
    if (ret > 0) {
        pc.printf("HTTP Error return in GetCurrentPlayer\n");
        return -1;
    }
    s = string(str);
    int pos = s.find("\"CurrentPlayer\":");
    if (pos == string::npos)
        return -1;
    return s[pos+16] - '0';
}
int GetWinner(int gameId)
{

    stringstream host;
    host  << "http://4180.azurewebsites.net/odata/TicTacToeGames(" << gameId << ")?$select=Winner";
    string s = host.str();
    int retry_count = 5;
    HTTPResult ret = (HTTPResult)1;
    while (ret > 0 & retry_count-- > 0)
        ret = http.get(s.c_str(), str, 1024);
    if (ret > 0) {
        pc.printf("HTTP Error return in GetWinner\n");
        return -1;
    }
    s = string(str);
    int pos = s.find("\"Winner\":");
    if (pos == string::npos)
        return -1;
    return s[pos+9] - '0';
}
int GetBoardState(int gameId, int** board)
{
    stringstream host;
    host  << "http://4180.azurewebsites.net/odata/TicTacToeGames(" << gameId << ")?$select=BoardState";
    string s = host.str();
    int retry_count = 5;
    HTTPResult ret = (HTTPResult)1;
    while (ret > 0 & retry_count-- > 0)
        ret = http.get(s.c_str(), str, 1024);
    if (ret > 0) {
        pc.printf("HTTP Error return in GetBoardState\n");
        return -1;
    }
    s = string(str);
    int pos = s.find("\"BoardState\":");
    if (pos == string::npos)
        return -1;

    ParseBoard(s.substr(pos +13, string::npos), board);
    return 0;
}
string GameStateToString(GAME_STATE state)
{
    switch(state) {
        case STARTING:
            return "STARTING";
        case PLAYING:
            return "PLAYING";
        case OVER:
            return "OVER";
        default:
        case RETURN_ERROR:
            return "ERROR";
    }
}
int GetSerialInput()
{
    return pc.getc() - '0';
}
void ScanForMove(int* x, int* y, int** board)
{
    
    while(1) {
        if (!in0 && board[0][0]== -1) {
            *x = 0;
            *y = 0;
            return;
        } else if (!in1 && board[0][1] == -1) {
            *x = 0;
            *y = 1;
            return;
        } else if (!in2 && board[0][2] == -1) {
            *x = 0;
            *y = 2;
            return;
        } else if (!in3 && board[1][0] == -1) {
            *x = 1;
            *y = 0;
            return;
        } else if (!in4 && board[1][1] == -1) {
            *x = 1;
            *y = 1;
            return;
        } else if (!in5 && board[1][2] == -1) {
            *x = 1;
            *y = 2;
            return;
        } else if (!in6 && board[2][0] == -1) {
            *x = 2;
            *y = 0;
            return;
        } else if (!in7 && board[2][1] == -1) {
            *x = 2;
            *y = 1;
            return;
        } else if (!in8 && board[2][2] == -1) {
            *x = 2;
            *y = 2;
            return;
        }
        wait(0.2);
    }
}
int main()
{
    pc.printf("Ethernet connecting...\n");
    eth.init(); //Use DHCP
    eth.connect();
    pc.printf("IP Address is %s\n", eth.getIPAddress());

    in0.mode(PullUp);
    in1.mode(PullUp);
    in2.mode(PullUp);
    in3.mode(PullUp);
    in4.mode(PullUp);
    in5.mode(PullUp);
    in6.mode(PullUp);
    in7.mode(PullUp);
    in8.mode(PullUp);
    lcd.baudrate(3000000);

    // START GAME OR JOIN GAME
    // FORMAT THIS TO LOOK PRETTY ON LCD
    int gameId = -1;
    int playerId = -1;
    bool reprint = true;
    do {
        if (reprint) {
            lcd.cls();
            lcd.text_width(2);
            lcd.text_height(2);
            
            lcd.printf("Button ");
            lcd.color(RED);
            lcd.printf("0");
            lcd.color(GREEN);
            lcd.printf(":");
            
            lcd.text_width(1);
            lcd.text_height(1);
            lcd.printf("\n\n\n Start New Game\n\n");
            lcd.text_width(2);
            lcd.text_height(2);
            lcd.printf("Button ");
            lcd.color(RED);
            lcd.printf("1");
            lcd.color(GREEN);
            lcd.printf(":");
            lcd.text_width(1);
            lcd.text_height(1);
            lcd.printf("\n\n\nJoin Existing Game");
            reprint = false;
            lcd.text_width(0);
            lcd.text_height(0);
        }

        if (!in0 /*|| true*/) {
            // Start Game
            gameId = StartNewGame();
            if (gameId < 1) { // fail
                lcd.printf("Failed to start a new game!\n");
                wait(1.5);
                reprint = true;
            } else
                playerId = 0;

        } else if(!in1) {
            gameId = JoinGame();
            if (gameId < 1) { // fail
                lcd.printf("Failed to join game, try making one!\n");
                wait(1.5);
                reprint = true;
            } else
                playerId = 1;
        }
    } while (gameId < 1);
    lcd.cls();

    if (playerId == 1){
        pc.printf("Successfully joined game %d!\n", gameId);
        lcd.printf("Successfully joined game %d!\n", gameId);
        }
    else{
        pc.printf("Successfully started game %d!\n", gameId);
        lcd.printf("Successfully started game %d!\n", gameId);
        }

    wait(1.5);

    Board board;
    lcd.cls();
    lcd.printf("Waiting for game to start...\n");
    // wait for game to start
    while(GetGameState(gameId) != PLAYING) {
        wait(2);
    }

    // Main Game Loop
    lcd.cls();

    while(1) {
        GAME_STATE state = GetGameState(gameId);
        if (state == OVER)
            break; // game over
        // wait for turn
        while(GetCurrentPlayer(gameId) != playerId){ wait(1.5); }
        wait(0.5);
        GetBoardState(gameId, board.get_board());
        printBoard(board.get_board());
                    
        state = GetGameState(gameId);
        if (state == OVER)
            break;
        int moveX, moveY;
        ScanForMove(&moveX,&moveY, board.get_board());
        PostMove(playerId, gameId, moveX, moveY);
        GetBoardState(gameId, board.get_board());
        printBoard(board.get_board());
        wait(2);
    }
    int winner = GetWinner(gameId);
    pc.printf("Player %d Won!\n", winner);
    lcd.printf("Player %d Won!\n", winner);





Please log in to post comments.