Skip to content

Commit

Permalink
Final Fall 2018 version
Browse files Browse the repository at this point in the history
  • Loading branch information
cgokmen committed Jan 16, 2019
1 parent 9c3267e commit c6856bc
Show file tree
Hide file tree
Showing 54 changed files with 2,554 additions and 466 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -18,22 +18,26 @@

package com.cemgokmen.particles.algorithms;

import com.cemgokmen.particles.util.RandomSelector;
import com.cemgokmen.particles.capabilities.*;
import com.cemgokmen.particles.util.Utils;
import com.cemgokmen.particles.models.Particle;
import com.cemgokmen.particles.models.ParticleGrid;
import com.cemgokmen.particles.models.amoebot.AmoebotGrid;
import com.cemgokmen.particles.models.amoebot.AmoebotParticle;
import com.cemgokmen.particles.models.amoebot.specializedparticles.DirectedAmoebotParticle;
import com.google.common.collect.ImmutableList;
import javafx.beans.property.DoubleProperty;
import javafx.beans.property.SimpleDoubleProperty;

import java.util.List;

public class AlignmentAlgorithm extends CompressionAlgorithm {
public class AlignmentAlgorithm extends ParticleAlgorithm {
public static final double DEFAULT_ROTATION_BIAS = 20.0;
public static final double DEFAULT_TRANSLATION_BIAS = 1.0;
public static final double DEFAULT_FORWARD_BIAS = 1.1;
public static final double DEFAULT_LAMBDA = 4.0;

public static final List<Class<? extends ParticleCapability>> requiredCapabilities = ImmutableList.of(
MovementCapable.class, NeighborDetectionCapable.class, UniformRandomDirectionCapable.class, SpinCapable.class, WrappedNormalRandomDirectionCapable.class);

protected final DoubleProperty rotationBias = new SimpleDoubleProperty();
protected final DoubleProperty translationBias = new SimpleDoubleProperty();
Expand Down Expand Up @@ -87,62 +91,61 @@ public AlignmentAlgorithm() {

@Override
public void onParticleActivation(Particle p) {
if (!(p instanceof DirectedAmoebotParticle)) {
throw new RuntimeException("This particle type is not compatible with AlignmentAlgorithm.");
}
double spinProbability = 0.1;

DirectedAmoebotParticle particle = (DirectedAmoebotParticle) p;
// Check if we're about to hit the wall
/* ParticleGrid.Direction faceDir = ((SpinCapable) p).getDirection();
if (!((NeighborDetectionCapable) p).isDirectionInBounds(faceDir)) {
spinProbability = 0.5;
} */

if (Utils.randomDouble() <= 0.5) {
if (Utils.randomDouble() <= spinProbability) {
// With one half probability, we rotate
ParticleGrid.Direction randomDirection = particle.getRandomDirection();
ParticleGrid.Direction randomDirection = ((UniformRandomDirectionCapable) p).getUniformRandomDirection();

double moveProbability = this.getRotateMoveProbability(particle, randomDirection);
double moveProbability = this.getRotateMoveProbability(p, randomDirection);
if (Utils.randomDouble() > moveProbability) {
return;
}

particle.setDirection(randomDirection);
((SpinCapable) p).setDirection(randomDirection);
} else {
// With the rest probability, we translate

// Pick a random direction using the correct weights
RandomSelector<ParticleGrid.Direction> selector = RandomSelector.weighted(particle.compass.getDirections(), direction -> {
double angle = particle.compass.getAngleBetweenDirections(direction, particle.getDirection());
return Math.pow(this.getForwardBias(), normalizeDotProduct(Math.cos(angle)));
});

ParticleGrid.Direction randomDirection = selector.next(Utils.random);
ParticleGrid.Direction currentDirection = ((SpinCapable) p).getDirection();
ParticleGrid.Direction randomDirection = ((WrappedNormalRandomDirectionCapable) p).getWrappedNormalRandomDirection(currentDirection, this.getForwardBias());

// Run move validation
if (!this.isMoveValid(particle, randomDirection)) {
if (!((MovementCapable) p).isDirectionWithinBounds(randomDirection)) {
return;
}

double moveProbability = this.getTranslateMoveProbability(particle, randomDirection);
/*if (false && !RuleUtils.isMoveValidCompressionMove(particle, randomDirection, false, true)) {
return;
}*/

double moveProbability = this.getTranslateMoveProbability(p, randomDirection);
if (Utils.randomDouble() > moveProbability) {
return;
}

// Now make the move
try {
particle.move(randomDirection, this.isSwapsAllowed(), this.isNonSwapsAllowed());
//System.out.println("Moved.");
} catch (Exception ignored) {

}
((MovementCapable) p).move(randomDirection);
} catch (Exception ignored){}
}
}

@Override
public boolean isParticleAllowed(Particle p) {
return p instanceof DirectedAmoebotParticle;
public List<Class<? extends ParticleCapability>> getRequiredCapabilities() {
return requiredCapabilities;
}

private double getRotateMoveProbability(DirectedAmoebotParticle p, ParticleGrid.Direction inDirection) {
List<Particle> neighbors = p.getNeighborParticles(false, null);
private double getRotateMoveProbability(Particle p, ParticleGrid.Direction inDirection) {
List<Particle> neighbors = ((NeighborDetectionCapable) p).getNeighborParticles(false, null);

double sumDotProducts = getDotProductSum(neighbors, p.getDirection());
double sumDotProducts = getDotProductSum(neighbors, ((SpinCapable) p).getDirection());
double newSumDotProducts = getDotProductSum(neighbors, inDirection);

return Math.pow(this.getRotationBias(), newSumDotProducts - sumDotProducts);
Expand All @@ -152,40 +155,34 @@ private static double getDotProductSum(List<Particle> particles, ParticleGrid.Di
double sumDotProducts = 0;

for (Particle nbrAnonymous : particles) {
DirectedAmoebotParticle nbr = (DirectedAmoebotParticle) nbrAnonymous;
sumDotProducts += normalizeDotProduct(Math.cos(nbr.compass.getAngleBetweenDirections(withDirection, nbr.getDirection())));
SpinCapable nbr = (SpinCapable) nbrAnonymous;
sumDotProducts += normalizeDotProduct(Math.cos(nbr.getCompass().getAngleBetweenDirections(withDirection, nbr.getDirection())));
}

return sumDotProducts;
}

private double getTranslateMoveProbability(DirectedAmoebotParticle p, ParticleGrid.Direction inDirection) {
AmoebotGrid.AmoebotCompass compass = (AmoebotGrid.AmoebotCompass) p.compass;
ParticleGrid.Direction particleDirection = p.getDirection();
private double getTranslateMoveProbability(Particle p, ParticleGrid.Direction inDirection) {
ParticleGrid.Direction particleDirection = ((SpinCapable) p).getDirection();

List<Particle> currentNeighbors = p.getNeighborParticles(false, null);
List<Particle> futureNeighbors = p.getAdjacentPositionNeighborParticles(inDirection, false, particle -> particle
List<Particle> currentNeighbors = ((NeighborDetectionCapable) p).getNeighborParticles(false, null);
List<Particle> futureNeighbors = ((NeighborDetectionCapable) p).getAdjacentPositionNeighborParticles(inDirection, false, particle -> particle
!= p);

double translationBiasTerm = Math.pow(this.getTranslationBias(), futureNeighbors.size() - currentNeighbors.size());

double rotationBiasExponent = getDotProductSum(futureNeighbors, p.getDirection()) - getDotProductSum(currentNeighbors, p.getDirection());
double rotationBiasExponent = getDotProductSum(futureNeighbors, ((SpinCapable) p).getDirection()) - getDotProductSum(currentNeighbors, ((SpinCapable) p).getDirection());
double rotationBiasTerm = Math.pow(this.getRotationBias(), rotationBiasExponent);

return translationBiasTerm * rotationBiasTerm;
}

@Override
public double getCompressionBias(Particle p) {
throw new RuntimeException("getCompressionBias method should not be used in AlignmentAlgorithm.");
private static double normalizeDotProduct(double dot) {
return (dot + 1) / 2.0;
}

@Override
public double getMoveProbability(AmoebotParticle p, ParticleGrid.Direction inDirection) {
throw new RuntimeException("getMoveProbability method should not be used in AlignmentAlgorithm.");
}

private static double normalizeDotProduct(double dot) {
return (dot + 1) / 2.0;
public boolean isGridValid(ParticleGrid grid) {
return true;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
/*
* Particles, a self-organizing particle system simulator.
* Copyright (C) 2018 Cem Gokmen.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/

package com.cemgokmen.particles.algorithms;

import com.cemgokmen.particles.capabilities.*;
import com.cemgokmen.particles.models.Particle;
import com.cemgokmen.particles.models.ParticleGrid;
import com.cemgokmen.particles.models.amoebot.specializedparticles.DirectedAmoebotParticle;
import com.cemgokmen.particles.util.RandomSelector;
import com.cemgokmen.particles.util.Utils;
import com.google.common.collect.ImmutableList;

import java.util.List;

public class BobBotAlignmentAlgorithm extends ParticleAlgorithm {
// TODO: FIX THIS
public static final List<Class<? extends ParticleCapability>> requiredCapabilities = ImmutableList.of(
MovementCapable.class, NeighborDetectionCapable.class, UniformRandomDirectionCapable.class, SpinCapable.class);

@Override
public void onParticleActivation(Particle p) {
// Do the rejection here
DirectedAmoebotParticle particle = (DirectedAmoebotParticle) p;
double dotProdSum = particle.getCompass().getDirections().stream()
.mapToDouble(d -> {
boolean occupied = particle.getNeighborInDirection(d, 0, null) != null;
if (!occupied) return 0;

double angle = particle.getCompass().getAngleBetweenDirections(d, ((DirectedAmoebotParticle) p).getDirection());
return -1 * Math.cos(angle);
})
.sum();

double moveProb = 0.2 + 0.1 * dotProdSum;
if (Utils.randomDouble() > moveProb) return;

if (Utils.randomDouble() <= 0.5) {
// With one half probability, we rotate
ParticleGrid.Direction randomDirection = particle.getUniformRandomDirection();

particle.setDirection(randomDirection);
} else {
// With the rest probability, we translate

// Pick a random direction using the correct weights
RandomSelector<ParticleGrid.Direction> selector = RandomSelector.uniform(particle.getCompass().getDirections());

ParticleGrid.Direction randomDirection = selector.next(Utils.random);

// Run move validation
if (!particle.isDirectionWithinBounds(randomDirection)) {
return;
}

// Now make the move
try {
particle.move(randomDirection);
//particle.setDirection(particle.compass.shiftDirectionCounterclockwise(particle.getDirection(), 3));
//System.out.println("Moved.");
} catch (Exception ignored) {

}
}
}

@Override
public List<Class<? extends ParticleCapability>> getRequiredCapabilities() {
return requiredCapabilities;
}

@Override
public boolean isGridValid(ParticleGrid grid) {
return true;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -18,14 +18,23 @@

package com.cemgokmen.particles.algorithms;

import com.cemgokmen.particles.capabilities.MovementCapable;
import com.cemgokmen.particles.capabilities.NeighborDetectionCapable;
import com.cemgokmen.particles.capabilities.ParticleCapability;
import com.cemgokmen.particles.capabilities.UniformRandomDirectionCapable;
import com.cemgokmen.particles.models.Particle;
import com.cemgokmen.particles.models.ParticleGrid;
import com.cemgokmen.particles.models.amoebot.AmoebotParticle;
import com.cemgokmen.particles.util.Utils;
import com.google.common.collect.ImmutableList;
import javafx.beans.property.DoubleProperty;
import javafx.beans.property.SimpleDoubleProperty;

import java.util.List;

public class CompressionAlgorithm extends ParticleAlgorithm {
public static final List<Class<? extends ParticleCapability>> requiredCapabilities = ImmutableList.of(MovementCapable.class, UniformRandomDirectionCapable.class, NeighborDetectionCapable.class);

public static final double DEFAULT_LAMBDA = 4.0;

protected final DoubleProperty lambda = new SimpleDoubleProperty();
Expand All @@ -50,32 +59,26 @@ public CompressionAlgorithm() {
this(DEFAULT_LAMBDA);
}

public double getCompressionBias(Particle p) {
return this.getLambda();
}

@Override
public void onParticleActivation(Particle p) {
if (!(p instanceof AmoebotParticle)) {
throw new RuntimeException("This particle type is not compatible with CompressionAlgorithm.");
}

AmoebotParticle particle = (AmoebotParticle) p;
UniformRandomDirectionCapable particle = (UniformRandomDirectionCapable) p;

// Pick a random direction
ParticleGrid.Direction randomDirection = particle.getRandomDirection();
ParticleGrid.Direction randomDirection = particle.getUniformRandomDirection();

//System.out.println("Time for move validation");

// Run move validation
if (!this.isMoveValid(particle, randomDirection)) {
//System.out.println("Invalid move, returning");
return;
if (p instanceof AmoebotParticle) {
if (!RuleUtils.isMoveValidCompressionMove((AmoebotParticle) particle, randomDirection, false, true)) {
//System.out.println("Invalid move, returning");
return;
}
}

//System.out.println("Time for probability calculation");

double moveProbability = this.getMoveProbability(particle, randomDirection);
double moveProbability = this.getMoveProbability((NeighborDetectionCapable) p, randomDirection);

//System.out.printf("Move probability: %.2f%%. Now filtering.", moveProbability * 100);

Expand All @@ -87,52 +90,27 @@ public void onParticleActivation(Particle p) {

// Now make the move
try {
particle.move(randomDirection, this.isSwapsAllowed(), this.isNonSwapsAllowed());
((MovementCapable) particle).move(randomDirection);
//System.out.println("Moved.");
} catch (Exception ignored) {

}
}

public boolean isSwapsAllowed() {
return false;
}

public boolean isNonSwapsAllowed() {
return true;
}

@Override
public boolean isParticleAllowed(Particle p) {
return p instanceof AmoebotParticle;
public List<Class<? extends ParticleCapability>> getRequiredCapabilities() {
return requiredCapabilities;
}

@Override
public boolean isGridValid(ParticleGrid grid) {
return RuleUtils.checkParticleConnection(grid, particle -> true) && RuleUtils.checkParticleHoles(grid, particle -> true);
}

public double getMoveProbability(AmoebotParticle p, ParticleGrid.Direction inDirection) {
public double getMoveProbability(NeighborDetectionCapable p, ParticleGrid.Direction inDirection) {
int currentNeighbors = p.getNeighborParticles(false, null).size();
int futureNeighbors = p.getAdjacentPositionNeighborParticles(inDirection, false, particle -> particle
!= p).size();
return Math.pow(this.getCompressionBias(p), futureNeighbors - currentNeighbors);
return Math.pow(this.getLambda(), futureNeighbors - currentNeighbors);
}

public boolean isMoveValid(AmoebotParticle p, ParticleGrid.Direction d) {
if (!p.isDirectionWithinBounds(d)) {
return false;
}
boolean isOccupied = p.getNeighborInDirection(d, 0, null) != null;
if ((isOccupied && !this.isSwapsAllowed()) || (!isOccupied && !this.isNonSwapsAllowed())) {
return false;
}

boolean cond1 = p.getNeighborParticles(false, null).size() < 5;
boolean cond2 = RuleUtils.checkProperty1(p, d, null);
boolean cond3 = RuleUtils.checkProperty2(p, d, null);

return cond1 && (cond2 || cond3);
}

}
Loading

0 comments on commit c6856bc

Please sign in to comment.