Skip to content

Instantly share code, notes, and snippets.

@mb2532
Last active December 21, 2020 07:23
Show Gist options
  • Save mb2532/c5179e14e4bc3c891b32828834821ff4 to your computer and use it in GitHub Desktop.
Save mb2532/c5179e14e4bc3c891b32828834821ff4 to your computer and use it in GitHub Desktop.
//Top Level AI Compute Module:
//gamestate bits: 00 = empty, 01 = AI move, 10 = user move
module connectFourAI(
input [83:0] gameState,
output [3:0] aiMove,
output [4:0] maxConnectOut,
input clk, reset
);
wire [3:0] move [7:0];
wire [4:0] foundMax [7:0];
wire [83:0] nextState [6:0];
wire disable_column [6:0];
wire [3:0] trapMove [7:0];
//Instantiate 7 genStateFromColumns to create 7 new gameState values for an AI move in each column
genStateFromColumn genMove0(
.column (4'd0),
.gameState (gameState),
.player (2'b01),
.nextState (nextState[0]),
.disable_column (disable_column[0])
);
genStateFromColumn genMove1(
.column (4'd1),
.gameState (gameState),
.player (2'b01),
.nextState (nextState[1]),
.disable_column (disable_column[1])
);
genStateFromColumn genMove2(
.column (4'd2),
.gameState (gameState),
.player (2'b01),
.nextState (nextState[2]),
.disable_column (disable_column[2])
);
genStateFromColumn genMove3(
.column (4'd3),
.gameState (gameState),
.player (2'b01),
.nextState (nextState[3]),
.disable_column (disable_column[3])
);
genStateFromColumn genMove4(
.column (4'd4),
.gameState (gameState),
.player (2'b01),
.nextState (nextState[4]),
.disable_column (disable_column[4])
);
genStateFromColumn genMove5(
.column (4'd5),
.gameState (gameState),
.player (2'b01),
.nextState (nextState[5]),
.disable_column (disable_column[5])
);
genStateFromColumn genMove6(
.column (4'd6),
.gameState (gameState),
.player (2'b01),
.nextState (nextState[6]),
.disable_column (disable_column[6])
);
//instantiate 7 moveDeterminers to compute a heuristic value for each of the new gameStates
moveDeterminer findImmediateMove(
.gameState (gameState),
.clk (clk),
.disable_column (1'b0),
.player (2'b01),
.foundMax (foundMax[7]),
.move (move[7])
);
moveDeterminer findMove0(
.gameState (nextState[0]),
.clk (clk),
.disable_column (disable_column[0]),
.player (2'b10),
.foundMax (foundMax[0]),
.move (move[0])
);
moveDeterminer findMove1(
.gameState (nextState[1]),
.clk (clk),
.disable_column (disable_column[1]),
.player (2'b10),
.foundMax (foundMax[1]),
.move (move[1])
);
moveDeterminer findMove2(
.gameState (nextState[2]),
.clk (clk),
.disable_column (disable_column[2]),
.player (2'b10),
.foundMax (foundMax[2]),
.move (move[2])
);
moveDeterminer findMove3(
.gameState (nextState[3]),
.clk (clk),
.disable_column (disable_column[3]),
.player (2'b10),
.foundMax (foundMax[3]),
.move (move[3])
);
moveDeterminer findMove4(
.gameState (nextState[4]),
.clk (clk),
.disable_column (disable_column[4]),
.player (2'b10),
.foundMax (foundMax[4]),
.move (move[4])
);
moveDeterminer findMove5(
.gameState (nextState[5]),
.clk (clk),
.disable_column (disable_column[5]),
.player (2'b10),
.foundMax (foundMax[5]),
.move (move[5])
);
moveDeterminer findMove6(
.gameState (nextState[6]),
.clk (clk),
.disable_column (disable_column[6]),
.player (2'b10),
.foundMax (foundMax[6]),
.move (move[6])
);
//find the minimum of the moveDeterminer max output values
wire [4:0] min;
findMinimum minFinder(
.in0 (foundMax[0]),
.in1 (foundMax[1]),
.in2 (foundMax[2]),
.in3 (foundMax[3]),
.in4 (foundMax[4]),
.in5 (foundMax[5]),
.in6 (foundMax[6]),
.out (min)
);
//instantiate seven trap determiners to look for 2-move-ahead traps in parallel with move determiners
trapDeterminer trap0(
.gameState (nextState[0]),
.player (2'b01),
.clk (clk),
.disable_column (disable_column[0]),
.move (trapMove[0])
);
trapDeterminer trap1(
.gameState (nextState[1]),
.player (2'b01),
.clk (clk),
.disable_column (disable_column[1]),
.move (trapMove[1])
);
trapDeterminer trap2(
.gameState (nextState[2]),
.player (2'b01),
.clk (clk),
.disable_column (disable_column[2]),
.move (trapMove[2])
);
trapDeterminer trap3(
.gameState (nextState[3]),
.player (2'b01),
.clk (clk),
.disable_column (disable_column[3]),
.move (trapMove[3])
);
trapDeterminer trap4(
.gameState (nextState[4]),
.player (2'b01),
.clk (clk),
.disable_column (disable_column[4]),
.move (trapMove[4])
);
trapDeterminer trap5(
.gameState (nextState[5]),
.player (2'b01),
.clk (clk),
.disable_column (disable_column[5]),
.move (trapMove[5])
);
trapDeterminer trap6(
.gameState (nextState[6]),
.player (2'b01),
.clk (clk),
.disable_column (disable_column[6]),
.move (trapMove[6])
);
//AI Out Logic
wire [3:0] minMove;
wire [3:0] trapMoveFlag;
wire allFull;
//check if the board is full
assign allFull = (foundMax[0] == 5'd31) && (foundMax[1] == 5'd31) && (foundMax[2] == 5'd31) && (foundMax[3] == 5'd31) && (foundMax[4] == 5'd31) && (foundMax[5] == 5'd31) && (foundMax[6] == 5'd31);
//check to see if a trap has been detected, if so assign flag value of that move column, if not assign to value of 7; if multiple, prioritize middle columns
assign trapMoveFlag = (trapMove[3] != 4'd7 ? 4'd3 : (trapMove[2] != 4'd7 ? 4'd2 : (trapMove[4] != 4'd7 ? 4'd4 : (trapMove[5] != 4'd7 ? 4'd5 : (trapMove[1] != 4'd7 ? 4'd1 : (trapMove[6] != 4'd7 ? 4'd6 : 4'd7))))));
//assign to best move column as determined by moveDeterminers
assign minMove = (min==foundMax[3]? 4'd3 :(min==foundMax[2]? 4'd2 :(min==foundMax[4]? 4'd4 :(min==foundMax[1]? 4'd1 :(min==foundMax[5]? 4'd5:(min==foundMax[0]? 4'd0 : 4'd6))))));
//assign AI module output move, if a priority check or only one space left, assign to output of moveDeterminer 7, if not, check for trap moves, if not, assign to minMove
assign aiMove = (foundMax[7]>=15 || (allFull == 1'b1)) ? move[7] : ((trapMoveFlag != 4'd7 && foundMax[trapMoveFlag] < 5'd15)? trapMoveFlag : minMove);
//assign to value of max heuristic
assign maxConnectOut = (foundMax[7]>=5'd15 || (allFull == 1'b1)) ? foundMax[7] : min;
endmodule
//moveDeterminer module: outputs heuristic maximum value and corresponding move given gameState
module moveDeterminer(
input [83:0] gameState,
input [1:0] player,
input clk, disable_column,
output [4:0] foundMax,
output [3:0] move
);
wire [13:0] row0;
wire [13:0] row1;
wire [13:0] row2;
wire [13:0] row3;
wire [13:0] row4;
wire [13:0] row5;
assign row0 = gameState[13:0];
assign row1 = gameState[27:14];
assign row2 = gameState[41:28];
assign row3 = gameState[55:42];
assign row4 = gameState[69:56];
assign row5 = gameState[83:70];
wire [4:0] maxConnect [6:0];
//instantiate seven maxConnectFinder modules, one for each possible play
maxConnectFinder col0(
.clk (clk),
.player (player),
.row0 (row0),
.row1 (row1),
.row2 (row2),
.row3 (row3),
.row4 (row4),
.row5 (row5),
.moveColumn (4'd0),
.maxConnect (maxConnect[0])
);
maxConnectFinder col1(
.clk (clk),
.player (player),
.row0 (row0),
.row1 (row1),
.row2 (row2),
.row3 (row3),
.row4 (row4),
.row5 (row5),
.moveColumn (4'd1),
.maxConnect (maxConnect[1])
);
maxConnectFinder col2(
.clk (clk),
.player (player),
.row0 (row0),
.row1 (row1),
.row2 (row2),
.row3 (row3),
.row4 (row4),
.row5 (row5),
.moveColumn (4'd2),
.maxConnect (maxConnect[2])
);
maxConnectFinder col3(
.clk (clk),
.player (player),
.row0 (row0),
.row1 (row1),
.row2 (row2),
.row3 (row3),
.row4 (row4),
.row5 (row5),
.moveColumn (4'd3),
.maxConnect (maxConnect[3])
);
maxConnectFinder col4(
.clk (clk),
.player (player),
.row0 (row0),
.row1 (row1),
.row2 (row2),
.row3 (row3),
.row4 (row4),
.row5 (row5),
.moveColumn (4'd4),
.maxConnect (maxConnect[4])
);
maxConnectFinder col5(
.clk (clk),
.player (player),
.row0 (row0),
.row1 (row1),
.row2 (row2),
.row3 (row3),
.row4 (row4),
.row5 (row5),
.moveColumn (4'd5),
.maxConnect (maxConnect[5])
);
maxConnectFinder col6(
.clk (clk),
.player (player),
.row0 (row0),
.row1 (row1),
.row2 (row2),
.row3 (row3),
.row4 (row4),
.row5 (row5),
.moveColumn (4'd6),
.maxConnect (maxConnect[6])
);
//take the maximum value of the seven maxConnectFinders
wire [4:0] foundMax_temp;
findMaximum findmax(
.in0 (maxConnect[0]),
.in1 (maxConnect[1]),
.in2 (maxConnect[2]),
.in3 (maxConnect[3]),
.in4 (maxConnect[4]),
.in5 (maxConnect[5]),
.in6 (maxConnect[6]),
.out (foundMax_temp)
);
//if the column is disabled, assign to either max or min value depending on if AI or human, if not assign to maximum heuristic value
assign foundMax = (disable_column == 1'b1) ? (player == 2'b10 ? 5'd31 : 5'd0) : foundMax_temp;
//assign move to corresponding column
assign move = (foundMax==maxConnect[3]? 4'd3 : (foundMax==maxConnect[2]? 4'd2 : (foundMax==maxConnect[4]? 4'd4 : (foundMax==maxConnect[1]? 4'd1 : (foundMax==maxConnect[5]? 4'd5 : (foundMax==maxConnect[0]? 4'd0 : 4'd6))))));
endmodule
//trapDeterminer module: look ahead to see if an AI win is possible after a human player block of an immediate AI win
module trapDeterminer(
input [83:0] gameState,
input [1:0] player,
input clk, disable_column,
output [3:0] move
);
wire [13:0] row0;
wire [13:0] row1;
wire [13:0] row2;
wire [13:0] row3;
wire [13:0] row4;
wire [13:0] row5;
wire [13:0] row0N;
wire [13:0] row1N;
wire [13:0] row2N;
wire [13:0] row3N;
wire [13:0] row4N;
wire [13:0] row5N;
assign row0 = gameState[13:0];
assign row1 = gameState[27:14];
assign row2 = gameState[41:28];
assign row3 = gameState[55:42];
assign row4 = gameState[69:56];
assign row5 = gameState[83:70];
wire selfWin [6:0];
//instantiate seven winFinders to look for an immediate AI win that the human player will block
winFinder win0(
.clk (clk),
.row0 (row0),
.row1 (row1),
.row2 (row2),
.row3 (row3),
.row4 (row4),
.row5 (row5),
.moveColumn (4'd0),
.selfWin (selfWin[0])
);
winFinder win1(
.clk (clk),
.row0 (row0),
.row1 (row1),
.row2 (row2),
.row3 (row3),
.row4 (row4),
.row5 (row5),
.moveColumn (4'd1),
.selfWin (selfWin[1])
);
winFinder win2(
.clk (clk),
.row0 (row0),
.row1 (row1),
.row2 (row2),
.row3 (row3),
.row4 (row4),
.row5 (row5),
.moveColumn (4'd2),
.selfWin (selfWin[2])
);
winFinder win3(
.clk (clk),
.row0 (row0),
.row1 (row1),
.row2 (row2),
.row3 (row3),
.row4 (row4),
.row5 (row5),
.moveColumn (4'd3),
.selfWin (selfWin[3])
);
winFinder win4(
.clk (clk),
.row0 (row0),
.row1 (row1),
.row2 (row2),
.row3 (row3),
.row4 (row4),
.row5 (row5),
.moveColumn (4'd4),
.selfWin (selfWin[4])
);
winFinder win5(
.clk (clk),
.row0 (row0),
.row1 (row1),
.row2 (row2),
.row3 (row3),
.row4 (row4),
.row5 (row5),
.moveColumn (4'd5),
.selfWin (selfWin[5])
);
winFinder win6(
.clk (clk),
.row0 (row0),
.row1 (row1),
.row2 (row2),
.row3 (row3),
.row4 (row4),
.row5 (row5),
.moveColumn (4'd6),
.selfWin (selfWin[6])
);
//assign user move to column of AI win, otherwise assign to 7
wire [3:0] userMove;
assign userMove = (disable_column == 1'b1 ? 4'd7 : (selfWin[3]==1'b1 ? 4'd3 : (selfWin[2] == 1'b1 ? 4'd2 : (selfWin[4] == 1'b1 ? 4'd4 : (selfWin[1] == 1'b1 ? 4'd1 : (selfWin[5] == 1'b1 ? 4'd5 : (selfWin[0] == 1'b1 ? 4'd0 : (selfWin[6] == 1'b1 ? 4'd6 : 4'd7))))))));
//generate a new gameState from predicted user move
wire [83:0] trapState ;
wire tempDisable;
genStateFromColumn genTrapMove(
.column (userMove),
.gameState (gameState),
.player (2'b10),
.nextState (trapState),
.disable_column (tempDisable)
);
assign row0N = trapState[13:0];
assign row1N = trapState[27:14];
assign row2N = trapState[41:28];
assign row3N = trapState[55:42];
assign row4N = trapState[69:56];
assign row5N = trapState[83:70];
//instantiate seven more winFinders to look for a subsequent AI win
wire selfWinN [6:0];
winFinder win0N(
.clk (clk),
.row0 (row0N),
.row1 (row1N),
.row2 (row2N),
.row3 (row3N),
.row4 (row4N),
.row5 (row5N),
.moveColumn (4'd0),
.selfWin (selfWinN[0])
);
winFinder win1N(
.clk (clk),
.row0 (row0N),
.row1 (row1N),
.row2 (row2N),
.row3 (row3N),
.row4 (row4N),
.row5 (row5N),
.moveColumn (4'd1),
.selfWin (selfWinN[1])
);
winFinder win2N(
.clk (clk),
.row0 (row0N),
.row1 (row1N),
.row2 (row2N),
.row3 (row3N),
.row4 (row4N),
.row5 (row5N),
.moveColumn (4'd2),
.selfWin (selfWinN[2])
);
winFinder win3N(
.clk (clk),
.row0 (row0N),
.row1 (row1N),
.row2 (row2N),
.row3 (row3N),
.row4 (row4N),
.row5 (row5N),
.moveColumn (4'd3),
.selfWin (selfWinN[3])
);
winFinder win4N(
.clk (clk),
.row0 (row0N),
.row1 (row1N),
.row2 (row2N),
.row3 (row3N),
.row4 (row4N),
.row5 (row5N),
.moveColumn (4'd4),
.selfWin (selfWinN[4])
);
winFinder win5N(
.clk (clk),
.row0 (row0N),
.row1 (row1N),
.row2 (row2N),
.row3 (row3N),
.row4 (row4N),
.row5 (row5N),
.moveColumn (4'd5),
.selfWin (selfWinN[5])
);
winFinder win6N(
.clk (clk),
.row0 (row0N),
.row1 (row1N),
.row2 (row2N),
.row3 (row3N),
.row4 (row4N),
.row5 (row5N),
.moveColumn (4'd6),
.selfWin (selfWinN[6])
);
//output user move if any of the new winFinders outputs a 1, otherwise output a 7
assign move = (tempDisable == 1'b1) ? 4'd7 : (selfWinN[0] == 1'b1 || selfWinN[1] == 1'b1 || selfWinN[2] == 1'b1 || selfWinN[3] == 1'b1 || selfWinN[4] == 1'b1 || selfWinN[5] == 1'b1 || selfWinN[6] == 1'b1) ? userMove : 4'd7;
endmodule
//winFinder module: used to look for an AI win in gameState
module winFinder(
input [13:0] row0, row1, row2, row3, row4, row5,
input [3:0] moveColumn,
//input [3:0] moveRow,
input clk,
output selfWin
);
wire [13:0] rowArray [5:0];
assign rowArray[0] = row0;
assign rowArray[1] = row1;
assign rowArray[2] = row2;
assign rowArray[3] = row3;
assign rowArray[4] = row4;
assign rowArray[5] = row5;
//assign moveRow to the row number of the next open slot in moveColumn
wire [3:0] moveRow;
assign moveRow = (row0[moveColumn<<1] + row0[(moveColumn<<1)+1] + row1[moveColumn<<1] + row1[(moveColumn<<1)+1] + row2[moveColumn<<1] + row2[(moveColumn<<1)+1] + row3[moveColumn<<1] + row3[(moveColumn<<1)+1] + row4[moveColumn<<1] + row4[(moveColumn<<1)+1] + row5[moveColumn<<1] + row5[(moveColumn<<1)+1]);
reg [3:0] upLeftSelf;
wire [3:0] upLeftSelfWire;
reg [3:0] upRightSelf;
wire [3:0] upRightSelfWire;
reg [3:0] leftSelf;
wire [3:0] leftSelfWire;
reg [3:0] rightSelf;
wire [3:0] rightSelfWire;
reg [3:0] botSelf;
wire [3:0] botSelfWire;
reg [3:0] botRightSelf;
wire [3:0] botRightSelfWire;
reg [3:0] botLeftSelf;
wire [3:0] botLeftSelfWire;
assign botSelfWire = botSelf;
assign botLeftSelfWire = botLeftSelf;
assign botRightSelfWire = botRightSelf;
assign leftSelfWire = leftSelf;
assign rightSelfWire = rightSelf;
assign upLeftSelfWire = upLeftSelf;
assign upRightSelfWire = upRightSelf;
//check for split diagonals in AI tokens
wire crossCheckSelf;
assign crossCheckSelf = ((upLeftSelfWire+botRightSelfWire)>=4'd4 || (upRightSelfWire+botLeftSelfWire)>=4'd4 || (leftSelfWire+rightSelfWire)>=4'd4) ? 1'b1 : 1'b0;
// assign win flag a 1 if there are any three-in-a-rows next to an empty slot
assign selfWin = (botSelfWire==4'd10 || botLeftSelfWire==4'd10 || botRightSelfWire==4'd10 || leftSelfWire==4'd10 || rightSelfWire==4'd10 || upLeftSelfWire == 4'd10 || upRightSelfWire ==4'd10 || crossCheckSelf==1'b1) ? 1'b1 : 1'b0;
always @(*) begin
//bottom check
if(moveRow == 0) botSelf = 4'd0;
else if((moveRow != 0) && (rowArray[moveRow-1][(moveColumn<<1)] == 1'b1)) begin //check 1 under
if (moveRow - 1 != 0 && rowArray[moveRow-2][(moveColumn<<1)] == 1'b1) begin //check 2 under
if (moveRow - 2 != 0 && rowArray[moveRow-3][(moveColumn<<1)] == 1'b1) begin //check 3 under
botSelf = 4'd10;
end
else botSelf = 4'd3;
end
else botSelf = 4'd1;
end
else botSelf = 4'd0;
//bottom left check
if(moveRow == 0) botLeftSelf = 4'd0;
else if(moveRow != 0 && moveColumn != 0 && rowArray[moveRow-1][((moveColumn-1)<<1)] == 1'b1) begin //check 1 under
if (moveRow - 1 != 0 && moveColumn - 1 != 0 && rowArray[moveRow-2][((moveColumn-2)<<1)] == 1'b1) begin //check 2 under
if (moveRow - 2 != 0 && moveColumn - 2 != 0 && rowArray[moveRow-3][((moveColumn-3)<<1)] == 1'b1) begin //check 3 under
botLeftSelf = 4'd10;
end
else botLeftSelf = 4'd3;
end
else botLeftSelf = 4'd1;
end
else botLeftSelf = 4'd0;
//bottom right check
if(moveRow == 0) botRightSelf = 4'd0;
else if(moveRow != 0 && moveColumn != 6 && rowArray[moveRow-1][((moveColumn+1)<<1)] == 1'b1) begin //check 1 under
if (moveRow - 1 != 0 && moveColumn + 1 != 6 && rowArray[moveRow-2][((moveColumn+2)<<1)] == 1'b1) begin //check 2 under
if (moveRow - 2 != 0 && moveColumn + 2 != 6 && rowArray[moveRow-3][((moveColumn+3)<<1)] == 1'b1) begin //check 3 under
botRightSelf = 4'd10;
end
else botRightSelf = 4'd3;
end
else botRightSelf = 4'd1;
end
else botRightSelf = 4'd0;
//left check
if(moveColumn == 0) leftSelf = 0;
else if(moveColumn != 0 && rowArray[moveRow][((moveColumn-1)<<1)] == 1'b1) begin //check 1 under
if (moveColumn - 1 != 0 && rowArray[moveRow][((moveColumn-2)<<1)] == 1'b1) begin //check 2 under
if (moveColumn - 2 != 0 && rowArray[moveRow][((moveColumn-3)<<1)] == 1'b1) begin //check 3 under
leftSelf = 4'd10;
end
else leftSelf = 4'd3;
end
else leftSelf = 4'd1;
end
else leftSelf = 4'd0;
//right check
if(moveColumn == 6) rightSelf = 0;
else if(moveColumn != 6 && rowArray[moveRow][((moveColumn+1)<<1)] == 1'b1) begin //check 1 under
if (moveColumn + 1 != 6 && rowArray[moveRow][((moveColumn+2)<<1)] == 1'b1) begin //check 2 under
if (moveColumn + 2 != 6 && rowArray[moveRow][((moveColumn+3)<<1)] == 1'b1) begin //check 3 under
rightSelf = 4'd10;
end
else rightSelf = 4'd3;
end
else rightSelf = 4'd1;
end
else rightSelf = 4'd0;
//upper left check
if(moveColumn == 0) upLeftSelf = 0;
else if(moveColumn != 0 && moveRow != 5 && rowArray[moveRow+1][((moveColumn-1)<<1)] == 1'b1) begin //check 1 under
if (moveColumn - 1 != 0 && moveRow + 1 != 5 && rowArray[moveRow+2][((moveColumn-2)<<1)] == 1'b1) begin //check 2 under
if (moveColumn - 2 != 0 && moveRow + 2 != 5 && rowArray[moveRow+3][((moveColumn-3)<<1)] == 1'b1) begin //check 3 under
upLeftSelf = 4'd10;
end
else upLeftSelf = 4'd3;
end
else upLeftSelf = 4'd1;
end
else upLeftSelf = 4'd0;
//upper right check
if(moveColumn == 6) upRightSelf = 0;
else if(moveColumn != 6 && moveRow != 5 && rowArray[moveRow+1][((moveColumn+1)<<1)] == 1'b1) begin //check 1 under
if (moveColumn + 1 != 6 && moveRow + 1 != 5 && rowArray[moveRow+2][((moveColumn+2)<<1)] == 1'b1) begin //check 2 under
if (moveColumn + 2 != 6 && moveRow + 2 != 5 && rowArray[moveRow+3][((moveColumn+3)<<1)] == 1'b1) begin //check 3 under
upRightSelf = 4'd10;
end
else upRightSelf = 4'd3;
end
else upRightSelf = 4'd1;
end
else upRightSelf = 4'd0;
end //end always
endmodule
//maxConnectFinder module: output heuristic value for a given game state and move column
module maxConnectFinder(
input [13:0] row0, row1, row2, row3, row4, row5,
input [3:0] moveColumn,
input [1:0] player,
//input [3:0] moveRow,
input clk,
output [4:0] maxConnect
);
wire [13:0] rowArray [5:0];
assign rowArray[0] = row0;
assign rowArray[1] = row1;
assign rowArray[2] = row2;
assign rowArray[3] = row3;
assign rowArray[4] = row4;
assign rowArray[5] = row5;
//assign moveRow to the row number of the next open slot in moveColumn
wire [3:0] moveRow;
assign moveRow = (row0[moveColumn<<1'b1] + row0[(moveColumn<<1)+1'b1] + row1[moveColumn<<1'b1] + row1[(moveColumn<<1'b1)+1'b1] + row2[moveColumn<<1'b1] + row2[(moveColumn<<1'b1)+1'b1] + row3[moveColumn<<1'b1] + row3[(moveColumn<<1'b1)+1'b1] + row4[moveColumn<<1'b1] + row4[(moveColumn<<1'b1)+1'b1] + row5[moveColumn<<1'b1] + row5[(moveColumn<<1'b1)+1'b1]);
reg [3:0] upLeftSelf;
wire [3:0] upLeftSelfWire;
reg [3:0] upRightSelf;
wire [3:0] upRightSelfWire;
reg [3:0] leftSelf;
wire [3:0] leftSelfWire;
reg [3:0] rightSelf;
wire [3:0] rightSelfWire;
reg [3:0] botSelf;
wire [3:0] botSelfWire;
reg [3:0] botRightSelf;
wire [3:0] botRightSelfWire;
reg [3:0] botLeftSelf;
wire [3:0] botLeftSelfWire;
reg [3:0] upLeft;
wire [3:0] upLeftWire;
reg [3:0] upRight;
wire [3:0] upRightWire;
reg [3:0] left;
wire [3:0] leftWire;
reg [3:0] right;
wire [3:0] rightWire;
reg [3:0] bot;
wire [3:0] botWire;
reg [3:0] botRight;
wire [3:0] botRightWire;
reg [3:0] botLeft;
wire [3:0] botLeftWire;
wire selfWinWire;
assign botSelfWire = botSelf;
assign botLeftSelfWire = botLeftSelf;
assign botRightSelfWire = botRightSelf;
assign leftSelfWire = leftSelf;
assign rightSelfWire = rightSelf;
assign upLeftSelfWire = upLeftSelf;
assign upRightSelfWire = upRightSelf;
assign botWire = bot;
assign botLeftWire = botLeft;
assign botRightWire = botRight;
assign leftWire = left;
assign rightWire = right;
assign upLeftWire = upLeft;
assign upRightWire = upRight;
wire [4:0] crossCheck /* synthesis keep */;
wire crossCheckSelf;
//check for split diagonals in AI tokens
assign crossCheckSelf = ((upLeftSelfWire+botRightSelfWire)>=4'd4 || (upRightSelfWire+botLeftSelfWire)>=4'd4 || (leftSelfWire+rightSelfWire)>=4'd4) ? 1'b1 : 1'b0;
//assign self win a 1 if there are any three-in-a-row AI token strings next to an empty slot
assign selfWinWire = (botSelfWire==4'd10 || botLeftSelfWire==4'd10 || botRightSelfWire==4'd10 || leftSelfWire==4'd10 || rightSelfWire==4'd10 || upLeftSelfWire == 4'd10 || upRightSelfWire ==4'd10 || crossCheckSelf==1'b1) ? 1'b1 : 1'b0;
//check for split diagonals in human player tokens
assign crossCheck = ((upLeftWire+botRightWire) >= 4'd6 || (upRightWire+botLeftWire) >= 4'd6 || (leftWire+rightWire) >= 4'd6) ? 5'd10 : (((upLeftWire+botRightWire) == 4'd2 || (upRightWire+botLeftWire) == 4'd2 || (leftWire+rightWire) == 4'd2) ? 5'd3 : 5'd0); //NOTE: will add 10 if already 3 in a row, most likely benign
wire [4:0] tempSum;
//sum up weighted values for each direction
assign tempSum = botWire + botLeftWire + botRightWire + leftWire + rightWire + upLeftWire + upRightWire + crossCheck;
//assign max heuristic value
assign maxConnect = (moveRow < 4'd6) ? ((selfWinWire == 1'b1 && tempSum < 4'd15) ? (player == 2'b01 ? 5'd30 : 5'd14) :tempSum) : (player == 2'b01 ? 5'd0 : 5'd31);
always @(*) begin
///////////////////////////////////////////CHECK OPPONENT MOVES/////////////////////////////////////////////////////
//bottom check
if(moveRow == 4'd0) bot = 4'd0;
else if((moveRow != 4'd0) && (rowArray[moveRow - 4'd1][(moveColumn<<1) + 4'd1] == 1'b1)) begin //check 1 under
if (((moveRow - 4'd1) != 4'd0) && (rowArray[moveRow - 4'd2][(moveColumn<<1) + 4'd1] == 1'b1)) begin //check 2 under
if (((moveRow - 4'd2) != 4'd0) && (rowArray[moveRow - 4'd3][(moveColumn<<1) + 4'd1] == 1'b1)) begin //check 3 under
bot = 4'd15;
end
else bot = 4'd5;
end
else bot = 4'd1;
end
else bot = 4'd0;
//bottom left check
if(moveRow == 4'd0) botLeft = 4'd0;
else if((moveRow != 4'd0) && (moveColumn != 4'd0) && (rowArray[moveRow - 4'd1][((moveColumn - 4'd1)<<1) + 4'd1] == 1'b1)) begin //check 1 under
if (((moveRow - 4'd1) != 4'd0) && ((moveColumn - 4'd1) != 4'd0) && (rowArray[moveRow - 4'd2][((moveColumn - 4'd2)<<1)+ 4'd1] == 1'b1)) begin //check 2 under
if (((moveRow - 4'd2) != 4'd0) && ((moveColumn - 4'd2) != 4'd0) && (rowArray[moveRow - 4'd3][((moveColumn - 4'd3)<<1) + 4'd1] == 1'b1)) begin //check 3 under
botLeft = 4'd10;
end
else botLeft = 4'd5;
end
else begin
if ((moveColumn > 4'd2) && (moveRow > 4'd2) && (rowArray[moveRow - 4'd2][((moveColumn - 4'd2)<<1) + 4'd1] == 1'b0) && (rowArray[moveRow - 4'd2][((moveColumn - 4'd2)<<1)] == 1'b0) && (rowArray[moveRow - 4'd3][((moveColumn - 4'd3)<<1) + 4'd1] == 1'b1)) botLeft = 4'd5;
else botLeft = 4'd1;
end
end
else botLeft = 4'd0;
//bottom right check
if(moveRow == 4'd0) botRight = 4'd0;
else if((moveRow != 4'd0) && (moveColumn != 4'd6) && (rowArray[moveRow - 4'd1][((moveColumn + 4'd1)<<1) + 4'd1] == 1'b1)) begin //check 1 under
if (((moveRow - 4'd1) != 4'd0) && ((moveColumn + 4'd1) != 4'd6) && (rowArray[moveRow - 4'd2][((moveColumn + 4'd2)<<1) + 4'd1] == 1'b1)) begin //check 2 under
if (((moveRow - 4'd2) != 4'd0) && ((moveColumn + 4'd2) != 4'd6) && (rowArray[moveRow - 4'd3][((moveColumn + 4'd3)<<1) + 4'd1] == 1'b1)) begin //check 3 under
botRight = 4'd10;
end
else botRight = 4'd5;
end
else begin
if (((moveColumn + 4'd2) < 4'd6) && (moveRow > 4'd2) && (rowArray[moveRow - 4'd2][((moveColumn + 4'd2)<<1) + 4'd1] == 1'b0) && (rowArray[moveRow - 4'd2][((moveColumn + 4'd2)<<1)] == 1'b0) && (rowArray[moveRow - 4'd3][((moveColumn + 4'd3)<<1) + 4'd1] == 1'b1)) botRight = 4'd5;
else botRight = 4'd1;
end
end
else botRight = 4'd0;
//left check
if(moveColumn == 4'd0) left = 4'd0;
else if((moveColumn != 4'd0) && (rowArray[moveRow][((moveColumn - 4'd1)<<1) + 4'd1] == 1'b1)) begin //check 1 under
if (((moveColumn - 4'd1) != 4'd0) && (rowArray[moveRow][((moveColumn - 4'd2)<<1) + 4'd1] == 1'b1)) begin //check 2 under
if (((moveColumn - 4'd2) != 4'd0) && (rowArray[moveRow][((moveColumn - 4'd3)<<1) + 4'd1] == 1'b1)) begin //check 3 under
left = 4'd10;
end
else left = 4'd5;
end
else begin
if ((moveColumn > 4'd2) && (rowArray[moveRow][((moveColumn - 4'd2)<<1) + 4'd1] == 1'b0) && (rowArray[moveRow][((moveColumn - 4'd2)<<1)] == 1'b0) && (rowArray[moveRow][((moveColumn - 4'd3)<<1) + 4'd1] == 1'b1)) left = 4'd5;
else left = 4'd1;
end
end
else left = 4'd0;
//right check
if(moveColumn == 4'd6) right = 4'd0;
else if((moveColumn != 4'd6) && (rowArray[moveRow][((moveColumn+1)<<1)+1] == 1'b1)) begin //check 1 under
if (((moveColumn + 4'd1) != 4'd6) && (rowArray[moveRow][((moveColumn + 4'd2)<<1) + 4'd1] == 1'b1)) begin //check 2 under
if (((moveColumn + 4'd2) != 4'd6) && (rowArray[moveRow][((moveColumn + 4'd3)<<1) + 4'd1] == 1'b1)) begin //check 3 under
right = 4'd10;
end
else right = 4'd5;
end
else begin
if (((moveColumn + 4'd2) < 4'd6) && (rowArray[moveRow][((moveColumn + 4'd2)<<1) + 4'd1] == 1'b0) && (rowArray[moveRow][((moveColumn + 4'd2)<<1)] == 1'b0) && (rowArray[moveRow][((moveColumn + 4'd3)<<1) + 4'd1] == 1'b1)) right = 4'd5;
else right = 4'd1;
end
end
else right = 4'd0;
//upper left check
if(moveColumn == 0) upLeft = 4'd0;
else if((moveColumn != 4'd0) && (moveRow != 4'd5) && (rowArray[moveRow + 4'd1][((moveColumn - 4'd1)<<1) + 4'd1] == 1'b1)) begin //check 1 under
if (((moveColumn - 4'd1) != 4'd0) && ((moveRow + 4'd1) != 4'd5) && (rowArray[moveRow + 4'd2][((moveColumn - 4'd2)<<1) + 4'd1] == 1'b1)) begin //check 2 under
if (((moveColumn - 4'd2) != 4'd0) && ((moveRow + 4'd2) != 4'd5) && (rowArray[moveRow + 4'd3][((moveColumn - 4'd3)<<1) + 4'd1] == 1'b1)) begin //check 3 under
upLeft = 4'd10;
end
else upLeft = 4'd5;
end
else begin
if ((moveColumn > 4'd2) && ((moveRow + 4'd2) < 4'd5) && (rowArray[moveRow + 4'd2][((moveColumn - 4'd2)<<1) + 4'd1] == 1'b0) && (rowArray[moveRow + 4'd2][((moveColumn - 4'd2)<<1)] == 1'b0) && (rowArray[moveRow + 4'd3][((moveColumn - 4'd3)<<1) + 4'd1] == 1'b1)) upLeft = 4'd5;
else upLeft = 4'd1;
end
end
else upLeft = 4'd0;
//upper right check
if(moveColumn == 6) upRight = 4'd0;
else if((moveColumn != 4'd6) && (moveRow != 4'd5) && (rowArray[moveRow+1][((moveColumn+1)<<1)+1] == 1'b1)) begin //check 1 under
if (((moveColumn + 4'd1) != 4'd6) && ((moveRow + 4'd1) != 4'd5) && (rowArray[moveRow + 4'd2][((moveColumn + 4'd2)<<1) + 4'd1] == 1'b1)) begin //check 2 under
if (((moveColumn + 4'd2) != 4'd6) && ((moveRow + 4'd2) != 4'd5) && (rowArray[moveRow + 4'd3][((moveColumn + 4'd3)<<1) + 4'd1] == 1'b1)) begin //check 3 under
upRight = 4'd10;
end
else upRight = 4'd5;
end
else begin
if (((moveColumn + 4'd2) < 4'd6) && ((moveRow + 4'd2) < 4'd5) && (rowArray[moveRow + 4'd2][((moveColumn + 4'd2)<<1) + 4'd1] == 1'b0) && (rowArray[moveRow + 4'd2][((moveColumn + 4'd2)<<1)] == 1'b0) && (rowArray[moveRow + 4'd3][((moveColumn +4'd3)<<1) + 4'd1] == 1'b1)) upRight = 4'd5;
else upRight = 4'd1;
end
end
else upRight = 4'd0;
////////////////////////////////////////////////CHECK SELF WIN/////////////////////////////////////////////////////////////////
//bottom check
if(moveRow == 0) botSelf = 4'd0;
else if((moveRow != 0) && (rowArray[moveRow-1][(moveColumn<<1)] == 1'b1)) begin //check 1 under
if (moveRow - 1 != 0 && rowArray[moveRow-2][(moveColumn<<1)] == 1'b1) begin //check 2 under
if (moveRow - 2 != 0 && rowArray[moveRow-3][(moveColumn<<1)] == 1'b1) begin //check 3 under
botSelf = 4'd10;
end
else botSelf = 4'd3;
end
else botSelf = 4'd1;
end
else botSelf = 4'd0;
//bottom left check
if(moveRow == 0) botLeftSelf = 4'd0;
else if(moveRow != 0 && moveColumn != 0 && rowArray[moveRow-1][((moveColumn-1)<<1)] == 1'b1) begin //check 1 under
if (moveRow - 1 != 0 && moveColumn - 1 != 0 && rowArray[moveRow-2][((moveColumn-2)<<1)] == 1'b1) begin //check 2 under
if (moveRow - 2 != 0 && moveColumn - 2 != 0 && rowArray[moveRow-3][((moveColumn-3)<<1)] == 1'b1) begin //check 3 under
botLeftSelf = 4'd10;
end
else botLeftSelf = 4'd3;
end
else botLeftSelf = 4'd1;
end
else botLeftSelf = 4'd0;
//bottom right check
if(moveRow == 0) botRightSelf = 4'd0;
else if(moveRow != 0 && moveColumn != 6 && rowArray[moveRow-1][((moveColumn+1)<<1)] == 1'b1) begin //check 1 under
if (moveRow - 1 != 0 && moveColumn + 1 != 6 && rowArray[moveRow-2][((moveColumn+2)<<1)] == 1'b1) begin //check 2 under
if (moveRow - 2 != 0 && moveColumn + 2 != 6 && rowArray[moveRow-3][((moveColumn+3)<<1)] == 1'b1) begin //check 3 under
botRightSelf = 4'd10;
end
else botRightSelf = 4'd3;
end
else botRightSelf = 4'd1;
end
else botRightSelf = 4'd0;
//left check
if(moveColumn == 0) leftSelf = 0;
else if(moveColumn != 0 && rowArray[moveRow][((moveColumn-1)<<1)] == 1'b1) begin //check 1 under
if (moveColumn - 1 != 0 && rowArray[moveRow][((moveColumn-2)<<1)] == 1'b1) begin //check 2 under
if (moveColumn - 2 != 0 && rowArray[moveRow][((moveColumn-3)<<1)] == 1'b1) begin //check 3 under
leftSelf = 4'd10;
end
else leftSelf = 4'd3;
end
else leftSelf = 4'd1;
end
else leftSelf = 4'd0;
//right check
if(moveColumn == 6) rightSelf = 0;
else if(moveColumn != 6 && rowArray[moveRow][((moveColumn+1)<<1)] == 1'b1) begin //check 1 under
if (moveColumn + 1 != 6 && rowArray[moveRow][((moveColumn+2)<<1)] == 1'b1) begin //check 2 under
if (moveColumn + 2 != 6 && rowArray[moveRow][((moveColumn+3)<<1)] == 1'b1) begin //check 3 under
rightSelf = 4'd10;
end
else rightSelf = 4'd3;
end
else rightSelf = 4'd1;
end
else rightSelf = 4'd0;
//upper left check
if(moveColumn == 0) upLeftSelf = 0;
else if(moveColumn != 0 && moveRow != 5 && rowArray[moveRow+1][((moveColumn-1)<<1)] == 1'b1) begin //check 1 under
if (moveColumn - 1 != 0 && moveRow + 1 != 5 && rowArray[moveRow+2][((moveColumn-2)<<1)] == 1'b1) begin //check 2 under
if (moveColumn - 2 != 0 && moveRow + 2 != 5 && rowArray[moveRow+3][((moveColumn-3)<<1)] == 1'b1) begin //check 3 under
upLeftSelf = 4'd10;
end
else upLeftSelf = 4'd3;
end
else upLeftSelf = 4'd1;
end
else upLeftSelf = 4'd0;
//upper right check
if(moveColumn == 6) upRightSelf = 0;
else if(moveColumn != 6 && moveRow != 5 && rowArray[moveRow+1][((moveColumn+1)<<1)] == 1'b1) begin //check 1 under
if (moveColumn + 1 != 6 && moveRow + 1 != 5 && rowArray[moveRow+2][((moveColumn+2)<<1)] == 1'b1) begin //check 2 under
if (moveColumn + 2 != 6 && moveRow + 2 != 5 && rowArray[moveRow+3][((moveColumn+3)<<1)] == 1'b1) begin //check 3 under
upRightSelf = 4'd10;
end
else upRightSelf = 4'd3;
end
else upRightSelf = 4'd1;
end
else upRightSelf = 4'd0;
end //end always
endmodule
//module to output the max value given 7 inputs
module findMaximum(
input [4:0] in0, in1, in2, in3, in4, in5, in6,
output [4:0] out
);
wire [4:0] comp1;
wire [4:0] comp2;
wire [4:0] comp3;
wire [4:0] comp4;
wire [4:0] comp5;
assign comp1 = (in0==5'd31) ? in1 : ((in1==5'd31) ? in0 : ((in0>in1) ? in0 : in1));
assign comp2 = (in2==5'd31) ? in3 : ((in3==5'd31) ? in2 : ((in2>in3) ? in2 : in3));
assign comp3 = (in4==5'd31) ? in5 : ((in5==5'd31) ? in4 : ((in4>in5) ? in4 : in5));
assign comp4 = (comp1==5'd31) ? comp2 : ((comp2==5'd31) ? comp1 : ((comp1>comp2) ? comp1 : comp2));
assign comp5 = (comp4==5'd31) ? comp3 : ((comp3==5'd31) ? comp4 : ((comp4>comp3) ? comp4 : comp3));
assign out = (comp5==5'd31) ? in6 : ((in6==5'd31) ? comp5 : ((comp5>in6) ? comp5 : in6));
endmodule
//module to output the min value given 7 inputs
module findMinimum(
input [4:0] in0, in1, in2, in3, in4, in5, in6,
output [4:0] out
);
wire [4:0] comp1;
wire [4:0] comp2;
wire [4:0] comp3;
wire [4:0] comp4;
wire [4:0] comp5;
assign comp1 = (in0<in1)?in0:in1;
assign comp2 = (in2<in3)?in2:in3;
assign comp3 = (in4<in5)?in4:in5;
assign comp4 = (comp1<comp2)?comp1:comp2;
assign comp5 = (comp4<comp3)?comp4:comp3;
assign out = (comp5<in6)?comp5:in6;
endmodule
//generate an 84-bit game state given the current game state and a new move
module genStateFromColumn(
input [3:0] column,
input [83:0] gameState,
input [1:0] player,
output [83:0] nextState,
output disable_column
);
wire [13:0] row0;
wire [13:0] row1;
wire [13:0] row2;
wire [13:0] row3;
wire [13:0] row4;
wire [13:0] row5;
wire [13:0] rowArray [5:0];
assign row0 = gameState[13:0];
assign rowArray[0] = row0;
assign row1 = gameState[27:14];
assign rowArray[1] = row1;
assign row2 = gameState[41:28];
assign rowArray[2] = row2;
assign row3 = gameState[55:42];
assign rowArray[3] = row3;
assign row4 = gameState[69:56];
assign rowArray[4] = row4;
assign row5 = gameState[83:70];
assign rowArray[5] = row5;
wire [3:0] moveRow;
assign moveRow = (row0[column<<1] + row0[(column<<1)+1] + row1[column<<1] + row1[(column<<1)+1] + row2[column<<1] + row2[(column<<1)+1] + row3[column<<1] + row3[(column<<1)+1] + row4[column<<1] + row4[(column<<1)+1] + row5[column<<1] + row5[(column<<1)+1]);
assign disable_column = (moveRow >= 4'd6) ? 1'b1 : 1'b0;
wire [3:0] exponent;
assign exponent = (column<<1) + player - 4'd1;
wire [13:0] newRow;
assign newRow = rowArray[moveRow] + (14'd1 << exponent);
assign nextState[13:0] = (moveRow==4'd0) ? newRow : row0;
assign nextState[27:14] = (moveRow==4'd1) ? newRow : row1;
assign nextState[41:28] = (moveRow==4'd2) ? newRow : row2;
assign nextState[55:42] = (moveRow==4'd3) ? newRow : row3;
assign nextState[69:56] = (moveRow==4'd4) ? newRow : row4;
assign nextState[83:70] = (moveRow==4'd5) ? newRow : row5;
endmodule
/*
module RAM_512_18(
output reg signed [17:0] q,
input signed [17:0] data,
input [8:0] wraddress, rdaddress,
input wren, rden, clock
);
reg [8:0] read_address_reg;
reg signed [17:0] mem [511:0];
reg rden_reg;
always @ (posedge clock)
begin
if (wren)
mem[wraddress] <= data;
end
always @ (posedge clock) begin
if (rden_reg)
q <= mem[read_address_reg];
read_address_reg <= rdaddress;
rden_reg <= rden;
end
endmodule
*/
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment