One big strength of packages like shiny is the ability to easily vary parameters and view the results, especially in plots.
So here’s a small shiny app that I created to learn about reactivity, while also having fun.
The idea is simple. Vary many aspects of geom_segments in ggplot, and see what emerges. The things that I played with are canvas size, line origin and destination, line length, the angle and the colors.
Because it is art, I made the background black.
There were many experiments that didn’t appeal to me aesthetically. Others seemed very repetitive. The ones that seemed okay, I kept.
Using R and Integer Programming to find solutions to FlowFree game boards
What is FlowFree?
A popular game (iOS/Android) on a square board with simple rules. As the website states: Connect matching colors with pipes to create a flow. Pair all colors, and cover the entire board to solve each puzzle in Flow Free.
If you play a few games, you will be able to follow this post better. The games get progressively harder as you increase the board size.
The solutions to the various levels are available on the web, but it is fun to use R (and the lpSolveAPI package) to come up with solutions ourselves.
So let's say that the board is made up on n "cells" (small squares) on each side.
A pipe can enter a cell from the center of any side. So each cell has 4 edges.
Figure: A cell with 4 edges meeting at the center
Terminal cells - Those cells where a colored-strand begins or ends. (Only one edge can be on in that cell.)
The 'rules' that we need to incorporate into our IP model
* The lines cannot cross.
* All the cells (squares) must be covered
* The colored lines must begin and end where they are shown
Decision variables
The problem comes down to deciding which edges to turn on, and which ones to leave off.
An edge has a color and a cell. X_cke is 1 if edge e of color k in cell c is valid. 0 otherwise.
The constraints in English
Cell Cover Constraints: Every cell has to have 2 edges that turned on. (One to come in, one to exit)
Special case: Terminal cells have only one edge that can be 1. All other edges are 0.
An Edge can have only one color (LimitEdge constraints)
Horizontal Connectivity - If two cells are horizontal neighbors (side by side), then the value of the east edge of the left cell must be the same as the west edge of the cell on the right.
Vertical Connectivity - If two cells are vertical neighbors (one on top of the other), then the value of the downward edge of the top cell must be the same as the upward edge of the bottom cell
Boundary Edges - Certain edges for the cells in the boundary of the board are made zero. (For example, in the 4 corner cells, at most 2 edges can be 1.)
Single color in Terminal Cells - Each terminal cell has a pre-determined color given to us as input, so we can set of the edge varibles of every other color to be zero.
Same color per cell & Pick 1 constraints. We set 0/1 variables and make sure that if a color is one inside a cell, ONLY that color edges are allowed in that cell. (These are dense constraints and can make solution times explode for larger grids.)
Load one specific Puzzle
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
All of the work of creating the matrix, the right hand side are done by 3 functions - init(), populate.Amatrix() and defineIP(). [See github for the code] Now, let's initialize an empty data frame, based on number of constraints and variables that the IP will have.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Model name: a linear program with 500 decision variables and 458 constraints > solve(lpff) > sol <- get.variables(lpff)
> sum(unlist(sol[1:num.edges])) [1] 42
> plotSol(terminal.cells, colorpalette)
produces the solution:
And here's the solution when I tried an 8x8 (Level 17) grid:
Note: Because of same-color and pick-1 constraints, this problem explodes in size as n (the size of the grid) increases. There are however, ways to address it, using relaxation.
Future Improvements: The addition of the pick-1 and the same-color constraints spoil the structure of the A-matrix and increase the solution time. These can be made optional, in which case the solution will require manual intervention.