Cookie Cutter Report

Valerie Davidkova
Miqdad Mohammed
Adam Rosenzweig






"C is for cookie, and that's good enough for me"


Introduction
    The Unique Cookie Company has thought up a remarkable marketing gimmick. Every bag of cookies contains n identical cookies, but no two bags of cookies contain cookies with the same shape. Thus every customer gets a set of unique cookies!
    To support this endeavor, the U.C.C. has purchased a Highly Sophisticated Robot that can automatically configure the cookie shape on the fly. The H.S.R. can cut arbitrary polygonal shapes with up to twelve sides. Since the U.C.C. wants each packet to contain the same weight of cookies, the H.S.R. will be configured to cut cookies of a fixed area a .
    Various production costs are proportional to the length of dough needed to cut the cookies. Thus, the U.C.C. would like to minimize the average length of dough needed for the production of a batch of n cookies.





Cookie Ideas and Types
Random Shapes
    These shapes are not generated according to any formula or logic, they are simply random. Because of this, it is impossible to write specialized strategies to handle them. Any given random shape may fall into one or more types of shapes that can be addressed by a particular strategy, or into none of them, making a generic strategy most effective for it.

Simple Geometry
    Simple geometric shapes are typically relatively easy to pack together and tesselate. This is because they are convex and not complicated. Most simple geometric shapes have some form of correspondance that fits them together well for tesselation.

Puzzle Pieces
    "Puzzle Pieces" are cookie shapes specifically designed with interlocking concavities and convexities. They are unlikely to be randomly generated due to the need for appropriately matched protrusions and incisions. That is not to say random generation will not produce some puzzle pieces, but most puzzle pieces will be hand-crafted for proper fits. The concept of the puzzle piece is that there is some special way to combine two or more such that the concavities are filled by the protrusions in a near-perfect manner, and that this positioning is optimal. Proper matching of concavities to convexities is non-trivial in this case.





Placement Strategies in General
Shortest Width
    A simple and naive, though effective, strategy, is to rotate the cookie shape until you discover the minimum width rotation that still fits on the board (that is, is no more than one unit tall, but is as narrow as can be under that constraint). This strategy will always produce an optimal solution for the n = 1 case, assuming the granularity of the rotation is fine enough. It places each successive cookie to the right of the previous one. This simple strategy, with a minor improvement of attempting to squish the cookie horizontally over rather than stopping at the intersections of the bounding boxes, was implemented in our player.

Vertical Stacking
    Another simple and naive strategy is attempting to stack the polygons vertically rather than horizontally. This was our second strategy, and based on the same principle. It found the shortest width, and then attempted to place the latest cookie below the previous cookie.

Tesselation
    In combination, the shortest width and vertical stacking strategies produce a simple tesselation of the cookie shape, since they both calculate the same rotation for the cookie. In general, tesselation involves repeating a shape in some sort of packing. With the strategies we have implemented, this is a simple vertical/horizontal grid packing. The weakness of straight up tesselation is that it often leaves space free because it does not attempt different orientations of the shapes to fit them together more tightly. Tesselating well-packed combinations of shapes often manages to address this issue.

Bounding Boxes vs. Closer Approximations of Shapes
    Initially we placed shapes via their bounding boxes - a rectangle of the same height and width as the rotated shape. This leads to a great deal of wasted space in many cases, because the rectangular box encompasses a great deal more space than just the cookie, especially in the case of star-shaped or similar cookies that have spikes extending far out from the main body of the shape. A somewhat closer approximation of the shape is a convex hull, which is comprised of a subset of the points on the cookie's perimeter, but is guaranteed to be entirely convex. Still, this prevents matching convexities with concavities, so algorithms based on matching edges, angles, or complex shape-features of the cookies are still important. Our player ended up placing cookies by bounding boxes, and then trying to squeeze them to the left as much as possible. Unfortunately, it does not attempt different rotations or to push up and left, or down and left, all of which would be able to improve placement. Still, it is significantly better than simple bounding boxes.

Matching Edges
    We attempted to match two polygons by the longest edge in our code. The idea here is to create a composite shape consisting of a good packing of two cookies, and then place the composite shape. Theoretically at least, this reduces workload because n/2 items need to be placed. We were working on a pair of strategies that computed this composite shape, and then placed them horizontally and vertically, like the shortest width and vertical stacking strategies. Unfortunately, we were unable to produce working code for this, so the concept was not fully explored. However, it is likely that such an approach would not only cut down the size of the tree we had to explore, but also save space since the two cookies paired would be wasting a minimum of area in between them. Ideally, an algorithm would actually find the best edge to pair the shapes on by experimentation, rather than simply selecting the longest edge on the premise that the longest edge produces the most conserved space and is probably the best way to pair the shapes.

Matching Angles
    The concept of matching angles is another way to try and fit cookie shapes together. In essence, it looks for two angles that sum up to something near 360 degrees, and attempts to insert the smaller angle into the larger angle. In theory, this helps combine the shapes into what is, effectively, one larger shape, with a minimum of wasted space, because concavities are being filled and that space taken advantage of. It seems that, while this handles most concavities well, does not do so well on handling the puzzle piece shapes, which seem to require specialized algorithms to handle ideally. The angle-matching we implemented (though it didn't make it into the tournament) went on the following premise: each subsequent cookie attempted to find a rotation that fit its convexity into a concavity of the cookies already placed, or attempted to fit a convexity of those cookies into its concavity.

Matching Complex Concavities and Convexities - Puzzle Shapes
    This type of strategy takes the shape of the cookie, and locates both the concavities and the protrusions. It then attempts to match up a protrusion with a concavity, to find an appropriate alignment that fits the shapes together efficiently. It is fairly specialized towards dealing with puzzle piece shapes, at which it should excel. Unfortunately, we were unable to implement this strategy.

Expansion / Seperation Technique
    In class it was noted that pushing objects together to find the fit of complex concavities with complex convexities is difficult, because it is possible these complex concavities and convexities "pinch off" and thus, the shapes would intersect before they were actually put close enough together to properly match the shapes. This is exemplified by the martini glass example used throughout the class discussions. A variation on this is to start the polygons on top of each other, sharing the same space, and translate them apart along the same axis they would have been translated together on. Once they no longer intersect, you have found the positioning you want for the pair. Most importantly, this variation prevents the case of early intersection.

Physics Simulator
    The physics simulator approach developed by Group 4 intrigued us a great deal, and we were hoping to be able to adapt it as a strategy for our code. Unfortuntely, it was not finished early enough for us to begin work on adapting it, so it remained just a thought for us.





Multiple Strategies Approach
    As shown above, there are many strategies that are quickly conceived of, all of which show promise at solving the problem, or at least specific aspects of the problem. But no one of the strategies is clearly optimal over the others. Most of the matching techniques show great promise for puzzle-like shapes, but substantially less benefit for simpler shapes.
    It seemed logical to combine strategies in some manner. Several groups in fact ran a set of strategies and picked the one that had given the best result for that particular cookie. Our approach was different, but first, a word on that methodology.
Comparing Strategies
    Theoretically, a Cookie Cutter could look at each cookie and determine characteristics about that cookie which would lead to it selecting a particular strategy from its library. This was concluded to be relatively complex. A simplification of the concept leads to the Cookie Cutter trying each strategy in its library for the given cookie and number of copies, and then comparing their results, keeping the one that placed this configuration best.

State Space Search
    A variation on this approach was the core of our player. Rather than employing each strategy to place all cookies in a batch and then selecting the best of the results of those strategies, our player has its strategies place the cookies one at a time. It follows a depth-first tree structure. It places each cookie with the first strategy, then stores that if it's valid. Next it backs up by one cookie and places that last cookie with the second strategy, and compares it to the previous one, again assuming that it is valid. Now it tries on the third strategy for that last cookie, and so on and so forth. It tries every combination of strategies for placing the copies of the given cookie.
    The advantage of this approach is that it allows for maximum flexibility in cookie placement, and also maximizing the functionality of simple strategies like pure horizontal and vertical stacking. The main weakness of it is the slowness. Specifically, if it has s strategies to try, and is placing n copies of a cookie, the time it will take is on the order of s^n. So, in the submitted code, with only two strategies to search, placing ten copies of a cookie involved over one thousand placements to be checked and compared. This is not a big deal with only a few copies, but the time consumption becomes extremely damaging with large numbers of copies.
    It should be noted that the time cost would be fairly low for any strategy or combination of strategies in the real world, since all computations would be performed on specialized chips rather than in a Java Virtual Machine. This massively offsets the time consumption of the strategies, as does the fact that many strategies would likely be run in parallel.
    It should also be noted that the effectiveness of this player is completely dependant upon the set of strategies it searches. We believe this is entirely the reason for our overall poor tournament performance: more on that later.

     The image above serves just to illustrate the difference between comparing a set of strategies and comparing all combinations of the strategies. All three of the nodes discovered by the placement comparison are also found by the full search tree, with the nodes marked (1), (2) and (3) corresponding the the nodes marked (1, 1), (2, 2) and (3, 3) in the full search tree. So the full search tree sees all the same results that a simple comparison does, but it also sees many more. One thing we did not do, that would have been interesting, was print out the path to the particular leaf node that contained the selected solution. It would have been interesting to see how the strategies interacted in this manner.




Tournament Results and Discussion
    In the tournament, our player consistently came out in sixth place, sometimes climbing to five, and occasionally managing to break into the top three. We also occasionally dropped down to seventh place. It was near optimal for the single object cases - behind the top players but typically only by 0.0005 or so, not an extreme problem. This deficiency could be resolved by reducing the angle increment used when computing the minimum width rotation of the shape. Clearly, 0.005 was too large a value to increase the rotations by, and while good rotations were found, the optimal ones were missed in some cases.
    As the number of copies of each cookie increased, both our runtime and our deficiency compared to other players increased. We were never able to place fifty-three cookies in time, due to the s^n nature of the code's runtime. Sometimes, we were not able to place 20 copies either (it took about 4330 seconds). Also, due to our reliance on two naive strategies, we were unable to find complementary rotations and fit cookies together. While typically not a major issue in the case of a small n, this becomes exponentially more problematic as n increases.
    Our results in the tournament were roughly what we had expected, considering the fact that our player was only able to rely on two rather naive strategies. We believe that if we had been able to implement some more advanced strategies in our search space, our performance would have been significantly improved.

    We had another player, which was not finished quite in time for the deadline, and so there was no chance to integrate the strategy it used with the overall state space search. We did run a partial tournament with it ourselves, and the results were fairly interesting. On the whole, it performed better than the state space searcher, and would have placed one or two ranks higher in most situations. Being able to integrate this player would likely have provided a significant boost to our tournament performance.
    Some statistics on this player's performance: in the boat game, with four cookies, it had a score of 0.5079, which would have put it in second place. For seven copies of the dumbbell cookie, it scored 1.2206, which would have it in second place. For two horseshoe cookies, it had a score of 0.3435, for third place. The lightening cookie, with seven cookies, produced 0.653, for fifth place. And for the small cookie, with six copies, it scored 0.077, for a third or fourth place score.
    This player was not tested on more than ten cookies, but it seemed that at more than seven, the packing began to break down.





What We Learned
    We learned a great deal about dealing with geometric shapes. Specifically, the difficulty of manipulating them accurately in a discrete domain. Looking at the tournament results, and how far behind the absolute optimal placement we ended up for the single cookie situations, we realized that we had not selected a sufficiently granular rotational increment, so we learned something about the fineness of the discretization.





Future Considerations
    There are two main considerations for the future: first, increasing the space of strategies to be searched by the program. This will massively increase the effectiveness of the placements. Secondly, time optimizations. Without modifying the strategy's core, the only way to do this is to use hardware and memory to reduce the number of leaf nodes in the placement tree that need to be explored. If a list of previously reached states was stored, then each time a new state was reached, it could be checked against the list. If it had been reached already (and implicitly, by a different path), then there would be no need to explore it further, because it would not produce any new results.
    Between this modification and the specialized hardware implementation mentioned above, the time complexity of our strategy should be sufficiently negated for all but the largest values of n.





Credit Where Credit is Due
    We used Group 1's code as a reference for developing the translation and rotation algorithm, thought presumably it could have been referenced from the game engine just as easily. Likewise, Group 1's code was used in the attempts to code up a strategy that would pair cookie copies by the longest edge and place the combined shape rather than placing each cookie individually. The attempts failed to produce workable code by the submission date, but still, Group 1's code was looked at for it. We also used Group 6's routine for finding the minimal distance to pack two shapes together, though that did not make it to the tournament.
    We would also like to give credit to Abhinav for actually sitting through the full runtime of our player for n=20 for even one cookie shape. At 4332.242 seconds, that was 72 minutes and 12 seconds. Thank you.





A Final Note
GEOMETRY PROBLEMS ARE HARD!!!!!!!
    Any problem involving geometry is a difficult one, due to the complexity of dealing with interacting, complicated continuous shapes in a discrete domain. >