Saving Game Data

... by Bittle in Java Telegram Bot April 12, 2019

We are going to use SQLite JDBC because it's simple to set up. Download the latest .jar file and import it. We have one game so far, so we need to create a game table that holds usernames and scores.


SQL

Create game table:

String sql = "CREATE TABLE IF NOT EXISTS games ("
        + " username text NOT NULL UNIQUE,\n"
        + " guess_score INTEGER NOT NULL);";

Insert new player into game table (0 score for all games):

String sql = "INSERT INTO " + TABLE_GAME +
        "(username,guess_score) VALUES(?,0)";

Increment score for player by 1:

String sql = "UPDATE " + TABLE_GAME +
        " SET " + game_name + " = " + game_name + " + 1 "+
        " WHERE username = ?";

Get scores for player:

String sql = "SELECT " + game_name + " "
        + "FROM " + TABLE_GAME + " WHERE username = ?";


Code

Let's put all the SQL code together and get a working database! The basic functions we need are:

  1. Connection
  2. Creating table
  3. Inserting players
  4. Updating player scores
  5. Getting scores

These functions will use the SQL mentioned above.


The final Database class will look like this:

Database.java
import java.sql.*;

public class Database {

    private static Database db = null;

    public static Database getInstance() {
        if (db == null) {
            db = new Database();
        }
        return db;
    }

    private final String DB_NAME = "jdbc:sqlite:database.db";
    private final String TABLE_GAME = "game";

    public Database() {
        createDatabase();
        createGameTable();
    }

    private void createDatabase() {

        try {
            DriverManager.getConnection(DB_NAME);
        } catch (Exception e) {
            System.out.println(e.getMessage());
        }
    }

    private void createGameTable() {
        // SQL statement for creating a new table
        String sql = "CREATE TABLE IF NOT EXISTS " + TABLE_GAME + "("
                + "    username text NOT NULL UNIQUE,\n"
                + " guess_score INTEGER NOT NULL);";

        try (Connection conn = DriverManager.getConnection(DB_NAME);
             Statement stmt = conn.createStatement()) {
            // create a new table
            stmt.execute(sql);
        } catch (Exception e) {
            System.out.println(e.getMessage());
        }
    }

    private Connection connect() {
        // SQLite connection string
        Connection conn = null;
        try {
            Class.forName("org.sqlite.JDBC");
            conn = DriverManager.getConnection(DB_NAME);
        } catch (Exception e) {
            System.out.println(e.getMessage());
        }
        return conn;
    }

    // com.bit.telebot.game methods
    private void createGameEntry(String username) {
        String sql = "INSERT INTO " + TABLE_GAME +
                "(username,guess_score) VALUES(?,0)";

        try (Connection conn = this.connect();
             PreparedStatement pstmt = conn.prepareStatement(sql)) {
            pstmt.setString(1, username);
            pstmt.executeUpdate();
        } catch (Exception e) {
            //System.out.println(e.getMessage());
        }
    }

    private void incrementScore(String username, String game_name, int val) {
        // try to update the type score for the username, if not successful it means that
        // that user is not in db, so add em with a 1 score for type
        createGameEntry(username);
        String sql = "UPDATE " + TABLE_GAME +
                " SET " + game_name + " = " + game_name + " + " + val + " " +
                " WHERE username = ?";

        try (Connection conn = this.connect();
             PreparedStatement pstmt = conn.prepareStatement(sql)) {
            pstmt.setString(1, username);
            pstmt.executeUpdate();
        } catch (Exception e) {
            System.out.println(e.getMessage());
        }
    }

    public void incrementGuessScore(String username) {
        incrementScore(username, "guess_score", 1);
    }

    private long getScore(String username, String game_name) {
        createGameEntry(username);
        String sql = "SELECT " + game_name + " "
                + "FROM " + TABLE_GAME + " WHERE username = ?";

        try (Connection conn = this.connect();
             PreparedStatement pstmt = conn.prepareStatement(sql)) {

            // set the value
            pstmt.setString(1, username);

            ResultSet rs = pstmt.executeQuery();

            // loop through the result set
            if (rs.next()) {
                return rs.getInt(game_name);
            }
            return -1;
        } catch (SQLException e) {
            System.out.println(e.getMessage());
            return -2;
        }
    }

    public long getGuessScore(String username) {
        return getScore(username, "guess_score");
    }

}

I would go through how everything works, but we want to get to the juicy section of the steak! The Database code is mostly self explanatory. If you struggle to understand how it works read this. Ok, so let's get to saving information! In the GameHandler class will call

Database.getInstance().incrementGuessScore(username);

whenever the user was correct in their guess:

GameHandler check function
// check if guess game answered correctly
else if (game.guessGame != null && message_text_lower.contains(game.guessGame.getAnswer())) {
    Database.getInstance().incrementGuessScore(username);
    // reset the guess game!
    game.guessGame = null;
    kodeCentralBot.sendMessage(Long.toString(chatId), username + " has won!");
}

Ok, so now the database will keep track of scores, but how do we see them? Let's add another command /scores which will retrieve the guess scores for that user and return a message:

GameHanlder check function
else if (message_text_lower.equals("/scores")) {
    Database d = Database.getInstance();
    kodeCentralBot.sendMessage(Long.toString(chatId), "Guess: " + d.getGuessScore(username));
}


Files

Main.java
import org.telegram.telegrambots.ApiContextInitializer;
import org.telegram.telegrambots.meta.TelegramBotsApi;
import org.telegram.telegrambots.meta.exceptions.TelegramApiException;

public class Main {
    public static void main(String[] args) {
        // Initialize Api Context
        ApiContextInitializer.init();

        // Instantiate Telegram Bots API
        TelegramBotsApi botsApi = new TelegramBotsApi();

        // Register our bot
        try {
            botsApi.registerBot(new KodeCentralBot());
        } catch (TelegramApiException e) {
            e.printStackTrace();
        }
    }
}


KodeCentralBot.java
import org.telegram.telegrambots.bots.TelegramLongPollingBot;
import org.telegram.telegrambots.meta.api.methods.send.SendMessage;
import org.telegram.telegrambots.meta.api.methods.send.SendPhoto;
import org.telegram.telegrambots.meta.api.objects.Update;
import org.telegram.telegrambots.meta.exceptions.TelegramApiException;

import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.Date;

public class KodeCentralBot extends TelegramLongPollingBot {
    public void onUpdateReceived(Update update) {
        // We check if the update has a message and the message has text
        if (update.hasMessage() && update.getMessage().hasText()) {
            // NEW:
            GameHandler.check(this, update);
        }
    }

    private void log(String username, String chatId, String textReceived, String botResponse) {
        System.out.println("----------------------------\n");
        // print out in PM/AM time
        DateFormat dateFormat = new SimpleDateFormat("yyyy/MM/dd h:mm a");
        Date date = new Date();
        System.out.println(dateFormat.format(date));
        System.out.println("Message from " + username + ". (id = " + chatId + ") \n Text - " + textReceived);
        System.out.println("Bot answer: \n Text - " + botResponse);
    }

    public void sendPhoto(String chatId, String url) {
        SendPhoto sendPhoto = new SendPhoto();
        sendPhoto.setChatId(chatId);
        sendPhoto.setPhoto(url);

        try {
            execute(sendPhoto);
        } catch (TelegramApiException e) {
            e.printStackTrace();
        }
    }

    public void sendMessage(String chatId, String message) {
        SendMessage sendMessageRequest = new SendMessage();
        sendMessageRequest.setChatId(chatId);
        sendMessageRequest.setText(message);
        try {
            execute(sendMessageRequest);
        } catch (TelegramApiException e) {
            e.printStackTrace();
        }
    }

    public String getBotUsername() {
        // Return bot username
        // If bot username is @KodeCentralBot, it must return 'KodeCentralBot'
        return "KodeCentralBot";
    }

    @Override
    public String getBotToken() {
        // Return bot token from BotFather
        return "token";
    }
}


GameHandler.java
import org.telegram.telegrambots.meta.api.objects.Message;
import org.telegram.telegrambots.meta.api.objects.Update;

import java.util.HashMap;

public class GameHandler {

    private static class Game {

        // for upcoming tutorial
        private ImageGuess guessGame = null;
    }

    // to play separate games on separate groups
    private static HashMap<Long, Game> games = new HashMap<Long, Game>();

    public static void check(KodeCentralBot kodeCentralBot, Update update) {
        // create a new game if this group doesn't have one already, otherwise grab from HashMap
        Game game = new Game();
        long chatId = update.getMessage().getChatId();
        if (games.containsKey(chatId))
            game = games.get(chatId);
        else {
            games.put(chatId, game);
        }

        // variables
        Message message = update.getMessage();
        String message_text = message.getText();
        String message_text_lower = message_text.toLowerCase();
        String username = message.getFrom().getUserName();

        // check if starting a new guess game
        if (message_text_lower.equals("/guess") || message_text_lower.equals("???? guess")) {
            // only create a new guess game if there isn't one
            if (game.guessGame == null) {
                game.guessGame = ImageGuess.random();
            }
            kodeCentralBot.sendPhoto(Long.toString(chatId), game.guessGame.getUrl());
        }
        // check if guess game answered correctly
        else if (game.guessGame != null && message_text_lower.contains(game.guessGame.getAnswer())) {
            Database.getInstance().incrementGuessScore(username);
            // reset the guess game!
            game.guessGame = null;
            kodeCentralBot.sendMessage(Long.toString(chatId), username + " has won!");
        } else if (message_text_lower.equals("/scores")) {
            Database d = Database.getInstance();
            kodeCentralBot.sendMessage(Long.toString(chatId), "Guess: " + d.getGuessScore(username));
        }
    }
}


Database.java
import java.sql.*;

public class Database {

    private static Database db = null;

    public static Database getInstance() {
        if (db == null) {
            db = new Database();
        }
        return db;
    }

    private final String DB_NAME = "jdbc:sqlite:database.db";
    private final String TABLE_GAME = "game";

    public Database() {
        createDatabase();
        createGameTable();
    }

    private void createDatabase() {

        try {
            DriverManager.getConnection(DB_NAME);
        } catch (Exception e) {
            System.out.println(e.getMessage());
        }
    }

    private void createGameTable() {
        // SQL statement for creating a new table
        String sql = "CREATE TABLE IF NOT EXISTS " + TABLE_GAME + "("
                + "    username text NOT NULL UNIQUE,\n"
                + " guess_score INTEGER NOT NULL);";

        try (Connection conn = DriverManager.getConnection(DB_NAME);
             Statement stmt = conn.createStatement()) {
            // create a new table
            stmt.execute(sql);
        } catch (Exception e) {
            System.out.println(e.getMessage());
        }
    }

    private Connection connect() {
        // SQLite connection string
        Connection conn = null;
        try {
            Class.forName("org.sqlite.JDBC");
            conn = DriverManager.getConnection(DB_NAME);
        } catch (Exception e) {
            System.out.println(e.getMessage());
        }
        return conn;
    }

    // com.bit.telebot.game methods
    private void createGameEntry(String username) {
        String sql = "INSERT INTO " + TABLE_GAME +
                "(username,guess_score) VALUES(?,0)";

        try (Connection conn = this.connect();
             PreparedStatement pstmt = conn.prepareStatement(sql)) {
            pstmt.setString(1, username);
            pstmt.executeUpdate();
        } catch (Exception e) {
            //System.out.println(e.getMessage());
        }
    }

    private void incrementScore(String username, String game_name, int val) {
        // try to update the type score for the username, if not successful it means that
        // that user is not in db, so add em with a 1 score for type
        createGameEntry(username);
        String sql = "UPDATE " + TABLE_GAME +
                " SET " + game_name + " = " + game_name + " + " + val + " " +
                " WHERE username = ?";

        try (Connection conn = this.connect();
             PreparedStatement pstmt = conn.prepareStatement(sql)) {
            pstmt.setString(1, username);
            pstmt.executeUpdate();
        } catch (Exception e) {
            System.out.println(e.getMessage());
        }
    }

    public void incrementGuessScore(String username) {
        incrementScore(username, "guess_score", 1);
    }

    private long getScore(String username, String game_name) {
        createGameEntry(username);
        String sql = "SELECT " + game_name + " "
                + "FROM " + TABLE_GAME + " WHERE username = ?";

        try (Connection conn = this.connect();
             PreparedStatement pstmt = conn.prepareStatement(sql)) {

            // set the value
            pstmt.setString(1, username);

            ResultSet rs = pstmt.executeQuery();

            // loop through the result set
            if (rs.next()) {
                return rs.getInt(game_name);
            }
            return -1;
        } catch (SQLException e) {
            System.out.println(e.getMessage());
            return -2;
        }
    }

    public long getGuessScore(String username) {
        return getScore(username, "guess_score");
    }

}


ImageGuess.java
import java.util.ArrayList;
import java.util.Random;

class ImageGuess {
    private String url;
    private String answer;

    public ImageGuess(String url, String answer) {
        this.url = url;
        this.answer = answer;
    }

    public String getUrl() {
        return url;
    }

    public String getAnswer() {
        return answer;
    }

    private static ArrayList<ImageGuess> l = new ArrayList<ImageGuess>();

    private static void initList() {

        l.add(new ImageGuess("https://bit.ly/2R9FiRU", "zebra"));
        l.add(new ImageGuess("https://bit.ly/2RCc3Gu", "horse"));
        l.add(new ImageGuess("https://bit.ly/2RxAcOD", "shark"));
        // and so forth...
    }

    // get a random image
    static ImageGuess random() {
        if (l.isEmpty())
            initList();
        return l.get(new Random().nextInt(l.size()));
    }
}

I included all files in case yours got messed up along the way.


And there you have it! Your own bot that can now keep track of games and scores! See you soon!


Output

Comments (0)

Search Here