Skip to content

Instantly share code, notes, and snippets.

@hsanchez
Created September 26, 2012 21:49
Show Gist options
  • Save hsanchez/3790836 to your computer and use it in GitHub Desktop.
Save hsanchez/3790836 to your computer and use it in GitHub Desktop.
It allows us to get an optimal placement of "clusters of parts" on a grid using backtracking and incremental improvement ideas.
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Random;
public class ItemsPlacement {
// Area where we will placing parts
static class Area {
int x = 0;
int y = 0;
int w = 0;
int h = 0;
Cluster cluster = new Cluster();
@Override public String toString() {
return String.format("Area(x=%d, y=%d, w=%d, h=%d)", x, y, w, h);
}
}
static class Solution {
Area[] current = new Area[0];
}
// Part of a Robot
static class Part {
String name = null;
@Override public String toString() {
return String.format("Part(name=%s)", name == null ? "." : name);
}
}
// Clusters of parts
static class Cluster {
List<Part> parts = new ArrayList<Part>();
}
// Helper object that does not rely on Collections.shuffle functionality
static class Shuffler {
static Random random;
static long seed;
static {
seed = System.currentTimeMillis();
random = new Random(seed);
}
static int uniform(int N) {
return random.nextInt(N);
}
static void shuffle(Object[] a) {
final int N = a.length;
for(int i = 0; i < N; i++){
int r = i + uniform(N - i); // btw i and N - 1
Object temp = a[i];
a[i] = a[r];
a[r] = temp;
}
}
}
private static Cluster[] CLUSTERS = new Cluster[5];
static {
final Cluster ONE = new Cluster();
ONE.parts.add(new Part(){{name = "MICRO"; }}); // microcontroller
ONE.parts.add(new Part(){{name = "BPACK"; }}); // battery pack
final Cluster TWO = new Cluster();
TWO.parts.add(new Part(){{name = "SERVO"; }}); // servo
TWO.parts.add(new Part(){{name = "WHEEL"; }}); // wheel controlled by servo
final Cluster THREE = new Cluster();
// this cluster represent the two holes on the chassis to put wheels
THREE.parts.add(new Part(){{name = "WHEEL"; }});
THREE.parts.add(new Part(){{name = "WHEEL"; }});
final Cluster FOUR = new Cluster();
// cluster comprised of two sensors (either light or motion)
FOUR.parts.add(new Part(){{name = "SENSOR"; }});
FOUR.parts.add(new Part(){{name = "SENSOR"; }});
final Cluster FIVE = new Cluster();
// cluster comprised of one sensor (either light or motion)
FIVE.parts.add(new Part(){{name = "SENSOR"; }});
// set up available clusters.
CLUSTERS[0] = ONE;
CLUSTERS[1] = TWO;
CLUSTERS[2] = THREE;
CLUSTERS[3] = FOUR;
CLUSTERS[4] = FIVE;
}
private final int n;
private final int d;
private final List<Solution> solutions = new ArrayList<Solution>();
public ItemsPlacement(int n, int d) {
this.n = n;
this.d = d;
}
void admit(int[] q) {
final List<Area> area = evictSolution(q);
final Area[] src = area.toArray(new Area[area.size()]);
final Area[] dst = new Area[area.size()];
System.arraycopy(src, 0, dst, 0, src.length);
final Solution sol = new Solution();
sol.current = dst;
solutions.add(sol);
}
void enumerate() {
int[] grid = new int[n];
enumerate(grid, 0);
prepClusters();
}
void enumerate(int[] q, int r) {
int N = q.length;
if (r == N) { admit(q); } else {
for (int j = 0; j < N; j++) {
q[r] = j;
if (isConsistent(q, j, r)) { enumerate(q, r + 1); }
}
}
}
static int distance(Solution sol){
// this is a point to point distance
// if this does not work, then maybe we can calculate this dist wrt the center of the grid
int dist = 0;
Area pivot = sol.current[0];
for(int i = 1; i < sol.current.length; i++){
final Area each = sol.current[i];
final double pow = Math.pow(pivot.x - each.x, 2) + Math.pow(pivot.y - each.y, 2);
dist += Math.floor(Math.sqrt(pow));
pivot = each;
}
return dist;
}
static boolean less(Solution a, Solution b){
return distance(a) < distance(b);
}
static Solution findMin(List<Solution> solutions){
Solution min = null;
// Get an optimal one
for(Solution eachSolution : solutions){
if(min == null) { min = eachSolution; } else {
if(less(eachSolution, min)){
min = eachSolution;
}
}
}
return min;
}
void prepClusters(){
for(Solution each : solutions){
// feed the areas with randomly selected cluster
Shuffler.shuffle(CLUSTERS);
for(int i = 0; i < each.current.length; i++){
each.current[i].cluster = CLUSTERS[i];
}
}
}
Solution solve(){
// Enumerate feasible placements
enumerate();
// Get an optimal placement
return findMin(solutions);
}
/**
* @param q current cluster placement
* @param j column index
* @param r row index
* @return true if cluster placement q[n] does not conflict with other cluster placement q[0] through q[n-1]
*/
private static boolean isConsistent(int[] q, int j, int r) {
for (int i = 0; i < r; i++) {
if (q[i] == j) {
return false; // same column in the grid
}
if (q[i] == j + r - i) {
return false; // same major diagonal in the grid
}
if (q[i] == j - r + i) {
return false; // same minor diagonal in the grid
}
}
return true;
}
/**
* Print out N-by-N placement of areas from permutation q in ASCII.
*
* @param q cluster placement
*/
private List<Area> evictSolution(int[] q) {
final List<Area> areas = new ArrayList<Area>();
int N = q.length;
int X = 0;
int Y = 0;
for (int i = 0; i < N; i++) {
for (int j = 0; j < N; j++) {
if (q[i] == j) {
final Area area = new Area();
area.x = X;
area.y = Y;
area.w = d;
area.h = d;
areas.add(area);
String val = String.format("[%d,%d] ", area.x, area.y);
System.out.print(val);
} else {
System.out.print("[X] ");
}
X += d;
if (j + 1 == N) {
X = 0;
Y += d;
}
}
if (i + 1 == N) {
Y = 0;
}
System.out.println();
}
System.out.println();
return areas;
}
public static void main(String[] args) {
/**
* possible clusters are
* A: batterypack, microprocessor
* B: servo, batterpack, sensors
* C: etc.
*
* Clusters are formed based on user input. Users know---based on their experience assembling
* these things---what to include in these clusters of parts.
*/
int N = 5; // N-by-N grid
int D = 2; // Distance from point to point. Since this is a grid, we assume that width == height
final ItemsPlacement solver = new ItemsPlacement(N, D);
final Solution optimal = solver.solve();
System.out.println("Solution=>" + Arrays.toString(optimal.current));
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment