how to convert a minimax to an alpha beta pruning in prolog - prolog

there is a 4 connect game using a minimax algorithm I'm trying to improving it by turning it to alpha-beta
i have this :
getResult([H,T|_],H,T).
doBest(Color, Depth, BestScore, BestMove):-
board(C,_),
setof(X,between(1,C,X),MoveList),
minimax(MoveList,Depth, Color, Res),
sort(Res,SortRes),
(level(N),Depth == N;true),
( Color == r ,!,
nth0(0,SortRes,Move),
getResult(Move,BestScore,BestMove)
;
Color == y ,!,
length(SortRes,Len),
nth1(Len,SortRes,Move),
getResult(Move,BestScore,BestMove)
).
minimax([],_,_,[]).
minimax([H|T],Depth, Color, L):-
minimax(T,Depth,Color,L1),
(
full(H),!, L = L1,!;
(
insert(H,Color), write('__here__'),
top(H,Hight),
checkStatus(H,Hight,Color), write('_'),write(H),write('-'),write(Hight),write('_'),
( win(r) ,!,(V0 is -1000000000 * (Depth + 1),append([[V0,H]],L1,L));
win(y) ,!,(V0 is 1000000000 * (Depth + 1),append([[V0,H]],L1,L));
draw() ,!, append([[0,H]],L1,L);
not(win(r);win(y);draw()),!,
(
Depth == 0 ,!,(score(r,Vr),score(y,Vy),V0 is Vy - Vr,
write('_'),write(Vr),write('|'),write(Vy),write('|'),write(V0),write('_'),
append([[V0,H]],L1,L));
Depth > 0 ,!,( NewDep is Depth - 1,
(Color == r,!,doBest(y, NewDep, BestScore,_),(write('{'),write(BestScore),write('}'));
Color == y,!,doBest(r, NewDep, BestScore,_),(write('{'),write(BestScore),write('}')) ),
append([[BestScore,H]],L1,L)
)
)
)
),
resetStatus(),
remove(H), write('__out__')
).
what its doing is for the current move get all the other player's moves , "sons of the vertex in the tree" , and for each- check if its a legal move (the column isn't full) ,
if yes, then check outliners ( a win to either or draw),
if not, check if its a leave vertex in the tree, and get the values
if not, go for another round in the next depth for every vertex create more sons,
every move that is calculated is inserted to the "game state" until the value goes up the tree and then its removed
for alphabeta pruning i know you need too add an A, B, parameters to both functions and send the boundaries at every calculation , and every vertex is checked against those to prone the next vertexes
i have this algorithem but i cant implement it to the original above , how shpuld i do it?
evaluate_and_choose([ Move | Moves ], Position, D, Alpha, Beta, Move1, BestMove ) :-
move( Move, Position, Positionl ),
alpha_beta( D, Positionl, Alpha, Beta, MoveX, Value ),
Value1 is -Value,
cutoff( Move, Value1, D, Alpha, Beta, Moves, Position, Move1, BestMove ).
evaluate_and_choose( [], Position, D, Alpha, Beta, Move, ( Move, Alpha )).
alpha_beta( 0, Position, Alpha, Beta, Move, Value ) :-
value( Position, Value ).
alpha_beta( D, Position, Alpha, Beta, Move, Value ) :-
findall( M, move( Position, M ), Moves ),
Alphal is -Beta,
Betal is -Alpha,
D1 is D-l,
evaluate_and_choose( Moves, Position, D1, Alphal, Betal, nil, ( Move, Value )).
cutoff( Move, Value, D, Alpha, Beta, Moves, Position, Movel, ( Move,Value )) :-
Value > Beta.
cutoff(Move, Value, D, Alpha, Beta, Moves, Position, Movel, BestMove ) :-
Alpha < Value, Value < Beta,
evaluate_and_choose( Moves, Position, D, Value, Beta, Move, BestMove ).
cutoff( Move, Value, D, Alpha, Beta, Moves, Position, Movel, BestMove ) :-
Value < Alpha,
evaluate_and_choose( Moves, Position, D, Alpha, Beta, Move1, BestMove ).

Related

WebGL triangle layout for deformation

I am implementing simple deformation in WebGL by moving vertices up or down, but stumbled upon a problem with the way the triangles are laid out.
I am using the PlaneGeometry in three.js and it uses the following layout for the triangles:
indices.push( a, b, d )
indices.push( b, c, d )
The layout used by three.js is on the left. Mine alternates between both.
Moving vertices up or down results in the image on the left, where, after moving the vertex, the deformation looks off. The blue dot represents the center vertex.
I decided to alternate the triangles using the following code:
if ( ( ix + iy ) % 2 === 0 ) {
// Even segment
indices.push( a, b, d )
indices.push( b, c, d )
} else {
// Odd segment
indices.push( a, b, c )
indices.push( a, c, d )
}
As you can see on the right, it gives me a much better result.
The two questions I have are:
Is the layout I used valid and what is its name?
Is there a better better way to solve this problem?

GPU blob bounding box connected component labeling

I have a binary image that will have one or more blobs. I want a list of pixels for each blob. If I can find one seed point for each blob, I can flood fill to find the pixels of the blob.
Doing some research for this problem, I think the algorithm I want is "Connected component labeling." Most examples I see just color code the blobs output. With this algorithm will I be able to gather: one point on the blob, and the axis aligned bounding box of the blob?
Does connected component labeling sound like the right algorithm for what I need? Does anyone have a good CUDA implementation?
Your suggestion is a good starting point.
Scan the image row by row and when you meet a black pixel start flood filling it. While you fill, you can keep the bounding box updated. After filling, you just continue the scan.
Fill(img, x, y, xm, xM, ym, yM):
img[x][y]= white
xm= min(xm, x); xM= max(xM, x); ym= min(ym, y); yM= max(yM, y);
if x >= 0 and img[x-1][y] == black:
Fill(img, x-1, y)
if x < w and img[x+1][y] == black:
Fill(img, x+1, y)
if y >= 0 and img[x][y-1] == black:
Fill(img, x, y-1)
if y < h and img[x][y+1] == black:
Fill(img, x, y+1)
FloodFill(img):
for y in range(h):
for x in range(w):
if Img[x][y] == black:
xm= xM= x; ym= yM= y
Fill(img, x, y, xm, xM, ym, yM)
Store(x, y, xm, xM, ym, yM)
As flood filling is stack-intensive, a scanline-based approach is recommended.

XMVector3Dot performance

When running a performance profiler (VS2017), I find that XMVector3Dot shows up as taking some time (it's part of my code that does collision detection). I find that by replacing the usage of XMVECTOR with XMFLOAT3 and manually calculating a dot product (the same reasoning applies to other vector operations), that the speed of my algorithm is faster. I understand that XMVECTORs are of course needed when suppling the GPU with vectors etc, this is what the GPU understands, but is it expected that when calculating on the CPU that it's faster to manually calculate a dot product with XMFLOAT3s instead of XMVECTORs?
Efficient use of SIMD requires a number of techniques, primarily keeping your computation vectorized for as long as you can. If you have to convert back and forth between vectorized and scalar, the performance benefits of SIMD are lost.
Dot-product takes two vectors and returns a scalar value. To make it easier to keep computations vectorized, XMVector3Dot returns the scalar value 'splatted' across the vector. If you are just extracting one of the components and going back to scalar computations, then your algorithm is likely not well vectorized and you would in fact be better off doing dot product as a scalar operation.
DirectXMath includes a collision header with various tests that follow the SIMD best practices. For example:
inline XMVECTOR PointOnPlaneInsideTriangle(FXMVECTOR P, FXMVECTOR V0, FXMVECTOR V1, GXMVECTOR V2)
{
// Compute the triangle normal.
XMVECTOR N = XMVector3Cross( XMVectorSubtract( V2, V0 ), XMVectorSubtract( V1, V0 ) );
// Compute the cross products of the vector from the base of each edge to
// the point with each edge vector.
XMVECTOR C0 = XMVector3Cross( XMVectorSubtract( P, V0 ), XMVectorSubtract( V1, V0 ) );
XMVECTOR C1 = XMVector3Cross( XMVectorSubtract( P, V1 ), XMVectorSubtract( V2, V1 ) );
XMVECTOR C2 = XMVector3Cross( XMVectorSubtract( P, V2 ), XMVectorSubtract( V0, V2 ) );
// If the cross product points in the same direction as the normal the the
// point is inside the edge (it is zero if is on the edge).
XMVECTOR Zero = XMVectorZero();
XMVECTOR Inside0 = XMVectorGreaterOrEqual( XMVector3Dot( C0, N ), Zero );
XMVECTOR Inside1 = XMVectorGreaterOrEqual( XMVector3Dot( C1, N ), Zero );
XMVECTOR Inside2 = XMVectorGreaterOrEqual( XMVector3Dot( C2, N ), Zero );
// If the point inside all of the edges it is inside.
return XMVectorAndInt( XMVectorAndInt( Inside0, Inside1 ), Inside2 );
}
Instead of doing a scalar conversion an then comparison, it uses vectorized comparisons.
The DirectXMath collision code also avoids dynamic branches. Modern CPUs have a lot of computational power so doing more work without dynamic branches or accessing memory is often faster. For example, here is the sphere-triangle test:
inline bool BoundingSphere::Intersects( FXMVECTOR V0, FXMVECTOR V1, FXMVECTOR V2 ) const
{
// Load the sphere.
XMVECTOR vCenter = XMLoadFloat3( &Center );
XMVECTOR vRadius = XMVectorReplicatePtr( &Radius );
// Compute the plane of the triangle (has to be normalized).
XMVECTOR N = XMVector3Normalize( XMVector3Cross( XMVectorSubtract( V1, V0 ), XMVectorSubtract( V2, V0 ) ) );
// Assert that the triangle is not degenerate.
assert( !XMVector3Equal( N, XMVectorZero() ) );
// Find the nearest feature on the triangle to the sphere.
XMVECTOR Dist = XMVector3Dot( XMVectorSubtract( vCenter, V0 ), N );
// If the center of the sphere is farther from the plane of the triangle than
// the radius of the sphere, then there cannot be an intersection.
XMVECTOR NoIntersection = XMVectorLess( Dist, XMVectorNegate( vRadius ) );
NoIntersection = XMVectorOrInt( NoIntersection, XMVectorGreater( Dist, vRadius ) );
// Project the center of the sphere onto the plane of the triangle.
XMVECTOR Point = XMVectorNegativeMultiplySubtract( N, Dist, vCenter );
// Is it inside all the edges? If so we intersect because the distance
// to the plane is less than the radius.
XMVECTOR Intersection = DirectX::Internal::PointOnPlaneInsideTriangle( Point, V0, V1, V2 );
// Find the nearest point on each edge.
XMVECTOR RadiusSq = XMVectorMultiply( vRadius, vRadius );
// Edge 0,1
Point = DirectX::Internal::PointOnLineSegmentNearestPoint( V0, V1, vCenter );
// If the distance to the center of the sphere to the point is less than
// the radius of the sphere then it must intersect.
Intersection = XMVectorOrInt( Intersection, XMVectorLessOrEqual( XMVector3LengthSq( XMVectorSubtract( vCenter, Point ) ), RadiusSq ) );
// Edge 1,2
Point = DirectX::Internal::PointOnLineSegmentNearestPoint( V1, V2, vCenter );
// If the distance to the center of the sphere to the point is less than
// the radius of the sphere then it must intersect.
Intersection = XMVectorOrInt( Intersection, XMVectorLessOrEqual( XMVector3LengthSq( XMVectorSubtract( vCenter, Point ) ), RadiusSq ) );
// Edge 2,0
Point = DirectX::Internal::PointOnLineSegmentNearestPoint( V2, V0, vCenter );
// If the distance to the center of the sphere to the point is less than
// the radius of the sphere then it must intersect.
Intersection = XMVectorOrInt( Intersection, XMVectorLessOrEqual( XMVector3LengthSq( XMVectorSubtract( vCenter, Point ) ), RadiusSq ) );
return XMVector4EqualInt( XMVectorAndCInt( Intersection, NoIntersection ), XMVectorTrueInt() );
}
For your algorithm, you should either (a) make it fully vectorized or (b) stick with a scalar dot-product.

Implementing alpha beta pruning in Prolog

I'm developing the game Teeko in Prolog and I try to implement alpha beta pruning but I do not know where to start. Could someone please guide me? I have already found the minimax algorithm.
I try to implement alpha beta pruning but I do not know where to start.
Could someone please guide me?
I have already found the minimax algorithm.
The short look into alpha beta pruning algorithm
Choosing a move using minimax with alpha-beta pruning
The new relation scheme is alpha_beta( Depth, Position, Alpha, Beta, Move, Value ),
which extends minimax by replacing the minimax flag with alpha and beta. The same relation holds with respect to evaluate_and_choose.
The program can be generalized by replacing the base case of alpha_beta by a test of whether the position is terminal. This is necessary in chess programs, for example, for handling incomplete piece exchanges.
evaluate_and_choose ( Moves, Position, Depth, Alpha, Beta, Record, BestMove )
Chooses the BestMove from the set of Moves from the current
Position using the minimax algorithm with alpha-beta cutoff searching
Depth ply ahead.
Alpha and Beta are the parameters of the algorithm.
Record records the current best move.
evaluate_and_choose([ Move | Moves ], Position, D, Alpha, Beta, Move1, BestMove ) :-
move( Move, Position, Positionl ),
alpha_beta( D, Positionl, Alpha, Beta, MoveX, Value ),
Value1 is -Value,
cutoff( Move, Value1, D, Alpha, Beta, Moves, Position, Move1, BestMove ).
evaluate_and_choose( [], Position, D, Alpha, Beta, Move, ( Move, Alpha )).
alpha_beta( 0, Position, Alpha, Beta, Move, Value ) :-
value( Position, Value ).
alpha_beta( D, Position, Alpha, Beta, Move, Value ) :-
findall( M, move( Position, M ), Moves ),
Alphal is -Beta,
Betal is -Alpha,
D1 is D-l,
evaluate_and_choose( Moves, Position, D1, Alphal, Betal, nil, ( Move, Value )).
cutoff( Move, Value, D, Alpha, Beta, Moves, Position, Movel, ( Move,Value )) :-
Value > Beta.
cutoff(Move, Value, D, Alpha, Beta, Moves, Position, Movel, BestMove ) :-
Alpha < Value, Value < Beta,
evaluate_and_choose( Moves, Position, D, Value, Beta, Move, BestMove ).
cutoff( Move, Value, D, Alpha, Beta, Moves, Position, Movel, BestMove ) :-
Value < Alpha,
evaluate_and_choose( Moves, Position, D, Alpha, Beta, Move1, BestMove ).

3D variant for summed area table (SAT)

As per Wikipedia:
A summed area table is a data structure and algorithm for quickly and efficiently generating the sum of values in a rectangular subset of a grid.
For a 2D space a summed area table can be generated by iterating x,y over the desired range,
I(x,y) = i(x,y) + I(x-1,y) + I(x,y-1) - I(x-1,y-1)
And the query function for a rectangle corners A(top-left), B(top-right), C(bottom-right), D can be given by:-
I(C) + I(A) - I(B) - I(D)
I want to convert the above to 3D. Also please tell if any other method/data structure available for calculating partial sums in 3D space.
I'm not sure but something like the following can be thought of. ( I haven't gone through the Wikipedia code )
For every coordinate (x,y,z) find the sum of all elements from (0,0,0) to this element.
Call it S(0,0,0 to x,y,z) or S0(x,y,z).
This can be easily built by traversing the 3D matrix once.
S0( x,y,z ) = value[x,y,z] + S0(x-1,y-1,z-1) +
S0( x,y,z-1 ) + S0( x, y-1, z ) + S0( x-1, y, z )
- S0( x-1, y-1, z ) - S0( x, y-1, z-1 ) - S0( x-1, y, z-1 )
(basically element value + S0(x-1,y-1,z-1) + 3 faces (xy,yz,zx) )
Now for every query (x1,y1,z1) to (x2,y2,z2), first convert the coordinates so that x1,y1,z1 is the corner of the cuboid closest to origin and x2,y2,z2 is the corner that is farthest from origin.
S( (x1,y1,z1) to (x2,y2,z2) ) = S0( x2,y2,z2 ) - S0( x2, y2, z1 )
- S0( x2, y1, z2 ) - S0( x1, y2, z2 )
+ S0( x1, y1, z2 ) + S0( x1, y2, z1 ) + S0( x2, y1, z1 )
- S0( x1, y1, z1 )
(subject to corrections)
A bit late to the party, but anyway. There is a general formula for n-dimensional space in Wikipedia, presented in this paper. Following that notation, we assume that you are interested in the volume specified by a rectangular box with corners (x0,y0,z0) and (x1,y1,z1). Then, having an integral image (volume), the coefficients would be:
S((x0,y0,z0) to(x1,y1,z1))
= S(x1,y1,z1) - S(x1,y1,z0) - S(x1,y0,z1) + S(x1,y0,z0) - S(x0,y1,z1) + S(x0,y1,z0) + S(x0,y0,z1) - S(x0,y0,z0)
Here is matlab code I used to calculate them (can specify dimensionality)
%number of dimensions
nDim = 3;
for i=1:2^nDim
str=dec2bin(i-1,nDim);
strout='index combo (';
sum=0;
for n=1:nDim
strout = strcat(strout,str(n));
sum=sum + str2num(str(n));
end
strout = strcat(strout,') sign: ',num2str((-1)^(nDim-sum)));
disp(strout);
end
which outputs:
(000) sign:-1
(001) sign:1
(010) sign:1
(011) sign:-1
(100) sign:1
(101) sign:-1
(110) sign:-1
(111) sign:1

Resources