Skip to content

Commit

Permalink
Merge branch 'type_driven' - the Haskell-inspired Java
Browse files Browse the repository at this point in the history
implementation of RPS

Conflicts:
	.gitignore
	build.xml
	src/RockPaperScissors.java
	src/com/twoguys/rps/Game.java
	src/com/twoguys/rps/Player.java
	src/com/twoguys/rps/Throw.java
	test/com/twoguys/rps/GameTest.java
	test/com/twoguys/rps/ThrowTest.java
  • Loading branch information
youngnh committed Feb 7, 2010
2 parents 3c64f89 + 238e457 commit f0eeb78
Show file tree
Hide file tree
Showing 57 changed files with 1,928 additions and 52 deletions.
2 changes: 1 addition & 1 deletion .gitignore
@@ -1,2 +1,2 @@
build/*
dist/*
dist/*
6 changes: 5 additions & 1 deletion build.xml
Expand Up @@ -10,6 +10,9 @@

<target name="init">
<tstamp />
<mkdir dir="${src}" />
<mkdir dir="${test}" />
<mkdir dir="${lib}" />
<mkdir dir="${classes}" />
<mkdir dir="${test.classes}" />
<mkdir dir="${test.report}" />
Expand Down Expand Up @@ -43,9 +46,10 @@
<junit printsummary="on" haltonerror="true" haltonfailure="true">
<classpath refid="class.path" />
<batchtest todir="${test.report}">
<formatter type="plain" />
<formatter type="plain" usefile="false" />
<fileset dir="${test}">
<include name="**/*Test.java"/>
<exclude name="**/*AbstractTest.java"/>
</fileset>
</batchtest>
</junit>
Expand Down
13 changes: 13 additions & 0 deletions data/RockPaperScissorsTest/bestof_game.expected
@@ -0,0 +1,13 @@
Player 1 Name:
Player 2 Name:
[R]ock, [P]aper, or [S]cissors?
[R]ock, [P]aper, or [S]cissors?
[R]ock, [P]aper, or [S]cissors?
[R]ock, [P]aper, or [S]cissors?
[R]ock, [P]aper, or [S]cissors?
[R]ock, [P]aper, or [S]cissors?
[R]ock, [P]aper, or [S]cissors?
[R]ock, [P]aper, or [S]cissors?
[R]ock, [P]aper, or [S]cissors?
[R]ock, [P]aper, or [S]cissors?
Ben Wins!
12 changes: 12 additions & 0 deletions data/RockPaperScissorsTest/bestof_game.input
@@ -0,0 +1,12 @@
Nate
Ben
R
P
R
S
R
P
R
S
R
P
9 changes: 9 additions & 0 deletions data/RockPaperScissorsTest/firstto_game.expected
@@ -0,0 +1,9 @@
Player 1 Name:
Player 2 Name:
[R]ock, [P]aper, or [S]cissors?
[R]ock, [P]aper, or [S]cissors?
[R]ock, [P]aper, or [S]cissors?
[R]ock, [P]aper, or [S]cissors?
[R]ock, [P]aper, or [S]cissors?
[R]ock, [P]aper, or [S]cissors?
Ben Wins!
8 changes: 8 additions & 0 deletions data/RockPaperScissorsTest/firstto_game.input
@@ -0,0 +1,8 @@
Nate
Ben
R
P
R
P
R
P
5 changes: 5 additions & 0 deletions data/RockPaperScissorsTest/nate_wins.expected
@@ -0,0 +1,5 @@
Player 1 Name:
Player 2 Name:
[R]ock, [P]aper, or [S]cissors?
[R]ock, [P]aper, or [S]cissors?
Nate Wins!
4 changes: 4 additions & 0 deletions data/RockPaperScissorsTest/nate_wins.input
@@ -0,0 +1,4 @@
Nate
Ben
R
S
5 changes: 5 additions & 0 deletions data/RockPaperScissorsTest/noargs_game.expected
@@ -0,0 +1,5 @@
Player 1 Name:
Player 2 Name:
[R]ock, [P]aper, or [S]cissors?
[R]ock, [P]aper, or [S]cissors?
Ben Wins!
4 changes: 4 additions & 0 deletions data/RockPaperScissorsTest/noargs_game.input
@@ -0,0 +1,4 @@
Nate
Ben
R
P
15 changes: 15 additions & 0 deletions data/RockPaperScissorsTest/winby_game.expected
@@ -0,0 +1,15 @@
Player 1 Name:
Player 2 Name:
[R]ock, [P]aper, or [S]cissors?
[R]ock, [P]aper, or [S]cissors?
[R]ock, [P]aper, or [S]cissors?
[R]ock, [P]aper, or [S]cissors?
[R]ock, [P]aper, or [S]cissors?
[R]ock, [P]aper, or [S]cissors?
[R]ock, [P]aper, or [S]cissors?
[R]ock, [P]aper, or [S]cissors?
[R]ock, [P]aper, or [S]cissors?
[R]ock, [P]aper, or [S]cissors?
[R]ock, [P]aper, or [S]cissors?
[R]ock, [P]aper, or [S]cissors?
Ben Wins!
15 changes: 15 additions & 0 deletions data/RockPaperScissorsTest/winby_game.input
@@ -0,0 +1,15 @@
Nate
Ben
R
P
R
S
R
P
R
S
R
P
R
P

Binary file added lib/commons-io-1.4.jar
Binary file not shown.
Binary file added lib/hamcrest-library-1.1.jar
Binary file not shown.
54 changes: 46 additions & 8 deletions src/RockPaperScissors.java
@@ -1,18 +1,56 @@

import com.twoguys.rps.*;
import com.twoguys.util.*;
import java.io.*;
import java.util.*;

public class RockPaperScissors {

public static void main(String[] args) throws Exception {
Reader in = new InputStreamReader(System.in);
private LineNumberReader in;
private Writer out;

public static void main(String[] args) {
InputStreamReader stdin = new InputStreamReader(System.in);
LineNumberReader in = new LineNumberReader(stdin);
Writer out = new OutputStreamWriter(System.out);

RockPaperScissors rps = new RockPaperScissors(in, out);
rps.run(args);
}

public RockPaperScissors(LineNumberReader in, Writer out) {
this.in = in;
this.out = out;
}

public void run(String[] args) {
try {
Either<String, WinLogic> logicOrError = WinLogicFactory.create(args);

Player p1 = new InteractivePlayer(in, out, 1);
Player p2 = new InteractivePlayer(in, out, 2);
if(logicOrError.left() != null) {
out.write(logicOrError.left());
} else {
WinLogic logic = logicOrError.right();

Game game = new Game(p1, p2);
Player winner = game.play();
winner.notifyWinner();
PlayerPrompt prompt1 = new PlayerPrompt(in, out, 1);
PlayerPrompt prompt2 = new PlayerPrompt(in, out, 2);

Player player1 = prompt1.prompt();
Player player2 = prompt2.prompt();

AllThrows p1Throws = new AllThrows(new ThrowPrompt(in, out));
AllThrows p2Throws = new AllThrows(new ThrowPrompt(in, out));

Pair<Player, Iterator<Throw>> p1 = new Pair<Player, Iterator<Throw>>(player1, p1Throws);
Pair<Player, Iterator<Throw>> p2 = new Pair<Player, Iterator<Throw>>(player2, p2Throws);

Game game = new Game(logic, p1, p2);
Player winner = game.play();

out.write(winner.getName() + " Wins!");
}
} catch(Exception e) {
e.printStackTrace(new PrintWriter(out));
}
}

}
43 changes: 43 additions & 0 deletions src/com/twoguys/rps/AllThrows.java
@@ -0,0 +1,43 @@
package com.twoguys.rps;

import com.twoguys.util.*;
import java.text.*;
import java.util.*;

public class AllThrows implements Iterator<Throw> {

private Prompt<Throw> prompt;
private Throw next;

public AllThrows(Prompt<Throw> prompt) {
this.prompt = prompt;
}

@Override
public boolean hasNext() {
try {
next = prompt.prompt();
} catch(ParseException e) {
return false;
}
return true;
}

@Override
public Throw next() {
Throw result = next;
try {
if(next == null) {
result = prompt.prompt();
}
next = null;
return result;
} catch(Exception e) {
throw new RuntimeException(e);
}
}

@Override
public void remove() {
}
}
26 changes: 26 additions & 0 deletions src/com/twoguys/rps/BestOf.java
@@ -0,0 +1,26 @@
package com.twoguys.rps;

import com.twoguys.util.*;

public class BestOf implements WinLogic {

private int of;
private WinLogic impl;

public BestOf(int of) {
if(of <= 1 || of % 2 == 0) {
throw new IllegalArgumentException(of + " is not valid, must provide an odd number greater than 1");
}

this.of = of;
this.impl = new FirstTo(of / 2 + 1);
}

public Maybe<Player> determineWinner(Pair<Player, Integer> p1, Pair<Player, Integer> p2) {
return impl.determineWinner(p1, p2);
}

public int getOf() {
return of;
}
}
10 changes: 10 additions & 0 deletions src/com/twoguys/rps/FirstTo.java
@@ -0,0 +1,10 @@
package com.twoguys.rps;

import com.twoguys.util.*;

public class FirstTo extends WinBy {

public FirstTo(int to) {
super(to, 0);
}
}
48 changes: 39 additions & 9 deletions src/com/twoguys/rps/Game.java
@@ -1,20 +1,50 @@
package com.twoguys.rps;

import com.twoguys.util.*;
import java.util.*;

public class Game {

private Player p1;
private Player p2;
public static final Maybe<Player> NO_WINNER = new Nothing();

private WinLogic logic;
private Player player1;
private Player player2;
private int p1Score = 0;
private int p2Score = 0;
private Iterator<Throw> p1Throws;
private Iterator<Throw> p2Throws;

public Game(Player p1, Player p2) {
this.p1 = p1;
this.p2 = p2;
public Game(WinLogic logic, Pair<Player, Iterator<Throw>> player1, Pair<Player, Iterator<Throw>> player2) {
this.logic = logic;
this.player1 = player1.a;
this.player2 = player2.a;
this.p1Throws = player1.b;
this.p2Throws = player2.b;
}

public Player play() {
Throw p1Throw = p1.getThrow();
Throw p2Throw = p2.getThrow();
private Maybe<Player> getWinner() {
Pair<Player, Integer> p1 = new Pair<Player, Integer>(player1, p1Score);
Pair<Player, Integer> p2 = new Pair<Player, Integer>(player2, p2Score);

return p1Throw.beats(p2Throw) ? p1 : p2;
return logic.determineWinner(p1, p2);
}

public Player play() {
Maybe<Player> player = getWinner();
while(player.equals(NO_WINNER)) {
if(p1Throws.hasNext() && p2Throws.hasNext()) {
Throw t1 = p1Throws.next();
Throw t2 = p2Throws.next();
if(t1.beats(t2)) {
p1Score++;
} else if(t2.beats(t1)) {
p2Score++;
}
}
player = getWinner();
}
return player.value();
}

}
17 changes: 13 additions & 4 deletions src/com/twoguys/rps/Player.java
@@ -1,9 +1,18 @@
package com.twoguys.rps;

public interface Player {
public class Player {

public String getName();
public Throw getThrow();
public void notifyWinner();
private String name;

public Player(String name) {
this.name = name;
}

public String getName() {
return name;
}

public void setName(String name) {
this.name = name;
}
}
12 changes: 12 additions & 0 deletions src/com/twoguys/rps/PlayerPrompt.java
@@ -0,0 +1,12 @@
package com.twoguys.rps;

import com.twoguys.util.*;
import java.io.*;

public class PlayerPrompt extends Prompt<Player> {

public PlayerPrompt(LineNumberReader in, Writer out, int n) {
super(in, new Notify(out, "Player " + n + " Name: "), new com.twoguys.util.Reader<Player>(new ReadPlayer()));
}

}
13 changes: 13 additions & 0 deletions src/com/twoguys/rps/ReadPlayer.java
@@ -0,0 +1,13 @@
package com.twoguys.rps;

import com.twoguys.util.*;
import java.util.*;

public class ReadPlayer implements Read<Player> {

public List<Pair<Player, String>> read(String str) {
Player player = new Player(str);
Pair<Player, String> parsed = new Pair<Player, String>(player, "");
return Arrays.asList(parsed);
}
}

0 comments on commit f0eeb78

Please sign in to comment.