I am working in a grid-universe - objects only exist at integer locations in a 2 dimensional matrix.
Some terms:
Square - a discrete location. Each square has an int x and int y coordinate, and no two squares have the same x and y pair.
Adjacent: A square X is adjacent to another square Y if the magnitude of the difference in either their x or y coordinate is no greater than 1. Put more simply, all squares immediately in the N, NE, E, SE, S, SW, W, and NW directions are adjacent.
Legend:
'?' - Unknown Traversibility
'X' - Non Traversable Square
'O' - Building (Non Traversable)
' ' - Traversable Square
The problem:
Given the following generic situation:
? ? ? ? ? ? ? ?
? ? ? ? ? ? ? ?
? ? ? ? ? ? ? ?
? ? ? O O ? ? ?
? ? ? O O ? ? ?
? ? ? ? ? ? ? ?
? ? ? ? ? ? ? ?
? ? ? ? ? ? ? ?
where the builder is adjacent to one of the four buildings, I want to build two buildings such that they both share a common adjacent square that is also adjacent to at least one of the four existing buildings, and this common adjacent square is not blocked in.
Basic Valid solutions:
X X X X X X X X X X X X X X X X X X X X X X
X X X X X X X X X X X X X X X X X X X X X X
X X X X X X X X X X X X X X X X X X X X X X
X X X O O X X X X X X O O X X X X X X O O X X X
X X X O O X X X X X X O O X X X X X O O O X X X
X X X O X X X O X X X X
O O X X X O X X X X X X X X
X X X X X X X X X X X
Currently, I iterate through all traversable square adjacent to the four buildings, and look for squares that have 3 adjacent traversable squares, but this sometimes produces situations such as:
X X X X X X X X X X X X X X X X X X X X X X X X
X X X X X X X X X X X X X X X X X X X X X X X
X X X X X X X X X X O X X X X X O X
X X X O O X X X X X O O O X X X O O O X X
X X X O O X X X X X O O X X X X O O X X
X X X X X X X X X X X X X X
X X X O O X X X X X X X X X X X X X X X
X X X X X X X X X X X X X X X X X X
Any thoughts on how I can refine my algorithm?
EDIT: Added another failing case.
EDIT: I'd also like to be able to know if there isn't a possible configuration in which these conditions could be met. I'm not guaranteed a viable solution, and would like to not-try if there isn't a way to do this successfully.
Checking to ensure your new buildings aren't orthogonally adjacent will eliminate cases such as your problem case 1, and checking to ensure not more than one of your new buildings is adjacent to any of the originals will clear up problem case 2.
This should work if you can safely assume you are no more constricted than in problem case 2. If there is only one square of exit, then the only solutions will need to violate the "not more than one" condition proposed above.
Your invalid cases are due to the splitting of the free space into 2 parts right? In that case, a crude method would be to flood-fill the free space after building placement and see if the connected space has the correct size (2 squares less than prior to building placement). That seems excessive. You really want to know if the graph of the free-space squares is still connected. More specifically, you want to know if all the free-space squares around the new buildings are still connected. Do they have to be locally connected, or can the path be arbitrarily long? i.e. is this valid:
X X X X X X X X
X X X
X X X X X X
X X X X X X
X O X X
X X O O O X X
X X O O X X
X X X X
X X X X X X
X X X X X X
If that is OK, this is a hard problem because that path could be very long.
The only solution I can think of is to do pathfinding from the common adjacent square out to the edge of the map. It looks to me like all the problem cases boil down to "the adjacent square is blocked in" so the way to ensure it isn't blocked in is to find a path from that square to an open edge of the map.
I don't know if that's the most efficient approach but it would be fairly simple to implement, since A* pathfinding routines are pretty widely implemented. And actually since you don't need the shortest path, just a path, you could simply do a flood-fill of free spaces starting from the adjacent square until you hit the edge of the map.
Related
In an ILP, given two variables x and y, is it possible to define a variable z where
z = (x==y)?
Meaning, if x equals y then z = 1.
Else, z = 0.
x and y are integer variables bounded between (1, M).
If you know that x <= y, then you can use z in {0,1}, x+Mz >= y, x+z <= y.
If you don't know which of x and y is minimum, you can do it with more work, by adding a variable minxy which takes the value of the minimum. You need to introduce another new variable (which I call a) to do this.
Introduce a variable a that's 0 if x<=y, 1 if y<=x (it could be either 0 or 1 if x==y):
a in {0,1}, x-y <= Ma, y-x <= M(1-a)
Introduce a variable minxy that's the minimum of x and y:
minxy <= x
minxy <= y
minxy >= x - Ma
minxy >= y - M(1-a)
Then you can define your z:
minxy + Mz >= x + y - minxy
minxy + z <= x + y - minxy
(Noting that max(x,y) is x + y - minxy).
We need to find the all possible subsets assuming the element used will be deleted.
test case
a=4 b=5
a b b
a b b
a a b
hence the answer is 3
Is there a general formula for doing this?
Let's say we have a = x and b = z. If we want to maximize the amount of groups we can make, we will want to pick 2 from the letter that we have most of. Let's say z > x. While this holds true, we will want to pick 2 from z and 1 from x.
Eventually 2 things can happen: either x got to 0, in which case we made x groups in total or x = z. If x = z, we can alternate taking 2 from one and 1 from the other until either both are 1 or both are 0. If both are 0, that means we used all z + x letters, so we made (z + x) / 3 groups. If both are 1, we used (z + x - 2) letters, so we made (z + x - 2 / 3) groups. Both these cases can be handled by floor((x + z) / 3).
So we have min(x, floor((x + z) / 3)) and if you assume x > z, you will also have to consider that x never got equal to z so you made z groups, thus leaving us with min(x, z, floor((x + z) / 3))
I have:
:-use_module(library(clpr)).
comp(X, Y, Z):-
{X = Y * Z, Y = Z, Y > 0, Z > 0}.
Which with the query:
?-comp(X,3,Z).
Yields:
X = 9.0,
Z = 3.0
as expected. But why doesn't
comp(9,Y,Z).
also give me values for Y and Z? What I get is instead:
{Z>0.0,Y=Z,9-Y*Z=0.0},
{9-Y*Z=0.0},
{9-Y*Z=0.0}
Thanks!
Probably a weakness of the used CLP(R) that quadratic case doesn't work so well. After Y = Z, it is evident that X = Y**2, and then with X = 9 and Y > 0, you should easily get Y = 3. Which CLP(R) do you use?
A CLP(R) need not only support linear equalities and inequalities. Using for example Gröbner Basis algorithm a CLP(R) could do more, even algebraically. Some computer algebra system can do that easily.
So I guess its not a problem of Prolog per se, rather of the library. Strictly speaking CLP(X) only indicates a domain X. For the domain R of real numbers there is wide variety of potential equation and inequation solvers.
Better with constraints over finite domains using this module:
:-use_module(library(clpfd)).
comp(X, Y, Z):-
X #= Y * Z, Y #= Z, Y #> 0, Z #> 0.
With
comp(9,Y,Z).
I get:
Y = Z, Z = 3
I got the following task:
int_log2(X,Y) which sets Y to the integer log2 of X, where X is assumed to be a non-negative integer. For example int_log(133,X) will set X to 7. The integer log base 2 of X means the number of times you divide Xby 2 to get down to one. Where divide means integer division. Use nothing more than + and div to code it.
This is what I got so far. I am not 100% sure if I should do it like this. When I run query int_log(133,Z), it only shows answer in true or false.
div(0,X).
div(X,Z) :- X \=0, X1 is X-1, div(X1,W), Z is floor(X/2).
int_log(0,X).
int_log(X,Z) :- X \= 0, X1 is X-1, int_log(X1,W), div(W,Z).
As it is with such exercises, the problem statement already contains the answer.
X is assumed to be a non-negative integer
% precondition( integer(X) ).
% precondition( X > 0 ).
... the number of times you divide X by 2 to get down to one
int_log2(1, 0).
int_log2(X, Y) :-
... the number of times you divide X by 2...
... Use nothing more than + and div to code it.
X0 is X div 2, % used `div`
int_log2(X0, Y0),
Y is Y0 + 1. % used `+`
So this works like this:
?- int_log2(133, X).
X = 7 .
?- int_log2(256, X).
X = 8 .
?- int_log2(255, X).
X = 7 .
What will happen if you try to look for more solutions? Where does the choice point come from? How can you get rid of it? How can you get rid of it without using a cut?
Is this for a math course or a "Prolog" course? If it is meant to teach you Prolog, you will have a bad time.
As for how one would solve it: if you are using an implementation that has the arithmetic function msb(), you just say:
Y is msb(X).
for example:
?- X is msb(133).
X = 7.
?- X is msb(256).
X = 8.
I am trying to get a grid to show in prolog, rather than getting the listing of it.
Here is what I have so far
sB:-
showBoard.
showBoard(Row) :-
setof([Row,Col,Object,Visible],square(Row,Col,Object,Visible),RList),
showRow(RList),
writeln(''),
NextRow is Row - 1,
showBoard(NextRow).
This is something new that I am trying to test out to see if I can get this or not. Am I on the right track?
EDIT
For a task, we have to generate a grid through code,
Here is what I am trying to get....
I am using square/3, getting back square(x,y,object). But I hope to step it up to square/4, so I can bring in the visibility of the grid, meaning the robot can only see around him, one square left, right, up and down, until he finds his glasses.
== == == == == == == == == ==
|| x x x x x x x x ||
|| x x x x x x x x ||
|| x x x x x x x x ||
|| x x x x x x x x ||
|| x x x x x x x x ||
|| x x x x x x x x ||
|| x x x x x x x x ||
== == == == == == == == == ==
The easiest would be to "scan" your board left-to-right, top-to-bottom (as this is how we output to a console), and see if there is anything to be shown for this particular square. Assuming that you are using format for writing (easier to control the formatting of the output), and assuming that you know in advance the size of your board, and your x and y coordinates start at the top left corner, you need to:
for each row of the board:
for each position on the row
see if there is something to draw on that square, and draw it
Or, in code:
show_board(Rows, Cols) :-
show_rows(1, Rows, Cols).
show_rows(R, Rows, Cols) :-
( R =< Rows
-> show_row(R, 1, Cols),
R1 is R + 1,
show_rows(R1, Rows, Cols)
; true
).
show_row(R, C, Cols) :-
( C =< Cols
-> show_square(R, C) % or maybe show_square(C, R)?
C1 is C + 1,
show_row(R, C1, Cols)
; true
).
% show_square should always succeed!
show_square(R, C) :-
( square(R, C, Obj /* additional arguments? */)
-> draw(Obj /* additional arguments */)
; draw_not_visible
).
This could be a starting point. It could be done more "fancy" but this is a perfectly valid approach. Drawing an object depends on what your object is, and drawing the boundary around the grid is trivial.