The beginning of the course we had was Haskell, now the next step after that was prolog. So a simple first lab was to find all possible combinations to travel over a sea (between two islands) and move a goose, a fox and a bag of grain over without the fox eating the goose and the goose eating the grain.

The following laboration was a bit more demanding both in time and in thinking. The result is after the break.

/**
* Relation: abs/2
* Finds the absolute value of X.
* @1: X - The value which we are suppose to calculate absolute value of
* @2: A - The ending value (absolute value of X)
**/
abs(0, 0) :- !.
abs(X, A) :-
    X > 0,
    !, A is X
    ;
    X < 0,
    A is -X.

Simple explanation: If the in value is 0, return 0, or vice versa. Otherwice if X is bigger than 0, return X, if X is below zero, return -X.

Okey, so that is pretty simple, now lets keep on going.

Here’s my utilities.pl. Every method should be pretty self explaining for those who have some basic knowledge about prolog. I’ll however take it step by step, method by method.

:- ensure_loaded('math.pl').

/**
* Relation: sort/10
* Sorts out pieces we are able to flip and pieces we are not able to flip
* @1: player(Color, X, Y) - The player and his coordinates
* @2: Board - The board we are going to sort
* @3: PossibleHorizontalTemp - Temporary possible pieces that are on the horizontal plane
* @4: PH - The end array of possible horizontal pieces
* @5: PossibleVerticalTemp - Temporary possible pieces that are on the vertical plane
* @6: PV - The end array of possible vertical pieces
* @7: PossibleDiagonalTemp - Temporary possible pieces that are on the diagonal plane
* @8: PD - The end array of possible diagonal pieces
* @9: NPT - Temporary array of pieces we are not going to be able to flip
* @10: NP - The end array of pieces we are not able to flip
**/
sort(_, [], PossibleHorizontalTemp, PH, PossibleVerticalTemp, PV, PossibleDiagonalTemp, PD, NPT, NP) :-
    !, PH = PossibleHorizontalTemp, PV = PossibleVerticalTemp, PD = PossibleDiagonalTemp, NP = NPT.

sort(player(Color, X, Y), [ (Player, X, Y1) | Players ], PHT, PH, PVT, PV, PDT, PD, NPT, NP) :-
    !, sort(player(Color, X, Y), Players, PHT, PH, [ (Player, X, Y1) | PVT ], PV, PDT, PD, NPT, NP).

sort(player(Color, X, Y), [ (Player, X1, Y) | Players ], PHT, PH, PVT, PV, PDT, PD, NPT, NP) :-
    !, sort(player(Color, X, Y), Players, [ (Player, X1, Y) | PHT ], PH, PVT, PV, PDT, PD, NPT, NP).

sort(player(Color, X, Y), [ (Player, X1, Y1) | Players ], PHT, PH, PVT, PV, PDT, PD, NPT, NP) :-
    isDiagonal(X, Y, X1, Y1),
    !, sort(player(Color, X, Y), Players, PHT, PH, PVT, PV, [ (Player, X1, Y1) | PDT ], PD, NPT, NP);

    !, sort(player(Color, X, Y), Players, PHT, PH, PVT, PV, PDT, PD, [ (Player, X1, Y1) | NPT ], NP).

So that was the sorting function, it takes the current player, the current player position and the board we want to sort, and returns several different things, the possible pieces in diagonal, in vertical and in horizontal. It also returns the pieces that can’t be flipped.

Next let’s move on to other stuff.

/**
* Relation: isDiagonal/4
* Check if two pieces are diagonal or not
* @1: X1 - X-coordinate of piece 1
* @2: Y1 - Y-coordinate of piece 1
* @3: X2 - X-coordinate of piece 2
* @4: Y2 - Y-coordinate of piece 2
**/
isDiagonal(X1, Y1, X2, Y2) :-
    getX(X1, X1R),
    getX(X2, X2R),
    abs(X2R - X1R, RX),
    abs(Y2 - Y1, RY),
    RX = RY.

The isDiagonal method just checks if two x,y coordinates are diagonal or not. Pretty self explanatory.

The following prolog methods are just some basic methods to switch values, check opponents and switch opponents.

/**
* Relation: get_opponent/2
* Fetches the opponent color for a player
* @1: Player - The color of the player
* @2: Opponent - The Color of the opponent
**/
get_opponent(white, black) :- !.
get_opponent(black, white).

/**
* Relation: xValue/2
* Fetches the above or below value of X
* @1 X - Value of X
* @2 X' - Value of X'
**/
xValue(a,b) :- !.
xValue(b,c) :- !.
xValue(c,d) :- !.
xValue(d,e) :- !.
xValue(e,f) :- !.
xValue(f,g) :- !.
xValue(g,h).

/**
* Relation: yValue/2
* Fetches the above or below value of Y
* @1: Y - Value of Y
* @2: Y' - Value of Y'
**/
yValue(1,2) :- !.
yValue(2,3) :- !.
yValue(3,4) :- !.
yValue(4,5) :- !.
yValue(5,6) :- !.
yValue(6,7) :- !.
yValue(7,8).

/**
* Relation: getX/2
* Gets the number representation of X-coordinate
* @1: X - The X-coordinate
* @2: Value - The value of X as a number
**/
getX(a, 1) :- !.
getX(b, 2) :- !.
getX(c, 3) :- !.
getX(d, 4) :- !.
getX(e, 5) :- !.
getX(f, 6) :- !.
getX(g, 7) :- !.
getX(h, 8).

The bigger part of this assignment was to find the legal moves for a piece in the game, this was done by implementing the “legalmove” method

:- ensure_loaded(['utilities.pl']).

/*
* Relation: legalmove/4
* Checks if a move is legal, or returns legal coordinates
* @1: Color - The color of the player
* @2: Board - The current playboard
* @3: X - The X-coordinate of the move
* @4: Y - The Y-coordinate of the move
*/
legalmove(Color, Board, X, Y) :-
    member(X, [a,b,c,d,e,f,g,h]),
    member(Y, [1,2,3,4,5,6,7,8]),
    \+(member((_, X, Y), Board)),
    walkAndCheck(player(Color, X, Y), Board).

The legalmove parts simply checks if the move is on the board, and that the move diesb’t already exist. After those checks are possible it calls the walkAndCheck method to check if the move flips any pieces.

/*
* Relation: walkAndCheck/2
* Checks where a move is possible, or if a move is legal
* @1: Player - The player as 'player(Color, X, Y)'
* @2: PH/PV/PD - The possible positions of board members.
*/
walkAndCheck(player(Color, X, Y), PH) :- % Right
    xValue(X, NextX),
    member((Player, NextX, Y), PH),
    get_opponent(Color, Player),
    wR(player(Color, NextX, Y), Player, PH), !.

walkAndCheck(player(Color, X, Y), PH) :- % Left
    xValue(NextX, X),
    member((Player, NextX, Y), PH),
    get_opponent(Color, Player),
    wL(player(Color, NextX, Y), Player, PH), !.

walkAndCheck(player(Color, X, Y), PV) :- % Up
    yValue(NextY, Y),
    member((Player, X, NextY), PV),
    get_opponent(Color, Player),
    wU(player(Color, X, NextY), Player, PV), !.

walkAndCheck(player(Color, X, Y), PV) :- % Down
    yValue(Y, NextY),
    member((Player, X, NextY), PV),
    get_opponent(Color, Player),
    wD(player(Color, X, NextY), Player, PV), !.

walkAndCheck(player(Color, X, Y), PD) :- % Right, Down
    xValue(X, NextX),
    yValue(Y, NextY),
    member((Player, NextX, NextY), PD),
    get_opponent(Color, Player),
    wDR(player(Color, NextX, NextY), Player, PD), !.

walkAndCheck(player(Color, X, Y), PD) :- % Right, Up
    xValue(X, NextX),
    yValue(NextY, Y),
    member((Player, NextX, NextY), PD),
    get_opponent(Color, Player),
    wUR(player(Color, NextX, NextY), Player, PD), !.

walkAndCheck(player(Color, X, Y), PD) :- % Left, Down
    xValue(NextX, X),
    yValue(Y, NextY),
    member((Player, NextX, NextY), PD),
    get_opponent(Color, Player),
    wDL(player(Color, NextX, NextY), Player, PD), !.

walkAndCheck(player(Color, X, Y), PD) :- % Left, Up
    xValue(NextX, X),
    yValue(NextY, Y),
    member((Player, NextX, NextY), PD),
    get_opponent(Color, Player),
    wUL(player(Color, NextX, NextY), Player, PD), !.

The walkandcheck method checks all possible directions to see if there exists an oponent directly by the player piece side. If there exists such a piece it tires to walk that way to see if there exists another piece of the players color to switch those between with (O X O => O O O)

The following methods are used to walk one way for another piece of the same color as the player.

/*
* Relation: wR/3
* Checks for a clear 'road' to a chip of the same color (RIGHT)
* @1: Player - The player in standard format
* @2: Color - The color of the last player
* @2: Board - The current board
*/
wR(player(Color, _, _), Color, _) :- !, true.
wR(player(Color, X, Y), _, Board):-
    xValue(X, NextX),
    member((Player, NextX, Y), Board),
    wR(player(Color, NextX, Y), Player, Board).

wR(_, _, _) :- !, false.

/*
* Relation: wL/3
* Checks for a clear 'road' to a chip of the same color (LEFT)
* @1: Player - The player in standard format
* @2: Color - The color of the last player
* @2: Board - The current board
*/
wL(player(Color, _, _), Color, _) :- !, true.
wL(player(Color, X, Y), _, Board) :-
    xValue(NextX, X),
    member((Player, NextX, Y), Board),
    wL(player(Color, NextX, Y), Player, Board).

wL(_, _, _) :- !, false.

/*
* Relation: wU/3
* Checks for a clear 'road' to a chip of the same color (UP)
* @1: Player - The player in standard format
* @2: Color - The color of the last player
* @2: Board - The current board
*/
wU(player(Color, _, _), Color, _) :- !, true.
wU(player(Color, X, Y), _, Board) :-
    yValue(NextY, Y),
    member((Player, X, NextY), Board),
    wU(player(Color, X, NextY), Player, Board).

wU(_, _, _) :- !, false.

/*
* Relation: wD/3
* Checks for a clear 'road' to a chip of the same color (DOWN)
* @1: Player - The player in standard format
* @2: Color - The color of the last player
* @2: Board - The current board
*/
wD(player(Color, _, _), Color, _) :- !, true.
wD(player(Color, X, Y), _, Board) :-
    yValue(Y, NextY),
    member((Player, X, NextY), Board),
    wD(player(Color, X, NextY), Player, Board).

wD(_, _, _) :- !, false.

/*
* Relation: wUR/3
* Checks for a clear 'road' to a chip of the same color (UP RIGHT)
* @1: Player - The player in standard format
* @2: Color - The color of the last player
* @2: Board - The current board
*/
wUR(player(Color, _, _), Color, _) :- !, true.
wUR(player(Color, X, Y), _, Board) :-
    yValue(NextY, Y),
    xValue(X, NextX),
    member((Player, NextX, NextY), Board),
    wUR(player(Color, NextX, NextY), Player, Board), !.

wUR(_, _, _) :- !, false.

/*
* Relation: wDR/3
* Checks for a clear 'road' to a chip of the same color (DOWN RIGHT)
* @1: Player - The player in standard format
* @2: Color - The color of the last player
* @2: Board - The current board
*/
wDR(player(Color, _, _), Color, _) :- !, true.
wDR(player(Color, X, Y), _, Board) :-
    yValue(Y, NextY),
    xValue(X, NextX),
    member((Player, NextX, NextY), Board),
    wDR(player(Color, NextX, NextY), Player, Board), !.

wDR(_, _, _) :- !, false.

/*
* Relation: wUL/3
* Checks for a clear 'road' to a chip of the same color (UP LEFT)
* @1: Player - The player in standard format
* @2: Color - The color of the last player
* @2: Board - The current board
*/
wUL(player(Color, _, _), Color, _) :- !, true.
wUL(player(Color, X, Y), _, Board) :-
    yValue(NextY, Y),
    xValue(NextX, X),
    member((Player, NextX, NextY), Board),
    wUL(player(Color, NextX, NextY), Player, Board), !.

wUL(_, _, _) :- !, false.

/*
* Relation: wDL/3
* Checks for a clear 'road' to a chip of the same color (DOWN LEFT)
* @1: Player - The player in standard format
* @2: Color - The color of the last player
* @2: Board - The current board
*/
wDL(player(Color, _, _), Color, _) :- !, true.
wDL(player(Color, X, Y), _, Board) :-
    yValue(Y, NextY),
    xValue(NextX, X),
    member((Player, NextX, NextY), Board),
    wDL(player(Color, NextX, NextY), Player, Board), !.

wDL(_, _, _) :- !, false.
Next we have the makemove and makemoves methods, these methods use alot of other methods like flatten, addNotAdded, turn, etc. I will not go into detail into these for now cause I simply don’t got the time. I will add a more thurrow review of these later on.

:- ensure_loaded(['utilities.pl', 'findbestmove.pl', 'legalmove.pl']).

/**
* Relation: makemove/5
* Makes a move and returns the new board.
* @1: Color - Player color
* @2: Board - Board that the move is suppose to be for
* @3: X - The X-coordinate of the move
* @4: Y - The Y-coordinate of the move
* @5: NewBoard - The board after the move
**/
makemove(Color, Board, X, Y, NewBoard) :-
    legalmove(Color, Board, X, Y),
    turn(player(Color, X, Y), Board, Turned),
    append(Turned, [(Color, X, Y)], NewBoard).

/**
* Relation: makemoves/5
* Makes N moves and returns a list of moves and the new board.
* @1: Color - Player color
* @2: Board - the board that the moves will be on
* @3: N - Number of moves to make
* @4: Moves - List of moves made
* @5: NewBoard - The new board after N moves
**/
makemoves(Color, Board, N, Moves, NewBoard) :-
    get_opponent(Color, Opponent),
    performNmoves(Color, Opponent, Board, N, [], Moves, NewBoard).

/**
* Relation: performNmoves/7
* Makes N moves, adds (Color, n, n) if a move isn't possible
* @1: Color - Current player color
* @2: Opponent - Color of the opponent
* @3: Board - Current playing board, new for each move
* @4: N - Number of moves to make
* @5: TMoves - Temporary moves array
* @6: Moves - End array of moves
* @7: NewBoard - End board after N moves
**/
performNmoves(_, _, Board, 0, TMoves, Moves, NewBoard) :-
    !, NewBoard = Board,
    Moves = TMoves.

performNmoves(Color, Opponent, Board, N, TMoves, Moves, NewBoard) :-
    N > 0,
    (
          Color = Opponent,
          findbestmove(Color, Board, 1, X, Y),
          makemove(Color, Board, X, Y, NewB),
          Move = [(Color, X, Y)]
    ;
          Color \= Opponent,
          makemove(Color, Board, X, Y, NewB),
          Move = [(Color, X, Y)]
    ;
          \+(legalmove(Color, Board, _, _)),
          Move = [(Color, n, n)]
    ),
    append(TMoves, Move, NewMoves),
    get_opponent(Color, NextPlayer),
    NewN is N - 1,
    performNmoves(NextPlayer, Opponent, NewB, NewN, NewMoves, Moves, NewBoard).

/*
* Relation: flatten/3
* 'Flattens' a list, [[X], [Y]] -> [X, Y]
* @1: List - The list of players we are cutting from
* @2: Temp - The temporary flattened list
* @3: End - The finished flattened list
*/
flatten([], Temp, Temp) :- !.
flatten([ List | Rest ], Temp, End) :-
    append(List, Temp, NewTemp),
    flatten(Rest, NewTemp, End).

/*
* Relation: addNotAdded/4
* Adds chips that are not currently in a list.
* @1: Players - Current players that we want to add to the list, if they
are not already there
* @2: Flippade - Already flipped chips
* @3: Temp - Temporary new list
* @4: New - The new list containing all chips
*/
addNotAdded([], _, Temp, Temp) :- !.
addNotAdded([ (_, X, Y) | Players ], Flippade, Temp, New) :-
    member((_, X, Y), Flippade),
    addNotAdded(Players, Flippade, Temp, New), !.

addNotAdded([ P | Players ], Flippade, Temp, New) :-
    addNotAdded(Players, Flippade, [ P | Temp ], New).

/************************'
* Relation: turn/3
* Turns all possible chips depending on the new move
* @1: Player - The player and the move made
* @2: Board - The old board (before flipping).
* @3: NewBoard - The board after the move
*/
turn(Player, Board, NewBoard) :-
    sort(Player, Board, [], PH, [], PV, [], PD, [], NP),
    findall(Z, getFlipPosHoriz(Player, PH, Z), FlippedHoriz),
    findall(W, getFlipPosVerti(Player, PV, W), FlippedVerti),
    findall(V, getFlipPosDiag(Player, PD, V), FlippedDiag),
    flatten(FlippedHoriz, [], FH),
    flatten(FlippedVerti, [], FV),
    flatten(FlippedDiag, [], FD),
    addNotAdded(PH, FH, FH, T1),
    addNotAdded(PV, FV, FV, T2),
    addNotAdded(PD, FD, FD, T3),
    append(T1, T2, T4),
    append(T4, T3, T5),
    append(T5, NP, NewBoard), !.

/*
* Relation: getFlipHoriz/3
* Finds possible flip positions in the horizontal plane and flips the
possible chips
* @1: Player - The player, as standard.
* @2: PH - Possible chips to flip
* @3: Flipped - List with flipped chips
*/
getFlipPosHoriz(player(Color, X, Y), PH, Flipped) :- % Right
    xValue(X, NextX),
    member((Player, NextX, Y), PH),
    get_opponent(Color, Player),
    walkRight(player(Color, X, Y), Player, PH, [], Flipped)
    ;
    xValue(NextX, X),
    member((Player, NextX, Y), PH),
    get_opponent(Color, Player),
    walkLeft(player(Color, X, Y), Player, PH, [], Flipped).

/*
* Relation: getFlipPosVerti/3
* Finds possible flip positions in the vertical plane and flips the
possible chips
* @1: Player - The player, as standard.
* @2: PV - Possible chips to flip
* @3: Flipped - List with flipped chips
*/
getFlipPosVerti(player(Color, X, Y), PV, Flipped) :- % Up
    yValue(NextY, Y),
    member((Player, X, NextY), PV),
    get_opponent(Color, Player),
    walkUp(player(Color, X, Y), Player, PV, [], Flipped)
    ;
    yValue(Y, NextY),
    member((Player, X, NextY), PV),
    get_opponent(Color, Player),
    walkDown(player(Color, X, Y), Player, PV, [], Flipped).

/*
* Relation: getFlipPosDiag/3
* Finds possible flip positions in the diagonal plane and flips the
possible chips
* @1: Player - The player, as standard.
* @2: PD - Possible chips to flip
* @3: Flipped - List with flipped chips
*/
getFlipPosDiag(player(Color, X, Y), PD, Flipped) :- % Right, Down
    xValue(X, NextX),
    yValue(Y, NextY),
    member((Player, NextX, NextY), PD),
    get_opponent(Color, Player),
    walkDownRight(player(Color, X, Y), Player, PD, [], Flipped)
    ;
    xValue(X, NextX),
    yValue(NextY, Y),
    member((Player, NextX, NextY), PD),
    get_opponent(Color, Player),
    walkUpRight(player(Color, X, Y), Player, PD, [], Flipped)
    ;
    xValue(NextX, X),
    yValue(Y, NextY),
    member((Player, NextX, NextY), PD),
    get_opponent(Color, Player),
    walkDownLeft(player(Color, X, Y), Player, PD, [], Flipped)
    ;
    xValue(NextX, X),
    yValue(NextY, Y),
    member((Player, NextX, NextY), PD),
    get_opponent(Color, Player),
    walkUpLeft(player(Color, X, Y), Player, PD, [], Flipped).

/**
* Relation: walkRight/5
* Tries to walk a path to a chip with the same color as the player,
flips the chips when walking. Either returns true and all flipped chips
or returns false.
* @1: Player - The player and current coordinates
* @2: Color - The current color of the chip
* @3: Board - The board we are checking
* @4: Temp - Temporary flipped chips
* @5: End - The finished flipped chips
*/
walkRight(player(Color, _, _), Color, _, End, End) :- !, true.
walkRight(player(Color, X, Y), _, Board, Temp, End) :-
    xValue(X, NextX),
    member((Player, NextX, Y), Board),
    (   Player \= Color, !, walkRight(player(Color, NextX, Y), Player, Board, [ (Color, NextX, Y) | Temp ], End); !, End = Temp ).

walkRight(_, _, _, _, _) :- !, false.

/**
* Relation: walkLeft/5
* Tries to walk a path to a chip with the same color as the player,
flips the chips when walking. Either returns true and all flipped chips
or returns false.
* @1: Player - The player and current coordinates
* @2: Color - The current color of the chip
* @3: Board - The board we are checking
* @4: Temp - Temporary flipped chips
* @5: End - The finished flipped chips
*/
walkLeft(player(Color, _, _), Color, _, End, End) :- !, true.
walkLeft(player(Color, X, Y), _, Board, Temp, End) :-
    xValue(NextX, X),
    member((Player, NextX, Y), Board),
    (   Player \= Color, !, walkLeft(player(Color, NextX, Y), Player, Board, [ (Color, NextX, Y) | Temp ], End); !, End = Temp ).

walkLeft(_, _, _, _, _) :- !, false.

/**
* Relation: walkUp/5
* Tries to walk a path to a chip with the same color as the player,
flips the chips when walking. Either returns true and all flipped chips
or returns false.
* @1: Player - The player and current coordinates
* @2: Color - The current color of the chip
* @3: Board - The board we are checking
* @4: Temp - Temporary flipped chips
* @5: End - The finished flipped chips
*/

walkUp(player(Color, _, _), Color, _, End, End) :- !, true.
walkUp(player(Color, X, Y), _, Board, Temp, End) :-
    yValue(NextY, Y),
    member((Player, X, NextY), Board),
    (   Player \= Color, !, walkUp(player(Color, X, NextY), Player, Board, [ (Color, X, NextY) | Temp ], End); !, End = Temp ).

walkUp(_, _, _, _, _) :- !, false.

/**
* Relation: walkDown/5
* Tries to walk a path to a chip with the same color as the player,
flips the chips when walking. Either returns true and all flipped chips
or returns false.
* @1: Player - The player and current coordinates
* @2: Color - The current color of the chip
* @3: Board - The board we are checking
* @4: Temp - Temporary flipped chips
* @5: End - The finished flipped chips
*/

walkDown(player(Color, _, _), Color, _, End, End) :- !, true.
walkDown(player(Color, X, Y), _, Board, Temp, End) :-
    yValue(Y, NextY),
    member((Player, X, NextY), Board),
    (   Player \= Color, !, walkDown(player(Color, X, NextY), Player, Board, [ (Color, X, NextY) | Temp ], End); !, End = Temp ).

walkDown(_, _, _, _, _) :- !, false.

/**
* Relation: walkUpRight/5
* Tries to walk a path to a chip with the same color as the player,
flips the chips when walking. Either returns true and all flipped chips
or returns false.
* @1: Player - The player and current coordinates
* @2: Color - The current color of the chip
* @3: Board - The board we are checking
* @4: Temp - Temporary flipped chips
* @5: End - The finished flipped chips
*/

walkUpRight(player(Color, _, _), Color, _, End, End) :- !, true.
walkUpRight(player(Color, X, Y), _, Board, Temp, End) :-
    yValue(NextY, Y),
    xValue(X, NextX),
    member((Player, NextX, NextY), Board),
    (   Player \= Color, !, walkUpRight(player(Color, NextX, NextY), Player, Board, [ (Color, NextX, NextY) | Temp ], End); !, End = Temp ).

walkUpRight(_, _, _, _, _) :- !, false.

/**
* Relation: walkDownRight/5
* Tries to walk a path to a chip with the same color as the player,
flips the chips when walking. Either returns true and all flipped chips
or returns false.
* @1: Player - The player and current coordinates
* @2: Color - The current color of the chip
* @3: Board - The board we are checking
* @4: Temp - Temporary flipped chips
* @5: End - The finished flipped chips
*/

walkDownRight(player(Color, _, _), Color, _, End, End) :- !, true.
walkDownRight(player(Color, X, Y), _, Board, Temp, End) :-
    yValue(Y, NextY),
    xValue(X, NextX),
    member((Player, NextX, NextY), Board),
    (   Player \= Color, !, walkDownRight(player(Color, NextX, NextY), Player, Board, [ (Color, NextX, NextY) | Temp ], End); !, End = Temp ).

walkDownRight(_, _, _, _, _) :- !, false.

/**
* Relation: walkDownLeft/5
* Tries to walk a path to a chip with the same color as the player,
flips the chips when walking. Either returns true and all flipped chips
or returns false.
* @1: Player - The player and current coordinates
* @2: Color - The current color of the chip
* @3: Board - The board we are checking
* @4: Temp - Temporary flipped chips
* @5: End - The finished flipped chips
*/

walkDownLeft(player(Color, _, _), Color, _, End, End) :- !, true.
walkDownLeft(player(Color, X, Y), _, Board, Temp, End) :-
    yValue(Y, NextY),
    xValue(NextX, X),
    member((Player, NextX, NextY), Board),
    (   Player \= Color, !, walkDownLeft(player(Color, NextX, NextY), Player, Board, [ (Color, NextX, NextY) | Temp ], End); !, End = Temp ).

walkDownLeft(_, _, _, _, _) :- !, false.

/**
* Relation: walkUpLeft/5
* Tries to walk a path to a chip with the same color as the player,
flips the chips when walking. Either returns true and all flipped chips
or returns false.
* @1: Player - The player and current coordinates
* @2: Color - The current color of the chip
* @3: Board - The board we are checking
* @4: Temp - Temporary flipped chips
* @5: End - The finished flipped chips
*/

walkUpLeft(player(Color, _, _), Color, _, End, End) :- !, true.
walkUpLeft(player(Color, X, Y), _, Board, Temp, End) :-
    yValue(NextY, Y),
    xValue(NextX, X),
    member((Player, NextX, NextY), Board),
    (   Player \= Color, !, walkUpLeft(player(Color, NextX, NextY), Player, Board, [ (Color, NextX, NextY) | Temp ], End); !, End = Temp ).

walkUpLeft(_, _, _, _, _) :- !, false.

so makeMove makes the move desired or finds a move and a new board.

Next on is the findbestmove which simply finds the most optimal move for a player depending on the desired depth for the calculations and the current board.

:- ensure_loaded(['makemove.pl', 'valueof.pl']).

/**
* Relation: findbestmove/5
* Finds the best move with depth N.
* @1: Color - The color of supposed move player
* @2: Board - The board for which the move is gonna take place
* @3: N - The depth of the calculation, number of moves.
* @4: X - The X coordinate of the best move
* @5: Y - The Y coordinate of the best move
**/
findbestmove(Color, Board, N, X, Y) :-
    findall((A, B, V), (
               makemoves(Color, Board, N, [ (_, A, B) | _ ], NewBoard),
               valueof(Color, NewBoard, V)),
        Bag),
    findbest(Bag, 0, pos(X, Y)).

/**
* Relation: findbest/3
* Finds the best X-/Y-coordinate
* @1: Moves - The moves and their values (X, Y, Value)
* @2: best(X, Y, Value) - The best current value and it's coordinates best(X, Y, Value)
* @3: Position - The end position that is the best of all, pos(X, Y)
**/
findbest([], best(X, Y, _), Best) :-
    !, Best = pos(X, Y).

findbest([(X, Y, V) | Tail], 0, Best) :-
    !, findbest(Tail, best(X, Y, V), Best).

findbest([(X, Y, V) | Tail], best(X1, Y1, BV), Best) :-
    (   V > BV,
        !, findbest(Tail, best(X, Y, V), Best)
    ;
        !, findbest(Tail, best(X1, Y1, BV), Best)
    ).

In the uploaded code package there is also two other files, one file containing the board printing method and one containing the testbench for the described prolog implementation of othello. You are free to use and distribute this code as you want, I only demand some recognition, link back to this blog is the only credit I ask for. All codes on this blog is released under the GNU license (http://www.gnu.org/licenses/gpl.html).

Downloads

Download Othello D7012E Lab4 Solution