A game of snake

A game of snake

snäke

A game of snake

As the last assignment of our java-course we had to create any kind of java based project that used a servlet based web-programming structure. The project had to include a database connection and a full create, read, update and delete that creates a table off the stored data in the database. 

(Insert pic of full functioning program)

I chose to create a game of snake with a database connection where the players scores would be stored with a player chosen username to identify each specific score. The game would use javascript to run the actual game but all server-end stuff (back end) would be using java.

The database client I used was a mariadb-client running on one of our schools servers. No passwords or usernames will be provided in code once again. The project was fully written in using the Ecilpse java-editor and run in browser from a localhost address so nothing was fully published. 

 

Landing page

The first task I had was to write a functional landing page that would pass on data to the server. The data that needed to be passed would be the user selected username and the color of the snake they wished to play as. The landing page was a basic html/css page that was controlled by a java-servlet. Once the user presses 'submit' on the form the servlet then reads the data in the specified fields.

snake1

 

<%@ page language="java" contentType="text/html; charset=ISO-8859-1"

pageEncoding="ISO-8859-1"%>

<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">

<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>

<html>

<head>

<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">

<link rel="stylesheet" href ="${pageContext.request.contextPath}/css/styles.css">

<link href="https://fonts.googleapis.com/css?family=Bungee+Inline" rel="stylesheet">

<link href="https://fonts.googleapis.com/css?family=Oxygen" rel="stylesheet">

<title>Projektin etusivu</title>

</head>

<body>

<h1>Hieno Projekti</h1>

<!-- Not necessary tbf -->

<div id = "topbar"/>

<div id = "form_div">

<form action = "devpro" method = "post" id = "formm">

<p>Type in your username</p>

<input type = "text" name = "userName" placeholder = "Username" class = "inputfield"><div class = "emptyerr"><c:out value="${emptyuserError}"></c:out></div>

<p>Choose your color</p>

<input type = "radio" name = "color" value = "green" checked class = "radio"> Green

<input type = "radio" name = "color" value = "blue" class = "radio"> Blue

<input type = "radio" name = "color" value = "yellow" class = "radio"> Yellow<br><br>

<input type = "submit" value = Submit class = "button">

</form>

</div>

</body>

</html>

 

 And the servlet code

package SnakeGameControl;

import javax.servlet.RequestDispatcher;

import java.io.IOException;

import java.util.regex.Pattern;

import javax.servlet.ServletException;

import javax.servlet.annotation.WebServlet;

import javax.servlet.http.HttpServlet;

import javax.servlet.http.HttpServletRequest;

import javax.servlet.http.HttpServletResponse;

@WebServlet("/devpro")

public class DevPro extends HttpServlet {

private static final long serialVersionUID = 1L;

public DevPro() {

super();

}

protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {

String jsp = "/view/projektinetusivu.jsp";

RequestDispatcher dispatcher = getServletContext().getRequestDispatcher(jsp);

dispatcher.forward(request, response);

}

protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {

// Takes user input from post for username with String Feeds to server prints on second site

// Takes user choice and prints on second screen

String userName = request.getParameter("userName");

String buttonCol =request.getParameter("color");

String eUserError = "";

if (userName.equals("")) {

String jsp = "/view/projektinetusivu.jsp";

eUserError = "Can't be empty";

request.setAttribute("emptyuserError", eUserError);

RequestDispatcher dispatcher = getServletContext().getRequestDispatcher(jsp);

dispatcher.forward(request, response);

}

// doesn't work

else if(Pattern.matches("[^\\da-zåäöA-ZÅÖÄ]",userName)) {

String jsp = "/view/projektinetusivu.jsp";

eUserError = "Can only contain letters, underscore or numbers";

request.setAttribute("emptyuserError", eUserError);

RequestDispatcher dispatcher = getServletContext().getRequestDispatcher(jsp);

dispatcher.forward(request, response);

}

String jsp = "/view/secondpage.jsp";

request.setAttribute("inUserName", userName);

request.setAttribute("inColor", buttonCol);

RequestDispatcher dispatcher = getServletContext().getRequestDispatcher(jsp);

dispatcher.forward(request, response);

}

}

 

The game page

After the user submits the form my servlet then directs the user to the page where the magic happens also known as the most basic game of all time after pong.

Some challenges I encountered while writing this page was related to passing the info I got from the first page forward. I found a solution to this by writing the users name in to a hidden form with the score they got that then posts as the user clicks on the prompt they get after losing the game on whether they want to play again or not. 

snake2

This page was also controlled by a servlet that uses a get method to get the userinfo from the hidden form. 

The servlet also opens a database connection with an sql insert statement that it runs to push the username and score to the database.

The control servlet

package SnakeGameControl;

import java.io.IOException;

import javax.servlet.RequestDispatcher;

import javax.servlet.ServletException;

import javax.servlet.annotation.WebServlet;

import javax.servlet.http.HttpServlet;

import javax.servlet.http.HttpServletRequest;

import javax.servlet.http.HttpServletResponse;

import snake.model.dao.SnakeDAO;

import snakeuser.model.UserScore;

@WebServlet("/insert")

public class InsertScoreServlet extends HttpServlet {

private static final long serialVersionUID = 1L;

public InsertScoreServlet() {

super();

// TODO Auto-generated constructor stub

}

protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {

String jsp = "/scoreboard";

String userName = request.getParameter("lol");

String userScore = request.getParameter("userscore");

int intScore = Integer.parseInt(userScore);

if(intScore == 0) {

response.sendRedirect("/ServletSnakeGame/scoreboard");

}

else {

UserScore userscore = new UserScore(userName, intScore);

SnakeDAO snakedao = new SnakeDAO();

snakedao.addScore(userscore);

userscore = new UserScore();

response.sendRedirect("/ServletSnakeGame/scoreboard");

}

// System.out.print(userName);

// System.out.print(userScore);

// RequestDispatcher dispatcher = getServletContext().getRequestDispatcher(jsp);

// dispatcher.forward(request, response);

// make this not repost all the time..

}

protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {

doGet(request, response);

}

}

Data Access Objects (DAO)

 

package snake.model.dao;

import java.sql.Connection;

import java.sql.DriverManager;

import java.sql.ResultSet;

import java.sql.Statement;

public class DataAccessObject {

/**

* Antaa tietokantayhteyden

*

* @return connection - tietokantayhteys

*/

protected static Connection getConnection() {

Connection connection = null;

// Alkumääritykset

String username = "";

// dbkäyttäjätunnuksesi on tässä a-alkuinen opiskelijanumerosi

String password = "";

String url = "jdbc:mysql://localhost:3306/a1704571";

// tietokantasi nimi on tässä a-alkuinen opiskelijanumerosi

try {

// Ladataan ajuri

Class.forName("org.mariadb.jdbc.Driver").newInstance();

// Avataan yhteys connection-nimiseen muuttujaan

connection = DriverManager.getConnection(url, username, password);

} catch (Exception e) {

throw new RuntimeException(e);

}

return connection;

}

/**

* Sulkee Statementin ja Connectionin

*

* @param SQL-statement

* @param Tietokantayhteys

*/

protected static void close(Statement stmt, Connection connection) {

close(null, stmt, connection);

}

/**

* Sulkee ResultSetin, Statementin ja Connectionin

*/

protected static void close(ResultSet rs, Statement stmt, Connection conn) {

try {

if (rs != null) { // Suljetaan rs (palautettu tulostaulu), mikäli

// olemassa

rs.close();

}

if (stmt != null) { // Suljetaan stmt (SQL-statement), mikäli

// olemassa

stmt.close();

}

if (conn != null) { // Suljetaan conn (yhteys), mikäli olemassa

conn.close();

}

} catch (Exception e) {

throw new RuntimeException(e);

}

}

}

SNAKEDAO 

The snakedao was used to execute the sql statements after calling the basic data access objects.

package snake.model.dao;

import java.util.ArrayList;

import snakeuser.model.*;

import java.sql.Connection;

import java.sql.PreparedStatement;

import java.sql.ResultSet;

import java.sql.SQLException;

public class SnakeDAO extends DataAccessObject{

public void addScore(UserScore userscore) {

Connection conn = null;

PreparedStatement insertStmt = null;

try {

conn = getConnection();

String sqlInsert = "INSERT INTO snakepoints(username, points) VALUES(?,?)";

insertStmt = conn.prepareStatement(sqlInsert);

insertStmt.setString(1, userscore.getuserName());

insertStmt.setInt(2, userscore.getScore());

insertStmt.executeUpdate();

}catch(SQLException e) {

throw new RuntimeException(e);

}finally {

close(insertStmt, conn);

}

}

public ArrayList <UserScore> findAll(){

Connection conn = null;

PreparedStatement stmt = null;

ResultSet rs = null;

ArrayList <UserScore> scorelist = new ArrayList<UserScore>();

UserScore userscore = null;

try {

conn = getConnection();

String sqlSelect = "SELECT username, points FROM snakepoints ORDER BY points desc";

stmt = conn.prepareStatement(sqlSelect);

rs = stmt.executeQuery();

while (rs.next()) {

userscore = readUser(rs);

scorelist.add(userscore);

}

}catch(SQLException e) {

throw new RuntimeException(e);

}finally {

close(rs, stmt, conn);

}

return scorelist;

}

private UserScore readUser(ResultSet rs) {

try {

String name = rs.getString("username");

int score = rs.getInt("points");

return new UserScore(name, score);

}catch (SQLException e) {

throw new RuntimeException(e);

}

}

}

Leaderboard 

The leaderboard page used some bootstrap to make my table look a little fancier otherwise the page was just some basic hmtl and css elements put together to create a simple black and white page with a table that lists all usernames and their corresponding scores from the desired table in the database. The query ranks all the scores by descending value so the first result is always the highest score.

snake3

I chose not to accept null values in to my database. If the user tries to jump with a null value to the leaderboard page the page just redirects the user to this page without submitting any scores. 

I used this tutorial to write the actual game. Changed some variables and had my game have the ability to alter snake color (tutorial)

Sources: 

  • https://www.freecodecamp.org/news/think-like-a-programmer-how-to-build-snake-using-only-javascript-html-and-css-7b1479c3339e/
  • https://stackoverflow.com/questions/4803906/reading-a-jsp-variable-from-javascript
  • https://www.w3schools.com/jsref/met_win_confirm.asp