Skip to content

Instantly share code, notes, and snippets.

@sebastientromp
Created May 9, 2016 13:08
Show Gist options
  • Save sebastientromp/be521585e784080b4f115f566e066955 to your computer and use it in GitHub Desktop.
Save sebastientromp/be521585e784080b4f115f566e066955 to your computer and use it in GitHub Desktop.
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.Random;
import java.util.Scanner;
import java.util.Set;
/**
* Auto-generated code below aims at helping you parse the standard input
* according to the problem statement.
**/
class Player {
private static final int TIME_SAFETY = 80;
public static final int NUMBER_OF_ROWS = 12;
public static final int NUMBER_OF_COLUMNS = 6;
public static final int NUMBER_OF_ROTATIONS = 4;
public static final int GENOME_LENGTH = 4 * 2;
public static final int POPULATION_SIZE = 600;
public static final int TOURNAMENT_SIZE = 20;
public static final int NUMBER_OF_GENERATIONS = 5;
public static final float SURVIVAL_RATE = 0.1f;
private static final float MUTATION_RATE = 0.2f;
private static final float MUTATION_IMPACT = 1;
public static Random rnd;
// public static final float DANGER_MALUS = 10;
public static final float FUTURE_RISK_FACTOR = 1f;
// private static final float GRID_FILL_FACTOR = 0f;
private static final float SKULL_FILL_FACTOR = 1f;
private static final float GROUPING_FACTOR = 4f;
public static final int CARRY_OVER = 15;
public static final int CARRY_REPLICATION = 20;
public static long startTime = getSystemTime();
public static List<Genome> carriedOver = new ArrayList<>();
public static void main(String args[]) {
Scanner in = new Scanner(System.in);
if (rnd == null) {
rnd = new Random();
}
// game loop
while (true) {
startTime = getSystemTime();
Pair[] blocks = new Pair[8];
for (int i = 0; i < 8; i++) {
// color of the first block
char colorA = Character.forDigit(in.nextInt(), 10);
// color of the attached block
char colorB = Character.forDigit(in.nextInt(), 10);
blocks[i] = new Pair(colorA, colorB);
}
System.err
.println(getSystemTime() - startTime + " - Computation to decide where to put block " + blocks[0]);
// My grid. One line of the map ('.' = empty, '0' = skull block, '1'
// to '5' = colored block)
Grid myGrid = new Grid();
int currentRow = 0;
for (int i = 0; i < 12; i++) {
String row = in.next();
myGrid.addRow(NUMBER_OF_ROWS - currentRow - 1, row);
currentRow++;
}
// The opponent
for (int i = 0; i < 12; i++) {
String row = in.next();
}
execute(blocks, myGrid);
}
}
public static void execute(Pair[] blocks, Grid myGrid) {
// Compute the state of the grid - create groups mainly
myGrid.computeGroups();
System.err.println(getSystemTime() - startTime + " - Computed state. Groups are " + myGrid.groups);
System.err.println(getSystemTime() - startTime + " - Pairs are " + Arrays.toString(blocks));
System.err.println(myGrid);
// Create a population of genomes
List<Genome> population = buildInitialPopulation(blocks);
System.err.println(getSystemTime() - startTime + " - Built initial population");
// Perform genetic algorithm + selection
List<Genome> fittest = evolve(myGrid, population, blocks);
for (int i = 0; i < 10; i++) {
System.err.println(getSystemTime() - startTime + " - Genome " + i + ": " + fittest.get(i));
}
carryOver(fittest);
// "x": the column in which to drop your blocks
System.out.println(fittest.get(0).genes[0] + " " + fittest.get(0).genes[1]);
}
private static void carryOver(List<Genome> fittest) {
carriedOver = new ArrayList<>();
for (int i = 0; i < CARRY_OVER; i++) {
carriedOver.add(fittest.get(i));
}
}
private static List<Genome> evolve(Grid grid, List<Genome> population, Pair[] blocks) {
int currentGeneration = 1;
// System.err.println(getSystemTime() - startTime + " - Computing score
// for " + population.size() + " genomes ");
for (Genome genome : population) {
// System.err.println("\t" + (getSystemTime() - startTime) + " -
// Computing score for one genome");
int score = computeScore(grid, genome, blocks);
// System.err.println("\t\t" + (System.nanoTime() -
// startTime) + " - Computed genome score");
genome.score = score;
}
Collections.sort(population);
System.err.println(getSystemTime() - startTime + " - Computed initial score");
while (currentGeneration < NUMBER_OF_GENERATIONS && System.currentTimeMillis() - startTime < TIME_SAFETY) {
// System.err
// .println(getSystemTime() - startTime + " - Starting breeding for
// generation " + currentGeneration);
population = breed(population);
// System.err.println("\t" + (getSystemTime() - startTime) + " -
// Bred");
// Add a score to each genome
for (Genome genome : population) {
int score = computeScore(grid, genome, blocks);
genome.score = score;
}
Collections.sort(population);
System.err.println("\t" + (getSystemTime() - startTime) + " - Bred generation " + currentGeneration);
// System.err.println("\t" + (getSystemTime() - startTime) + " - Top
// Genome " + population.get(0));
// System.err.println("\t" + (getSystemTime() - startTime) + " -
// Computed score");
currentGeneration++;
}
return population;
}
// The meat of the processing
public static int computeScore(Grid grid, Genome genome, Pair[] blocks) {
int score = 0;
grid = grid.copy();
// Compute the score after each placement
// System.err.println("\tLooking at genome " + genome);
for (int i = 0; i < GENOME_LENGTH / 2; i++) {
// System.err.println("\t\t" + (getSystemTime() - startTime) + " -
// Computing score for gene");
// System.err.println("\tLooking at block " + blocks[i] + " and
// genes " + genome.genes[2 * i] + " "
// + genome.genes[2 * i + 1]);
try {
boolean valid = grid.addPair(blocks[i], genome.genes[2 * i], genome.genes[2 * i + 1]);
System.err.println("\t\t\t" + (getSystemTime() - startTime) + " - Added pair for " + genome);
System.err.println(grid);
System.err.println(grid.debug());
if (!valid) { return -1; }
}
catch (ArrayIndexOutOfBoundsException e) {
System.err.println(genome);
throw e;
}
// int filled = grid.filled();
// float gridFillFactor = Math.max(1, GRID_FILL_FACTOR * filled /
// (NUMBER_OF_ROWS * NUMBER_OF_COLUMNS));
// float skullFillFactor = Math.max(1, SKULL_FILL_FACTOR *
// grid.skulls());
int baseScore = grid.computeScore(genome, blocks);
int nuisancePoints = baseScore / 70;
int skullsDropped = nuisancePoints / 6;
// System.err.println("Dropped " + skullsDropped + " skulls at " + i
// + " with score " + baseScore);
// Only consider strong combos, unless we're losing
// if (skullsDropped == 0) {
// baseScore *= grid.skulls() * SKULL_FILL_FACTOR;
// }
// else {
// baseScore *= 2 * skullsDropped;
// }
// baseScore = Math.min(baseScore, 8000);
score += Math.max(0, 1 - FUTURE_RISK_FACTOR * i / GENOME_LENGTH) * baseScore;
// score += baseScore;
// System.err.println("\t\t\t" + (getSystemTime() - startTime) + " -
// New grid for " + blocks[i] + " and genes "
// + genome.genes[2 * i] + " " + genome.genes[2 * i + 1]);
// System.err.println("\t\t\tscore is " + score);
// System.err.println(grid);
genome.skullsDropped[i] = skullsDropped;
}
genome.finalGrid = grid;
return score;
}
private static List<Genome> breed(List<Genome> population) {
// Collections.sort(population);
// System.err.println("\t\t" + (System.nanoTime() - startTime)
// + " - Sorted population");
List<Genome> fittest = population.subList(0, (int) (population.size() * SURVIVAL_RATE));
// System.err.println("\t\t" + (System.nanoTime() - startTime)
// + " - Kept fittest individuals");
List<Genome> winners = new ArrayList<>(fittest);
while (winners.size() < POPULATION_SIZE) {
Genome parent1 = tournamentSelection(fittest);
Genome parent2 = tournamentSelection(fittest);
Genome child = crossOver(parent1, parent2);
if (child.isValid()) {
winners.add(child);
}
Genome mutated = child.copy();
mutate(mutated);
if (mutated.isValid()) {
winners.add(mutated);
}
}
return winners;
}
private static Genome crossOver(Genome parent1, Genome parent2) {
Genome child = new Genome();
for (int i = 0; i < GENOME_LENGTH; i++) {
child.genes[i] = Math.random() < 0.5 ? parent1.genes[i] : parent2.genes[i];
}
return child;
}
private static void mutate(Genome child) {
for (int i = 0; i < GENOME_LENGTH; i++) {
if (Math.random() < MUTATION_RATE) {
int modulo = i % 2 == 0 ? NUMBER_OF_COLUMNS : NUMBER_OF_ROTATIONS;
child.genes[i] = (child.genes[i] + (int) ((rnd.nextInt(3) - 1) * MUTATION_IMPACT) + modulo) % modulo;
}
}
}
private static Genome tournamentSelection(List<Genome> fittest) {
List<Genome> participants = new ArrayList<>();
for (int i = 0; i < TOURNAMENT_SIZE; i++) {
participants.add(fittest.get(rnd.nextInt(fittest.size())));
}
Collections.sort(participants);
return participants.get(0);
}
private static List<Genome> buildInitialPopulation(Pair[] blocks) {
List<Genome> population = new ArrayList<>();
carryFrom(population);
for (int i = 0; i < NUMBER_OF_COLUMNS; i++) {
for (int j = 0; j < NUMBER_OF_ROTATIONS; j++) {
Genome genome = new Genome();
genome.genes[0] = i;
genome.genes[1] = j;
for (int k = 2; k < GENOME_LENGTH; k++) {
if (k % 2 == 0) {
genome.genes[k] = rnd.nextInt(NUMBER_OF_COLUMNS);
}
else {
genome.genes[k] = rnd.nextInt(NUMBER_OF_ROTATIONS);
}
}
// Filter out invalid genomes
if (genome.isValid()) {
population.add(genome);
}
}
}
while (population.size() < POPULATION_SIZE) {
Genome genome = new Genome();
for (int j = 0; j < GENOME_LENGTH; j++) {
if (j % 2 == 0) {
genome.genes[j] = rnd.nextInt(NUMBER_OF_COLUMNS);
}
else {
genome.genes[j] = rnd.nextInt(NUMBER_OF_ROTATIONS);
}
}
// Filter out invalid genomes
if (genome.isValid()) {
population.add(genome);
}
}
return population;
}
private static void carryFrom(List<Genome> population) {
for (Genome old : carriedOver) {
for (int j = 0; j < CARRY_REPLICATION; j++) {
Genome clone = old.copy();
for (int i = 0; i < GENOME_LENGTH - 2; i++) {
clone.genes[i] = old.genes[i + 2];
}
clone.genes[GENOME_LENGTH - 2] = rnd.nextInt(NUMBER_OF_COLUMNS);
clone.genes[GENOME_LENGTH - 1] = rnd.nextInt(NUMBER_OF_ROTATIONS);
if (clone.isValid()) {
population.add(clone);
}
}
}
}
private static long getSystemTime() {
// return System.nanoTime();
return System.currentTimeMillis();
}
public static class Genome implements Comparable<Genome> {
int[] genes = new int[GENOME_LENGTH];
int score;
Grid finalGrid;
List<String> debugInfo = new ArrayList<>();
int[] skullsDropped = new int[GENOME_LENGTH / 2];
@Override
public int compareTo(Genome o) {
// First look if anyone can drop 2 skulls
int oDropSkulls2 = o.dropSkulls(2);
int thisDropSkulls2 = dropSkulls(2);
if (oDropSkulls2 > -1 && thisDropSkulls2 == -1) {
return 1;
}
else if (oDropSkulls2 == -1 && thisDropSkulls2 > -1) {
return -1;
}
else if (oDropSkulls2 > -1 && thisDropSkulls2 > -1) {
if (oDropSkulls2 < thisDropSkulls2) {
return 1;
}
else if (oDropSkulls2 > thisDropSkulls2) {
return -1;
}
else {
return o.score - score;
}
}
else {
int oDropSkulls1 = o.dropSkulls(1);
int thisDropSkulls1 = dropSkulls(1);
if (oDropSkulls1 > -1 && thisDropSkulls1 == -1) {
return 1;
}
else if (oDropSkulls1 == -1 && thisDropSkulls1 > -1) {
return -1;
}
else if (oDropSkulls1 > -1 && thisDropSkulls1 > -1) {
if (oDropSkulls1 < thisDropSkulls1) {
return 1;
}
else if (oDropSkulls1 > thisDropSkulls1) {
return -1;
}
else {
return o.score - score;
}
}
}
return o.score - score;
}
private int dropSkulls(int amount) {
for (int i = 0; i < skullsDropped.length; i++) {
if (skullsDropped[i] >= amount) { return i; }
}
return -1;
}
public boolean isValid() {
for (int i = 0; i < GENOME_LENGTH; i = i + 2) {
if (genes[i] < 0 || genes[i] > 5 || genes[i] == 0 && genes[i + 1] == 2
|| genes[i] == 5 && genes[i + 1] == 0) { return false; }
}
return true;
}
public Genome copy() {
Genome copy = new Genome();
for (int i = 0; i < genes.length; i++) {
copy.genes[i] = genes[i];
}
return copy;
}
public void addDebugInfo(int blocksCleared, int chainPower, int colorBonus, int groupBonus,
int blocksInGroups) {
String debug = blocksCleared + "," + chainPower + "," + colorBonus + "," + groupBonus;
debugInfo.add(debug);
}
@Override
public String toString() {
return "Genome [genes=" + Arrays.toString(genes) + ", score=" + score + ", skullsDropped="
+ Arrays.toString(skullsDropped) + ", debugInfo=" + debugInfo + "]";
}
// @Override
// public String toString() {
// return "Genome [genes=" + Arrays.toString(genes) + ", score=" + score
// + ", debugInfo=" + debugInfo
// + ", finalGrid=\n" + finalGrid + "]";
// }
}
public static class Pair {
char colorA, colorB;
public Pair(char colorA, char colorB) {
super();
this.colorA = colorA;
this.colorB = colorB;
}
@Override
public String toString() {
return "Pair [colorA=" + colorA + ", colorB=" + colorB + "]";
}
}
public static class Grid {
Cell[] rows = new Cell[NUMBER_OF_COLUMNS * NUMBER_OF_ROWS];
Set<Group> groups = new HashSet<>();
public void addRow(int currentRow, String row) {
for (int i = 0; i < NUMBER_OF_COLUMNS; i++) {
rows[currentRow * NUMBER_OF_COLUMNS + i] = new Cell(currentRow * NUMBER_OF_COLUMNS + i, row.charAt(i));
}
}
public int skulls() {
int skulls = 0;
for (int i = 0; i < rows.length; i++) {
if (rows[i].block == '0') {
skulls++;
}
}
return skulls;
}
public int filled() {
int filled = 0;
for (int i = 0; i < rows.length; i++) {
if (rows[i].block != '.') {
filled++;
}
}
return filled;
}
public float highestColumn() {
for (int i = rows.length - 1; i >= 0; i--) {
if (rows[i].block != '.') { return i / NUMBER_OF_COLUMNS; }
}
return 0;
}
public int computeScore(Genome genome, Pair[] blocks) {
int chainSteps = -1;
int[] colorsCleared = new int[5];
int blocksCleared = 0;
int groupBonus = 0;
int blocksInGroups = 0;
System.err
.println("Starting chain score iterations for " + genome + " and pairs " + Arrays.toString(blocks));
// Each pass in the loop is a step in the score computation process
while (true) {
int blocksClearedThisStep = 0;
System.err.println("Iterating in chain score");
// System.err.println("Current group map is \n" + debug());
System.err.println(this);
// Add the score
for (Group group : groups) {
blocksInGroups += group.size();
// Something happens!
if (group.size() >= 4) {
for (int index : group.nodes) {
// try {
colorsCleared[Character.getNumericValue(rows[index].block) - 1] = 1;
// }
// catch (ArrayIndexOutOfBoundsException e) {
// System.err.println("error getting numeric value
// from cell " + rows[index]
// + " for group " + group + " with groups " +
// groups);
// throw e;
// }
rows[index].block = '.';
rows[index].group = null;
}
blocksClearedThisStep += group.size();
Set<Integer> neighbours = getNeighbors(group.nodes);
for (int index : neighbours) {
if (rows[index].block == '0') {
// clusterSize++;
rows[index].block = '.';
rows[index].group = null;
}
}
if (group.size() == 5) {
groupBonus += 1;
}
else if (group.size() == 6) {
groupBonus += 2;
}
else if (group.size() == 7) {
groupBonus += 3;
}
else if (group.size() == 8) {
groupBonus += 4;
}
else if (group.size() == 9) {
groupBonus += 5;
}
else if (group.size() == 10) {
groupBonus += 6;
}
else if (group.size() >= 11) {
groupBonus += 8;
}
blocksCleared += blocksClearedThisStep;
}
}
if (blocksClearedThisStep > 0) {
// Make the blocks fall down when applicable
falldownBlocks();
// Recompute groups
computeGroups();
chainSteps++;
}
else {
break;
}
}
int chainPower = 0;
if (chainSteps > 0) {
chainPower = 8;
chainSteps--;
while (chainSteps > 0) {
chainPower = 2 * chainPower;
chainSteps--;
}
}
int numberOfColors = 0;
for (int i = 0; i < colorsCleared.length; i++) {
numberOfColors += colorsCleared[i];
}
int colorBonus = 0;
if (numberOfColors == 2) {
colorBonus = 2;
}
else if (numberOfColors == 3) {
colorBonus = 4;
}
else if (numberOfColors == 4) {
colorBonus = 8;
}
else if (numberOfColors == 5) {
colorBonus = 16;
}
int multiplier = Math.min(Math.max(1, chainPower + colorBonus + groupBonus), 999);
int score = (int) (10 * (blocksCleared * multiplier + GROUPING_FACTOR * blocksInGroups));
genome.addDebugInfo(blocksCleared, chainPower, colorBonus, groupBonus, blocksInGroups);
// System.err.println("\t" + (getSystemTime() - startTime) + " -
// Updated grid");
// If there is something in the top row, decrease score
// for (int i = rows.length - NUMBER_OF_COLUMNS - 1; i <
// rows.length; i++) {
// if (rows[i].block != '.') {
// score -= DANGER_MALUS;
// }
// }
// System.err.println("\t" + (getSystemTime() - startTime) + " -
// Updated danger malus");
return score;
}
private Set<Integer> getNeighbors(Set<Integer> nodes) {
Set<Integer> neighbors = new HashSet<>();
for (int index : nodes) {
if (rows[index].isNotLeft() && !nodes.contains(rows[index - 1])) {
neighbors.add(index - 1);
}
if (rows[index].isNotRight() && !nodes.contains(rows[index + 1])) {
neighbors.add(index + 1);
}
if (rows[index].isNotBottom() && !nodes.contains(rows[index - NUMBER_OF_COLUMNS])) {
neighbors.add(index - NUMBER_OF_COLUMNS);
}
if (rows[index].isNotTop() && !nodes.contains(rows[index + NUMBER_OF_COLUMNS])) {
neighbors.add(index + NUMBER_OF_COLUMNS);
}
}
return neighbors;
}
private void falldownBlocks() {
boolean fellDown = true;
while (fellDown) {
fellDown = false;
for (int i = 0; i < rows.length - NUMBER_OF_COLUMNS; i++) {
if (rows[i].block == '.' && rows[i + NUMBER_OF_COLUMNS].block != '.') {
fellDown = true;
rows[i].block = rows[i + NUMBER_OF_COLUMNS].block;
rows[i + NUMBER_OF_COLUMNS].block = '.';
}
}
}
}
public boolean addPair(Pair pair, int position, int rotation) {
boolean valid = false;
System.err.println("adding pair " + pair);
System.err.println(this);
// Get back to the case where the first element of the pair is
// always at the bottom
if (rotation == 3) {
char previousColorA = pair.colorA;
pair.colorA = pair.colorB;
pair.colorB = previousColorA;
rotation = 1;
}
// System.err.println("\t\t\tGroups before first attachment " +
// groups);
// Add the first element
for (int i = 0; i < NUMBER_OF_ROWS; i++) {
Cell cell = rows[i * NUMBER_OF_COLUMNS + position];
if (cell.block == '.') {
// System.err.println("\t\t\tadding " + pair.colorA + "
// to "
// + position);
// System.err.println("\t\t\tattaching first element " +
// pair.colorA + " to " + cell);
cell.block = pair.colorA;
// reattach(cell);
valid = true;
break;
}
}
// System.err.println("\t\t\tGroups after first attachment " +
// groups);
// Add the second element
if (rotation == 0) {
position++;
}
else if (rotation == 2) {
position--;
}
for (int i = 0; i < NUMBER_OF_ROWS; i++) {
Cell cell = rows[i * NUMBER_OF_COLUMNS + position];
if (cell.block == '.') {
// System.err.println("\t\t\tadding " + pair.colorB + " to "
// + position);
// System.err.println("\t\t\tattaching second element " +
// pair.colorB + " to " + cell);
cell.block = pair.colorB;
// reattach(cell);
valid = true;
break;
}
}
if (valid) {
computeGroups();
}
// System.err.println("\t\t\tGroups after attachment " + groups);
return valid;
}
// private void reattach(Cell cell) {
// if (cell.block == '0' || cell.block == '.') { return; }
//
// List<Group> potentialGroups = new ArrayList<>();
//
// if (cell.isNotLeft() && rows[cell.index - 1].block == cell.block) {
// if (rows[cell.index - 1].group != null) {
// potentialGroups.add(rows[cell.index - 1].group);
// }
// else {
// Group group = cell.group(rows[cell.index - 1]);
// groups.add(group);
// potentialGroups.add(group);
// }
// }
// if (cell.isNotBottom() && rows[cell.index - NUMBER_OF_COLUMNS].block
// == cell.block) {
// if (rows[cell.index - NUMBER_OF_COLUMNS].group != null) {
// potentialGroups.add(rows[cell.index - NUMBER_OF_COLUMNS].group);
// }
// else {
// Group group = cell.group(rows[cell.index - NUMBER_OF_COLUMNS]);
// groups.add(group);
// potentialGroups.add(group);
// }
// }
// if (cell.isNotRight() && rows[cell.index + 1].block == cell.block) {
// // System.err.println("\t\t\t\tHas right neighbor " +
// // rows[cell.index + 1].block + " " + cell.block);
// if (rows[cell.index + 1].group != null) {
// potentialGroups.add(rows[cell.index + 1].group);
// }
// else {
// Group group = cell.group(rows[cell.index + 1]);
// groups.add(group);
// potentialGroups.add(group);
// }
// }
//
// // Consolidate the groups
// Group newGroup = new Group();
// for (Iterator<Group> iterator = potentialGroups.iterator();
// iterator.hasNext();) {
// Group group = iterator.next();
// for (Integer index : group.nodes) {
// newGroup.nodes.add(index);
// rows[index].group = newGroup;
// }
// iterator.remove();
// groups.remove(group);
// }
// if (!newGroup.nodes.isEmpty()) {
// groups.add(newGroup);
// }
// }
public void computeGroups() {
groups = new HashSet<>();
for (int i = 0; i < rows.length; i++) {
rows[i].group = null;
// If it's empty, it's not part of a group
if (rows[i].block == '.' || rows[i].block == '0') {
continue;
}
// If has a left neighbor
if (rows[i].isNotLeft() && rows[i - 1].block == rows[i].block) {
Group group = null;
if (rows[i - 1].group != null) {
group = rows[i - 1].group;
}
else {
group = new Group();
}
group.add(rows[i - 1]);
group.add(rows[i]);
rows[i].group = group;
rows[i - 1].group = group;
groups.add(group);
}
// If has a bottom neighbor
if (rows[i].isNotBottom() && rows[i - NUMBER_OF_COLUMNS].block == rows[i].block) {
Group group = null;
if (rows[i - NUMBER_OF_COLUMNS].group != null) {
group = rows[i - NUMBER_OF_COLUMNS].group;
if (rows[i].group != null) {
Group oldGroup = rows[i].group;
for (Integer index : rows[i].group.nodes) {
group.nodes.add(index);
rows[index].group = group;
}
groups.remove(oldGroup);
}
}
else if (rows[i].group != null) {
group = rows[i].group;
}
else {
group = new Group();
}
group.add(rows[i - NUMBER_OF_COLUMNS]);
group.add(rows[i]);
rows[i].group = group;
rows[i - NUMBER_OF_COLUMNS].group = group;
}
}
// for (int i = 0; i < rows.length; i++) {
// rows[i].computeGroupSize();
// }
}
public Grid copy() {
Grid copy = new Grid();
for (int i = 0; i < NUMBER_OF_COLUMNS * NUMBER_OF_ROWS; i++) {
copy.rows[i] = rows[i].copy();
}
for (Group group : groups) {
copy.groups.add(group.copy());
}
for (Group group : copy.groups) {
for (int index : group.nodes) {
copy.rows[index].group = group;
}
}
return copy;
}
public String debug() {
String groups = this.groups.toString() + "\n";
String ret = "" + groups;
for (int i = 0; i < NUMBER_OF_ROWS; i++) {
String row = "";
for (int j = 0; j < NUMBER_OF_COLUMNS; j++) {
int groupSize = rows[i * NUMBER_OF_COLUMNS + j].groupSize();
row += (groupSize == 0 ? "." : groupSize) + " ";
}
ret = row + "\n" + ret;
}
ret += "\n\n";
return ret;
}
@Override
public String toString() {
String ret = "";
for (int i = 0; i < NUMBER_OF_ROWS; i++) {
String row = "";
for (int j = 0; j < NUMBER_OF_COLUMNS; j++) {
row += rows[i * NUMBER_OF_COLUMNS + j].block + " ";
}
ret = row + "\n" + ret;
}
ret += "\n\n";
// for (int i = 0; i < NUMBER_OF_ROWS; i++) {
// for (int j = 0; j < NUMBER_OF_COLUMNS; j++) {
// int groupSize = rows[i * NUMBER_OF_COLUMNS + j].groupSize;
// ret += (groupSize == 0 ? " " : groupSize) + " ";
// }
// ret += "\n";
// }
return ret;
}
}
public static class Cell {
char block;
int index;
Group group = null;
public Cell(int index, char block) {
super();
this.index = index;
this.block = block;
}
public boolean isNotBottom() {
return index >= NUMBER_OF_COLUMNS;
}
public boolean isNotTop() {
return index <= NUMBER_OF_ROWS * (NUMBER_OF_COLUMNS - 1);
}
public boolean isNotLeft() {
return index % NUMBER_OF_COLUMNS > 0;
}
public boolean isNotRight() {
return index % NUMBER_OF_COLUMNS < NUMBER_OF_COLUMNS - 1;
}
public Cell copy() {
Cell copy = new Cell(index, block);
// copy.groupSize = groupSize;
return copy;
}
public int groupSize() {
return group == null || block == '.' ? 0 : group.size();
}
// public Group group(Cell cell) {
// if (cell.block == '0' || cell.block == '.') { return null; }
// if (cell.group == null) {
// cell.group = new Group();
// cell.group.add(cell);
// }
// cell.group.add(this);
// group = cell.group;
// return group;
// }
@Override
public String toString() {
return "Cell [block=" + block + ", index=" + index + ", group=" + group + "]";
}
}
public static class Group {
Set<Integer> nodes = new HashSet<>();
public void add(Cell node) {
nodes.add(node.index);
}
public Group copy() {
Group copy = new Group();
for (int index : nodes) {
copy.nodes.add(index);
}
return copy;
}
public int size() {
return nodes.size();
}
@Override
public String toString() {
return "Group [nodes=" + nodes + "]";
}
}
}
@sebastientromp
Copy link
Author

Le computescore à la L159 a un peu changé par rapport à ce que j'avais submit - j'ai tenté un truc pour ne pas utiliser le score en tant que tel, mais plus les nuisance points que ça générait, mais j'ai pas réussi à faire un truc efficace

@Jahz19
Copy link

Jahz19 commented Jun 10, 2016

Un algo génétique ça donne de jolis noms de fonctions :)
Je connais pas du tout le principe par contre, donc impossible de commenter là dessus.
D'un point de vue perf, j'ai l'impression que ça va être moyen car quand tu fais une copie de Grid, beaucoup de copies de structures à tailles variables et de "new". Tu tournais à combien en 100 ms ?
J'imagine qu'avec ce type d'algo la qualité du résultat dépend quand même bien du nombre de simuls.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment