Skip to content

Commit

Permalink
Zombicus example work in progress.
Browse files Browse the repository at this point in the history
  • Loading branch information
Stephen Blackheath committed Feb 12, 2015
1 parent ce1beea commit a5b4d85
Show file tree
Hide file tree
Showing 10 changed files with 406 additions and 199 deletions.
108 changes: 108 additions & 0 deletions book/zombicus/java/Animate.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,108 @@
import javax.imageio.*;
import javax.swing.*;
import java.io.IOException;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.ArrayList;
import java.util.List;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Point;
import java.awt.Toolkit;
import java.awt.image.*;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import sodium.*;

public class Animate extends JPanel {
private final double t0 = 0.0;
private final Dimension windowSize = new Dimension(600, 400);
private final BufferedImage sapienImgL;
private final BufferedImage sapienImgR;
private final BufferedImage zombicusImgL;
private final BufferedImage zombicusImgR;
private final BufferedImage coneImg;
private Cell<List<Character>> characters;
private CellSink<Double> clock;
private StreamSink<Unit> sTick;

public interface Animation {
public Cell<List<Character>> create(
double t0, Cell<Double> clock, Stream<Unit> sTick,
Dimension screenSize);
}

public Animate(Animation animation)
throws MalformedURLException, IOException
{
URL rootURL = new URL("file:.");
sapienImgL = ImageIO.read(new URL(rootURL, "../images/homo-sapien-left.png"));
sapienImgR = ImageIO.read(new URL(rootURL, "../images/homo-sapien-right.png"));
zombicusImgL = ImageIO.read(new URL(rootURL, "../images/homo-zombicus-left.png"));
zombicusImgR = ImageIO.read(new URL(rootURL, "../images/homo-zombicus-right.png"));
coneImg = ImageIO.read(new URL(rootURL, "../images/roadius-conium.png"));
Transaction.runVoid(() -> {
clock = new CellSink<Double>(t0);
sTick = new StreamSink<Unit>();
this.characters = animation.create(t0, clock, sTick, windowSize);
});
}

public void paintComponent(Graphics g) {
super.paintComponent(g);
Transaction.runVoid(() -> {
List<Character> chars = new ArrayList<Character>(characters.sample());
chars.sort((a, b) -> a.pos.y == b.pos.y ? 0 :
a.pos.y < b.pos.y ? -1 : 1);
for (Character c : chars) {
if (c.type == CharacterType.SAPIEN)
if (c.velocity.dx < 0)
g.drawImage(sapienImgL, c.pos.x-30, c.pos.y-73, null);
else
g.drawImage(sapienImgR, c.pos.x-23, c.pos.y-73, null);
else
if (c.velocity.dx < 0)
g.drawImage(zombicusImgL, c.pos.x-39, c.pos.y-73, null);
else
g.drawImage(zombicusImgR, c.pos.x-23, c.pos.y-73, null);
}
});
Toolkit.getDefaultToolkit().sync();
}

public Dimension getPreferredSize() {
return windowSize;
}

public static void animate(String title, Animation animation)
{
try {
JFrame frame = new JFrame(title);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
Animate view = new Animate(animation);
frame.setContentPane(view);
frame.pack();
frame.setVisible(true);
long t0 = System.currentTimeMillis();
long tLast = t0;
while (true) {
long t = System.currentTimeMillis();
long tIdeal = tLast + 20;
long toWait = tIdeal - t;
if (toWait > 0)
try { Thread.sleep(toWait); } catch (InterruptedException e) {}
view.clock.send((double)(tIdeal - t0) * 0.001);
view.sTick.send(Unit.UNIT);
view.repaint(0);
tLast = tIdeal;
}
}
catch (MalformedURLException e) {
e.printStackTrace();
}
catch (IOException e) {
e.printStackTrace();
}
}
}

50 changes: 50 additions & 0 deletions book/zombicus/java/BitableHomoSapien.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
import java.awt.Point;
import java.util.List;
import java.util.Optional;
import java.util.Random;
import sodium.*;

public class BitableHomoSapien {
private static class All {
All(Character character, double t) {
this.character = character;
this.t = t;
}
Character character;
double t;
}
public BitableHomoSapien(
World world,
int self,
double tInit,
Point posInit,
Cell<Double> clock,
Stream<Unit> sTick,
Stream<Integer> sBite,
Cell<List<Character>> others)
{
HomoSapien h = new HomoSapien(world, self, tInit, posInit, clock, sTick);
Stream<Integer> sBiteMe = sBite.filter(id -> id == self);
Cell<All> all = Cell.lift(
(ch, t) -> new All(ch, t),
h.character, clock);
Stream<HomoZombicus> sBecome = sBiteMe.snapshot(
all,
(id, a) -> new HomoZombicus(
world, self,
a.t, a.character.pos,
clock,
sTick, others
)
);
this.character = Cell.switchC(
sBecome.map(z -> z.character).hold(h.character)
);
this.sBite = Cell.switchS(
sBecome.map(z -> z.sBite).hold(new Stream<Integer>())
);
}
public final Cell<Character> character;
public final Stream<Integer> sBite;
}

119 changes: 0 additions & 119 deletions book/zombicus/java/Characters.java

This file was deleted.

80 changes: 43 additions & 37 deletions book/zombicus/java/HomoSapien.java
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import java.awt.Point;
import java.util.List;
import java.util.Optional;
import java.util.Random;
import sodium.*;
Expand All @@ -7,29 +8,16 @@ public class HomoSapien {
public static final double speed = 80.0;
public static final double step = 0.02;

static class State {
State(World world, Random rng, double t0, Point orig) {
this.t0 = t0;
this.orig = orig;
this.period = rng.nextDouble() * 1 + 0.5;
for (int i = 0; i < 10; i++) {
double angle = rng.nextDouble() * Math.PI * 2;
velocity = new Vector(Math.sin(angle), Math.cos(angle))
.mult(speed);
if (!world.hitsObstacle(positionAt(t0 + step*2)))
break;
}
private static class All {
All(State state, double t) {
this.state = state;
this.t = t;
}
double t0;
Point orig;
double period;
Vector velocity;
Point positionAt(double t) {
return velocity.mult(t - t0).add(orig);
}
}
final State state;
final double t;
};

public static Cell<Character> create(
public HomoSapien(
World world,
int self,
double tInit,
Expand All @@ -39,33 +27,51 @@ public static Cell<Character> create(
{
Random rng = new Random();
CellLoop<State> state = new CellLoop<>();
Cell<Tuple2<State, Double>> stateAndClock = Cell.lift(
(st, clk) -> new Tuple2<State, Double>(st, clk),
Cell<All> all = Cell.lift(
(st, clk) -> new All(st, clk),
state, clock);
Stream<Unit> sChange = Stream.filterOptional(
sTick.snapshot(stateAndClock,
(u, stclk) -> {
State st = stclk.a;
double t = stclk.b;
if (world.hitsObstacle(st.positionAt(t + step))
|| t - st.t0 >= st.period)
sTick.snapshot(all,
(u, a) -> {
if (world.hitsObstacle(a.state.positionAt(a.t + step))
|| a.t - a.state.t0 >= a.state.period)
return Optional.of(Unit.UNIT);
else
return Optional.<Unit>empty();
}));
state.loop(
sChange.snapshot(stateAndClock, (u, stclk) -> {
State st = stclk.a;
double t = stclk.b;
return new State(world, rng, t, st.positionAt(t));
sChange.snapshot(all, (u, a) -> {
return new State(world, rng, a.t, a.state.positionAt(a.t));
}).hold(new State(world, rng, tInit, posInit))
);
return stateAndClock.map(stclk -> {
State st = stclk.a;
double t = stclk.b;
character = all.map(a -> {
return new Character(self, CharacterType.SAPIEN,
st.positionAt(t), st.velocity);
a.state.positionAt(a.t), a.state.velocity);
});
}

public final Cell<Character> character;

private static class State {
State(World world, Random rng, double t0, Point orig) {
this.t0 = t0;
this.orig = orig;
this.period = rng.nextDouble() * 1 + 0.5;
for (int i = 0; i < 10; i++) {
double angle = rng.nextDouble() * Math.PI * 2;
velocity = new Vector(Math.sin(angle), Math.cos(angle))
.mult(speed);
if (!world.hitsObstacle(positionAt(t0 + step*2)))
break;
}
}
double t0;
Point orig;
double period;
Vector velocity;
Point positionAt(double t) {
return velocity.mult(t - t0).add(orig);
}
}
}

Loading

0 comments on commit a5b4d85

Please sign in to comment.