Last active
August 29, 2015 14:24
-
-
Save pschichtel/ba77e9c70c1c53a8ff11 to your computer and use it in GitHub Desktop.
javac ShellPong.java && java -cp . ShellPong; rm ShellPong*.class
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
public class ShellPong { | |
private static final int width = 80; | |
private static final int height = 24; | |
private static final char CORNER = '+'; | |
private static final char H_WALL = '-'; | |
private static final char V_WALL = '|'; | |
private static final char PADDLE = '#'; | |
private static final char BALL = 'O'; | |
private static final char BLANK = ' '; | |
private static final int GOAL = 3; | |
public static void main(String[] args) throws Exception { | |
final char[][] buf = new char[height][width]; | |
Ball b = new Ball(); | |
b.x = width / 2; | |
b.y = height / 2; | |
Paddle p1 = new Paddle(); | |
p1.x = 4; | |
p1.y = height / 2 - p1.height / 2; | |
Paddle p2 = new Paddle(); | |
p2.x = -5; | |
p2.y = height / 2 - p2.height / 2; | |
int p1Score = 0; | |
int p2Score = 0; | |
boolean ballMissed = false; | |
while (p1Score < GOAL && p2Score < GOAL) { | |
if (ballMissed) { | |
b.x = width / 2; | |
b.y = height / 2; | |
b.dx = Math.random() > .5 ? 1 : -1; | |
b.dy = Math.random() > .5 ? 1 : -1; | |
} | |
int yp1 = 0; | |
int yp2 = 0; | |
toggleRawInput(); | |
while (System.in.available() > 0) { | |
final int c = System.in.read(); | |
switch (c) { | |
case 'w': | |
yp1 = -1; | |
break; | |
case 's': | |
yp1 = 1; | |
break; | |
case 'o': | |
yp2 = -1; | |
break; | |
case 'l': | |
yp2 = 1; | |
break; | |
default: | |
System.out.println("" + c); | |
} | |
} | |
toggleRawInput(); | |
System.out.println("Player 1: " + p1Score + " - Player 2: " + p2Score); | |
clear(buf); | |
drawFrame(buf); | |
updatePaddle(p1, yp1); | |
drawPaddle(p1, buf); | |
updatePaddle(p2, yp2); | |
drawPaddle(p2, buf); | |
ballMissed = !updateBall(b, buf); | |
drawBall(b, buf); | |
draw(buf); | |
sleep(); | |
if (ballMissed) { | |
if (b.x < p1.x) { | |
p2Score++; | |
} else { | |
p1Score++; | |
} | |
} | |
} | |
System.out.println("Player " + (p1Score == GOAL ? "1" : "2") + " won!"); | |
} | |
private static void updatePaddle(Paddle p, int dy) { | |
int ny = p.y + dy; | |
if (ny == 0) { | |
return; | |
} | |
if (ny + height == heightBound(-1)) { | |
return; | |
} | |
p.y = ny; | |
} | |
private static void drawPaddle(Paddle p, char[][] buf) { | |
drawVerticalLine(buf, PADDLE, p.x, p.y, p.y + p.height); | |
} | |
public static boolean updateBall(Ball b, char[][] buf) { | |
int nx = b.x + b.dx; | |
int ny = b.y + b.dy; | |
if (nx == b.x && ny == b.y) { | |
return true; | |
} | |
final char nc = get(buf, nx, ny); | |
if (nc == V_WALL) { | |
return false; | |
} | |
if (nc == H_WALL) { | |
ny = b.y; | |
b.dy *= -1; | |
ny += b.dy; | |
} | |
if (nc == PADDLE) { | |
nx = b.x; | |
b.dx *= -1; | |
nx += b.dx; | |
} | |
b.x = nx; | |
b.y = ny; | |
return true; | |
} | |
private static void drawBall(Ball b, char[][] buf) { | |
drawDot(buf, BALL, b.x, b.y); | |
} | |
private static void drawFrame(char[][] buf) { | |
drawDot(buf, CORNER, 0, 0); | |
drawDot(buf, CORNER, -1, 0); | |
drawDot(buf, CORNER, 0, -1); | |
drawDot(buf, CORNER, -1, -1); | |
drawHorizontalLine(buf, H_WALL, 1, 0, -2); | |
drawHorizontalLine(buf, H_WALL, 1, -1, -2); | |
drawVerticalLine(buf, V_WALL, 0, 1, -2); | |
drawVerticalLine(buf, V_WALL, -1, 1, -2); | |
} | |
private static int widthBound(int x) { | |
return mod(width + x, width); | |
} | |
private static int heightBound(int y) { | |
return mod(height + y, height); | |
} | |
private static void clear(char[][] buf) { | |
for (int x = 0; x < width; ++x) { | |
for (int y = 0; y < height; ++y) { | |
buf[y][x] = BLANK; | |
} | |
} | |
} | |
private static void draw(char[][] buf) { | |
for (char[] chars : buf) { | |
System.out.println(chars); | |
} | |
} | |
private static void drawHorizontalLine(char[][] buf, char c, int x, int y, int x2) { | |
final char[] line = buf[heightBound(y)]; | |
x = widthBound(x); | |
x2 = widthBound(x2); | |
final int min = Math.min(x, x2); | |
final int max = Math.max(x, x2); | |
for (int i = min; i <= max; ++i) { | |
line[i] = c; | |
} | |
} | |
private static void drawVerticalLine(char[][] buf, char c, int x, int y, int y2) { | |
x = widthBound(x); | |
y = heightBound(y); | |
y2 = heightBound(y2); | |
final int min = Math.min(y, y2); | |
final int max = Math.max(y, y2); | |
for (int i = min; i <= max; ++i) { | |
buf[i][x] = c; | |
} | |
} | |
private static void drawDot(char[][] buf, char c, int x, int y) { | |
buf[heightBound(y)][widthBound(x)] = c; | |
} | |
private static char get(char[][] buf, int x, int y) { | |
return buf[heightBound(y)][widthBound(x)]; | |
} | |
private static int mod(int a, int b) { | |
return ((a % b) + b) % b; | |
} | |
private static void sleep() | |
{ | |
try { | |
Thread.sleep(100); | |
} catch (InterruptedException ignored) {} | |
} | |
private static boolean isRaw = false; | |
private static final String[] RAW_INPUT_COMMAND = {"/bin/sh", "-c", ""}; | |
private static void toggleRawInput() throws Exception { | |
RAW_INPUT_COMMAND[RAW_INPUT_COMMAND.length - 1] = "stty " + (isRaw ? "sane" : "raw") + " </dev/tty"; | |
isRaw = !isRaw; | |
Runtime.getRuntime().exec(RAW_INPUT_COMMAND).waitFor(); | |
} | |
private static class Ball { | |
public int x = 0; | |
public int y = 0; | |
public int dx = 1; | |
public int dy = 1; | |
} | |
private static class Paddle { | |
public int x = 0; | |
public int y = 0; | |
public int height = 5; | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment