Created
April 22, 2022 21:22
-
-
Save dogles/6b8d94d26c5e37ac2aa8e64ff124acb0 to your computer and use it in GitHub Desktop.
Example of rule formulas
This file contains hidden or 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
// Rule formulas can only be defined within a Program::define() block | |
auto simpleMaze = Program::define([](int width, int height, int entranceX, int entranceY, int exitX, int exitY) | |
{ | |
// Floating variables. These don't mean anything outside the context of a rule statement. | |
// Within a rule statement, they encode equality. E.g. if "X" shows up in two places in a rule, | |
// it means that those Xs are the same. See below. | |
FormulaParameter X, Y, X1, Y1; | |
// define col(1), col(2), ... col(width) as atoms. | |
Formula<1> col = Program::range(1, width); | |
// define row(1), row(2), ... row(height) as atoms. | |
Formula<1> row = Program::range(1, height); | |
// define a rule grid(X,Y), which is only true if X is a column and Y is a row. | |
Formula<2> grid; | |
grid(X,Y) <<= col(X) && row(Y); | |
// define a rule formula adjacent(x1,y1,x2,y2), which is only true for two adjacent tiles. | |
Formula<4> adjacent; | |
adjacent(X,Y,X,Y1) <<= grid(X,Y) && Y1 == Y + 1 && row(Y1); | |
adjacent(X,Y,X,Y1) <<= grid(X,Y) && Y1 == Y - 1 && row(Y1); | |
adjacent(X,Y,X1,Y) <<= grid(X,Y) && X1 == X + 1 && col(X1); | |
adjacent(X,Y,X1,Y) <<= grid(X,Y) && X1 == X - 1 && col(X1); | |
// Define a rule formula border(x,y), which is only true at the edges of the map. | |
Formula<2> border; | |
border(1,Y) <<= row(Y); | |
border(X,1) <<= col(X); | |
border(X,Y) <<= row(Y) && X == width; | |
border(X,Y) <<= col(X) && Y == height; | |
// define the entrance/exit positions, based on the program inputs. | |
Formula<2> entrance, exit; | |
entrance(X,Y) <<= X == entranceX && Y == entranceY; | |
exit(X,Y) <<= X == exitX && Y == exitY; | |
Formula<2> wall, empty; | |
// wall OR empty may be true if this is a grid tile that is not on the border and not the entrance or exit. | |
(wall(X,Y) | empty(X,Y)) <<= grid(X,Y) && -border(X,Y) && -entrance(X,Y) && -exit(X,Y); | |
// border is a wall as long as it's not the entrance or exit. | |
wall(X,Y) <<= border(X,Y) && -entrance(X,Y) && -exit(X,Y); | |
// entrance/exit are always empty. | |
empty(X,Y) <<= entrance(X,Y); | |
empty(X,Y) <<= exit(X,Y); | |
// disallow a 2x2 block of walls | |
Program::disallow(wall(X,Y) && wall(X1, Y) && wall(X, Y1) && wall(X1, Y1) && X1 == X+1 && Y1 == Y+1); | |
// disallow a 2x2 block of empty | |
Program::disallow(empty(X,Y) && empty(X1, Y) && empty(X1, Y1) && X1 == X+1 && Y1 == Y+1); | |
// If two walls are on a diagonal of a 2 x 2 square, both common neighbors should not be empty. | |
Program::disallow(wall(X,Y) && wall(X1+1,Y1+1) && empty(X1+1,Y) && empty(X, Y1+1)); | |
Program::disallow(wall(X+1,Y) && wall(X,Y+1) && empty(X, Y) && empty(X+1, Y1+1)); | |
// wallWithAdjacentWall(x,y) is only true when there is an adjacent cell that is a wall. | |
Formula<2> wallWithAdjacentWall; | |
wallWithAdjacentWall(X,Y) <<= wall(X,Y) && adjacent(X, Y, X1, Y1) && wall(X1, Y1); | |
// disallow walls that don't have any adjacent walls | |
Program::disallow(wall(X,Y) && -border(X,Y) && -wallWithAdjacentWall(X,Y)); | |
// encode reachability (faster to do this with a reachability constraint) | |
Formula<2> reach; | |
reach(X,Y) <<= entrance(X,Y); | |
reach(X1,Y1) <<= adjacent(X,Y,X1,Y1) && reach(X,Y) && empty(X1,Y1); | |
Program::disallow(empty(X,Y) && -reach(X,Y)); | |
}); | |
// give an instantiated version of the program to the solver. | |
// this is an addition to whatever other constraints you want to add! | |
solver.addProgram(simpleMaze(10, 10, /*entrance:*/1,5, /*exit:*/5,10)); | |
solver.solve(); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment