/// <summary> /// Evaluates the garden for symmetry by checking for relative symmetry on 4 axis /// N-S, E-W, NE-SW, and NW-SE. /// /// </summary> /// <returns>A double from 0 (unique) to 1 (full symmetry) describing the symmetry</returns> public double symmetric(int jigger, double weight) { //Gravel matches aren't that big of a deal. //More interested in Rocks //We are going to take the Hamming distance of the strings by "Jiggering" them by some integer (call it jigger) in each direction //Unlike Hamming we are only going to take the count of the Rs that do match up to the other neighborhood. //Then we will divide this number by the min number of Rs in each comparsion section times J^2 (so the number of Rs in N for E-W and NE in NW-SE) //If perfectly symmetrical, this number will be 1. List <double> products = new List <double>(); Neighborhood[] halves = allHalves(); Neighborhood north = halves[NORTH], northeast = halves[NORTHEAST], east = halves[EAST], southeast = halves[SOUTHEAST], south = halves[SOUTH], southwest = halves[SOUTHWEST], west = halves[WEST], northwest = halves[NORTHWEST]; //do all comparisons products.Add(symmetric(north, south, jigger, false, false)); products.Add(symmetric(east, west, jigger, false, true)); products.Add(symmetric(northwest, southeast, jigger, true, false)); products.Add(symmetric(northeast, southwest, jigger, true, false)); double averageProduct = average(products); return(averageProduct * weight); }
public Neighborhood[] allHalves() { Point tempPoint; Atom tempAtom; double slope = length / (width + 0.0); Neighborhood north, south, east, west, northeast, southwest, northwest, southeast; north = getNeighborhood(new Point(0, length / 2), width, length - (length / 2)); south = getNeighborhood(new Point(0, 0), width, (length / 2)); east = getNeighborhood(new Point(0, 0), (width / 2), length); west = getNeighborhood(new Point((width / 2), 0), width - (width / 2), length); northeast = new Neighborhood(); southeast = new Neighborhood(); northwest = new Neighborhood(); southwest = new Neighborhood(); for (int x = 0; x < width; x++) { for (int y = 0; y < length; y++) { tempPoint = new Point(x, y); tempAtom = atomAt(tempPoint); if (y > slope * x) { //in NW northwest.addAtom(tempAtom); } else { //in SE southeast.addAtom(tempAtom); } if (y > (-1 * slope) * x + length) { //in NE northeast.addAtom(tempAtom); } else { //in SW southwest.addAtom(tempAtom); } } } return(new Neighborhood[] { north, northeast, east, southeast, south, southwest, west, northwest }); }
/// <summary> /// Takes two preferably disjoint Neighborhoods and measures if one has /// a dominant amount of Rocks over the other. /// This score should be very weak in the case where there are few rocks as it may not /// be feasible to cover all distinct halves. This can be controlled with the /// "balanceOfNeighborhoods" property. /// </summary> /// <param name="upper">One neighborhood to measure.</param> /// <param name="lower">The other neighborhood to measure.</param> /// <returns></returns> private static double balanceOfNeighborhoods(Neighborhood upper, Neighborhood lower) { int nRocksUpper = upper.numberOfRocks(); int nRocksLower = upper.numberOfRocks(); double resultRatio; if (nRocksUpper >= nRocksLower) { //adding 1.0 to cast to double and prevent division by zero resultRatio = (nRocksLower + 1.0) / (nRocksUpper + 1.0); } else { resultRatio = (nRocksUpper + 1.0) / (nRocksLower + 1.0); } return(resultRatio); }
/// <summary> /// Counts the number of hits and return how many hits occured against how many /// were possible. /// </summary> /// <param name="atomCompare"></param> /// <param name="neighboorhoodCompare"></param> /// <param name="jigger"></param> /// <param name="atomLocation"></param> /// <returns></returns> private static double singleSymmetry(Atom atomCompare, Neighborhood neighboorhoodCompare, int jigger, Point atomLocation) { string atomCompareString = atomCompare.ToString(), compareTo; //temp. Only care about rocks if (!atomCompareString.Equals(Rock.rockString)) { return(0); } Point comparePoint; int countHits = 0, countAll = 0; for (int xDelta = -1 * jigger; xDelta <= jigger; xDelta++) { for (int yDelta = -1 * jigger; yDelta <= jigger; yDelta++) { comparePoint = new Point(atomLocation.X + xDelta, atomLocation.Y + yDelta); compareTo = neighboorhoodCompare.getAtom(comparePoint).ToString(); try { if (atomCompareString.Equals(compareTo)) { countHits++; } countAll++; } catch { //not on the grid. This is instance is not a problem. Jiggering can throw //us outside of the grid. } } } //prevent division by zero errors return(countAll != 0? countHits / (countAll + 0.0): 0); }
/// <summary> /// Go through every point in the upper neighborhood and compare it to the lower. /// Need to implement how to refernce points (Offsetting) /// </summary> /// <param name="upper"></param> /// <param name="lower"></param> /// <param name="jigger"></param> /// <returns></returns> private double symmetric(Neighborhood upper, Neighborhood lower, int jigger, bool flipCoordinates, bool flipOnWidth) { int totalRocks; int upperRocks = upper.numberOfRocks(); int lowerRocks = lower.numberOfRocks(); totalRocks = upperRocks < lowerRocks ? upperRocks : lowerRocks; List <double> products = new List <double>(); Atom tempAtom; Point tempLocation; foreach (Atom a in upper.getAtoms()) { if (!a.getResident().isGravel) { if (flipCoordinates) { tempLocation = invert(a.getLocation()); } else { if (flipOnWidth) { tempLocation = new Point(a.getLocation().X, length - 1 - a.getLocation().Y); } else { tempLocation = new Point(width - 1 - a.getLocation().X, a.getLocation().Y); } } tempAtom = atomAt(tempLocation); products.Add(singleSymmetry(tempAtom, lower, jigger, a.getLocation())); } } return(1 - Math.Pow(average(products), 1 / 4.0)); }