Skip to content

Commit

Permalink
making high score code work locally when not online.
Browse files Browse the repository at this point in the history
  • Loading branch information
aschearer committed Dec 29, 2008
1 parent fbc4a3c commit bd24ba8
Show file tree
Hide file tree
Showing 15 changed files with 980 additions and 43 deletions.
Empty file added res/states/highscore/scores.csv
Empty file.
52 changes: 52 additions & 0 deletions script/batch.php
@@ -0,0 +1,52 @@
<?php
/** Read in a CSV file and save the rows. */
// read CSV data from POST.
$scores = @$_POST['scores'];

/* Replace this w/ real information. */
$dsn = 'mysql:dbname=[dbname];host=[dbhost]';
$user = '[dbuser]';
$pass = '[dbpass]';

if (!isset($scores)) {
echo "failure";
exit;
}

try {
$dbh = new PDO($dsn, $user, $pass);
} catch (PDOException $e) {
echo "failure";
exit;
}

// TODO start transaction
$q = 'INSERT INTO `scores` (clear, name, score) VALUES (?, ?, ?)';
$stmt = $dbh->prepare($q);

// Get a file pointer to the score data.
$fp = fopen('php://memory', 'r+');
fputs($fp, $scores);
rewind($fp);

try {
$dbh->beginTransaction();
while (($score = fgetcsv($fp, 1000, ',')) !== FALSE) {
$stmt->bindParam(1, $score[2], PDO::PARAM_INT);
$stmt->bindParam(2, $score[0], PDO::PARAM_STR);
$stmt->bindParam(3, $score[1], PDO::PARAM_INT);
if (!$stmt->execute()) {
// TODO rollback transaction
echo "failure";
exit;
}
}
$dbh->commit();
} catch (Exception $e) {
$dbh->rollBack();
echo "failure"; // failed somewhere along the way
exit;
}

echo "success";
?>
68 changes: 68 additions & 0 deletions src/com/shade/score/BatchWriter.java
@@ -0,0 +1,68 @@
package com.shade.score;

import java.io.BufferedReader;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.net.URL;
import java.net.URLConnection;
import java.net.URLEncoder;
import java.util.Scanner;

import org.newdawn.slick.util.ResourceLoader;

/**
* Post all of the scores in a csv file to a server.
*
* @author Alexander Schearer <aschearer@gmail.com>
*/
public class BatchWriter {

private static final String NEWLINE = "\n";
private static final String SERVER = "http://anotherearlymorning.com/games/shade/batch.php";

private String path;

public BatchWriter(String path) {
this.path = path;
}

public boolean write() {
try {
String scores = collectScores();
String content = "scores=" + URLEncoder.encode(scores, "US-ASCII");
URL url = new URL(SERVER);
URLConnection c = url.openConnection();
c.setConnectTimeout(2000);
c.setDoOutput(true);
OutputStreamWriter o = new OutputStreamWriter(c.getOutputStream());
// write the content
o.write(content);
o.flush();
o.close();
// read response and check for success
BufferedReader i = new BufferedReader(new InputStreamReader(c
.getInputStream()));
String response = i.readLine();
return response.equals("success");

} catch (Exception e) {
return false;
}
}

private String collectScores() {
StringBuilder builder = new StringBuilder();
Scanner reader = getScanner();
while (reader.hasNextLine()) {
builder.append(reader.nextLine());
builder.append(NEWLINE);
}
return builder.toString();
}

private Scanner getScanner() {
InputStream stream = ResourceLoader.getResourceAsStream(path);
return new Scanner(stream);
}
}
30 changes: 30 additions & 0 deletions src/com/shade/score/FailSafeHighScoreReader.java
@@ -0,0 +1,30 @@
package com.shade.score;

/**
* Reader which will fall back to the local high score list if it cannot connect
* to the server.
*
* @author Alexander Schearer <aschearer@gmail.com>
*/
public class FailSafeHighScoreReader implements HighScoreReader {

private static final String FILE = "states/highscore/scores.csv";
private static final String SERVER = "http://anotherearlymorning.com/games/shade/board.php";

private LocalHighScoreReader localReader;
private RemoteHighScoreReader remoteReader;

public FailSafeHighScoreReader() {
localReader = new LocalHighScoreReader(FILE);
remoteReader = new RemoteHighScoreReader(SERVER);
}

public String[][] getScores(int limit) {
String[][] scores = remoteReader.getScores(limit);
if (scores == null) {
scores = localReader.getScores(limit);
}
return scores;
}

}
63 changes: 63 additions & 0 deletions src/com/shade/score/FailSafeHighScoreWriter.java
@@ -0,0 +1,63 @@
package com.shade.score;

import java.io.FileWriter;
import java.io.IOException;
import java.net.URL;

import org.newdawn.slick.util.ResourceLoader;

/**
* Write high scores to a remote server or locally if you cannot connect to the
* server.
*
* Try to write current score to server
* If failed then write locally, exit
* If successful try to write each local score to server, continue
* If failed then quit, exit
* If successful then remove from local file, continue
*
* @author Alexander Schearer <aschearer@gmail.com>
*/
public class FailSafeHighScoreWriter implements HighScoreWriter {

private static final String FILE = "states/highscore/scores.csv";
private static final String SERVER = "http://anotherearlymorning.com/games/shade/post.php";

private LocalHighScoreWriter localWriter;
private RemoteHighScoreWriter remoteWriter;
private BatchWriter batchWriter;

public FailSafeHighScoreWriter() {
localWriter = new LocalHighScoreWriter(FILE);
remoteWriter = new RemoteHighScoreWriter(SERVER);
batchWriter = new BatchWriter(FILE);
}

public boolean write(String name, int score, boolean clear) {
// try to write remotely
if (remoteWriter.write(name, score, clear)) {
// try to write past local scores to server
if (batchWriter.write()) {
// clear the file
clearFile(FILE);
}
// else do nothing, they will get written later
} else {
// can't connect to server, write locally
return localWriter.write(name, score, clear);
}
// wrote current score successfully
return true;
}

private void clearFile(String f) {
try {
URL u = ResourceLoader.getResource(f);
FileWriter w = new FileWriter(u.getPath());
w.flush();
} catch (IOException e) {
e.printStackTrace();
}
}

}
4 changes: 1 addition & 3 deletions src/com/shade/score/HighScoreReader.java
@@ -1,7 +1,5 @@
package com.shade.score;

import org.newdawn.slick.SlickException;

public interface HighScoreReader {

/**
Expand All @@ -10,5 +8,5 @@ public interface HighScoreReader {
* @param limit Return this many, set to zero to return all.
* @return
*/
public String[][] getScores(int limit) throws SlickException;
public String[][] getScores(int limit);
}
4 changes: 1 addition & 3 deletions src/com/shade/score/HighScoreWriter.java
@@ -1,8 +1,6 @@
package com.shade.score;

import org.newdawn.slick.SlickException;

public interface HighScoreWriter {

public boolean write(String name, int score, boolean clear) throws SlickException;
public boolean write(String name, int score, boolean clear);
}
76 changes: 76 additions & 0 deletions src/com/shade/score/LocalHighScoreReader.java
@@ -0,0 +1,76 @@
package com.shade.score;

import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.util.Collections;
import java.util.Comparator;
import java.util.LinkedList;

import org.newdawn.slick.util.ResourceLoader;

import com.shade.util.CsvReader;

/**
* Read high scores from a csv file located in the jar.
*
* This is useful if the remote server cannot be reached.
*
* @author Alexander Schearer <aschearer@gmail.com>
*/
public class LocalHighScoreReader implements HighScoreReader {

private static final int NAME = 0;
private static final int SCORE = 1;
private static final int CLEAR = 2;

private CsvReader reader;

public LocalHighScoreReader(String path) {
InputStream stream = ResourceLoader.getResourceAsStream(path);
InputStreamReader input = new InputStreamReader(stream);
reader = new CsvReader(input);
}

/**
* Returns all the scores if zero is passed.
*/
public String[][] getScores(int limit) {
LinkedList<String[]> rows = new LinkedList<String[]>();
try {
while (reader.readRecord()) {
String[] row = new String[3];
row[NAME] = reader.get(NAME);
row[SCORE] = reader.get(SCORE);
row[CLEAR] = reader.get(CLEAR);
rows.add(row);
}
} catch (IOException e) {
e.printStackTrace();
}

Collections.sort(rows, new Comparator<String[]>() {

public int compare(String[] s1, String[] s2) {
return s1[SCORE].compareTo(s2[SCORE]);
}

});

return firstN(rows, limit);
}

private String[][] firstN(LinkedList<String[]> rows, int limit) {
limit = (limit == 0) ? rows.size() : limit;
int size = (rows.size() > limit) ? limit : rows.size();
String[][] n = new String[size][3];

for (int i = 0; i < size; i++) {
n[i][NAME] = rows.get(i)[NAME];
n[i][SCORE] = rows.get(i)[SCORE];
n[i][CLEAR] = rows.get(i)[CLEAR];
}
return n;
}

}
49 changes: 49 additions & 0 deletions src/com/shade/score/LocalHighScoreWriter.java
@@ -0,0 +1,49 @@
package com.shade.score;

import java.io.FileWriter;
import java.io.IOException;
import java.net.URL;

import org.newdawn.slick.util.ResourceLoader;

import com.shade.util.CsvWriter;

public class LocalHighScoreWriter implements HighScoreWriter {

private static final int NAME = 0;
private static final int SCORE = 1;
private static final int CLEAR = 2;

private static final char COMMA = ',';
private CsvWriter writer;

public LocalHighScoreWriter(String path) {
try {
URL url = ResourceLoader.getResource(path);
FileWriter stream = new FileWriter(url.getPath(), true);
writer = new CsvWriter(stream, COMMA);
} catch (IOException e) {
e.printStackTrace();
}
}

public boolean write(String name, int score, boolean clear) {
String[] row = new String[3];
row[NAME] = name;
row[SCORE] = score + "";
row[CLEAR] = (clear) ? "1" : "0";
return write(row[NAME], row[SCORE], row[CLEAR]);
}

protected boolean write(String name, String score, String clear) {
String[] row = new String[] { name, score, clear };
try {
writer.writeRecord(row);
writer.flush();
} catch (IOException e) {
return false;
}
return true;
}

}

0 comments on commit bd24ba8

Please sign in to comment.