├── .gitattributes ├── README.md ├── report ├── Project报告.pdf └── README.md ├── screenshot ├── black-wins.jpg ├── draw.jpg ├── game-running.jpg └── white-wins.jpg └── src ├── clock └── clk_divider.v ├── data ├── gobang_datapath.v └── testbench │ └── gobang_datapath_tb.v ├── display ├── display_pics.v ├── vga_display.v └── vga_sync.v ├── gobang_top.v ├── input ├── ps2_input.v ├── ps2_scan.v └── testbench │ └── ps2_scan_tb.v ├── logic ├── gobang_logic.v ├── gobang_patterns.v ├── gobang_strategy.v ├── score_calculator.v └── win_checker.v └── random └── random_generator.v /.gitattributes: -------------------------------------------------------------------------------- 1 | *.v linguist-language=verilog -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Verilog-Gobang-Game-with-AI 2 | This is my project for the course "Logic and Computer Design Fundamentals"(LCDF, course instructor: SQS) in Zhejiang University. 3 | 4 | It is a gobang game for one or two players which can be played using the Kintex-7 FPGA Board, a VGA monitor and a PS/2 keyboard. The players can play with each other or play with AI or watch the game between two AI. A greedy strategy is used to implement the AI of the game. 5 | 6 | If you are intrested, you can read my project report (in Chinese) for more details. 7 | 8 | game-running.jpg 9 | 10 | ^ The game is running. 11 | 12 | black-wins.jpg 13 | 14 | ^ Black wins the game 15 | 16 | white-wins.jpg 17 | 18 | ^ White wins the game 19 | 20 | draw.jpg 21 | 22 | ^ It's a draw 23 | -------------------------------------------------------------------------------- /report/Project报告.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tsreaper/verilog-gobang-game-with-ai/82478150edce899de7589b3bbcb7e759f8f89cab/report/Project报告.pdf -------------------------------------------------------------------------------- /report/README.md: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tsreaper/verilog-gobang-game-with-ai/82478150edce899de7589b3bbcb7e759f8f89cab/report/README.md -------------------------------------------------------------------------------- /screenshot/black-wins.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tsreaper/verilog-gobang-game-with-ai/82478150edce899de7589b3bbcb7e759f8f89cab/screenshot/black-wins.jpg -------------------------------------------------------------------------------- /screenshot/draw.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tsreaper/verilog-gobang-game-with-ai/82478150edce899de7589b3bbcb7e759f8f89cab/screenshot/draw.jpg -------------------------------------------------------------------------------- /screenshot/game-running.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tsreaper/verilog-gobang-game-with-ai/82478150edce899de7589b3bbcb7e759f8f89cab/screenshot/game-running.jpg -------------------------------------------------------------------------------- /screenshot/white-wins.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tsreaper/verilog-gobang-game-with-ai/82478150edce899de7589b3bbcb7e759f8f89cab/screenshot/white-wins.jpg -------------------------------------------------------------------------------- /src/clock/clk_divider.v: -------------------------------------------------------------------------------- 1 | `timescale 1ns / 1ps 2 | 3 | //------------------------------------------------------------------------------ 4 | // Clock division module 5 | //------------------------------------------------------------------------------ 6 | module clk_divider( 7 | input wire clk, // Clock 8 | input wire rst, // Reset 9 | output reg [31:0] clk_div // Division result 10 | ); 11 | 12 | always @ (posedge clk or negedge rst) 13 | if (!rst) 14 | clk_div <= 32'b0; 15 | else 16 | clk_div <= clk_div + 1; 17 | 18 | endmodule 19 | -------------------------------------------------------------------------------- /src/data/gobang_datapath.v: -------------------------------------------------------------------------------- 1 | `timescale 1ns / 1ps 2 | 3 | //------------------------------------------------------------------------------ 4 | // Stores the data of the chessboard 5 | //------------------------------------------------------------------------------ 6 | module gobang_datapath( 7 | input wire clk, // Clock 8 | input wire rst, // Reset 9 | input wire clr, // Clear 10 | 11 | input wire write, // Enable-write signal 12 | input wire [3:0] write_i, // The position to write information 13 | input wire [3:0] write_j, 14 | input wire write_color, // The color to write in 15 | 16 | input wire [3:0] logic_i, // Row needed by logic 17 | input wire [3:0] display_i, // Row needed by display 18 | input wire [3:0] consider_i, // Row considered by strategy/checker 19 | input wire [3:0] consider_j, // Column considered by s/c 20 | 21 | output wire [14:0] logic_row, // Row information for logic 22 | output wire [14:0] display_black, // Row information for display 23 | output wire [14:0] display_white, 24 | output reg [8:0] black_i, // Row information for s/c 25 | output reg [8:0] black_j, // Column information for s/c 26 | output reg [8:0] black_ij, // Main diagonal information for s/c 27 | output reg [8:0] black_ji, // Counter diagonal information for s/c 28 | output reg [8:0] white_i, 29 | output reg [8:0] white_j, 30 | output reg [8:0] white_ij, 31 | output reg [8:0] white_ji 32 | ); 33 | 34 | // Side parameters 35 | localparam BLACK = 1'b0, 36 | WHITE = 1'b1; 37 | 38 | // Chessboard parameters 39 | localparam BOARD_SIZE = 15; 40 | 41 | // RAMs, store the information of the black/white chess 42 | reg [14:0] board_black [14:0]; 43 | reg [14:0] board_white [14:0]; 44 | 45 | // Helper registers to fetch information from RAM 46 | integer i, j; 47 | reg [14:0] row_4b, row_3b, row_2b, row_1b, row0b, 48 | row1b, row2b, row3b, row4b; 49 | reg [14:0] row_4w, row_3w, row_2w, row_1w, row0w, 50 | row1w, row2w, row3w, row4w; 51 | 52 | // Generate the output 53 | assign logic_row = board_black[logic_i] | board_white[logic_i]; 54 | assign display_black = board_black[display_i]; 55 | assign display_white = board_white[display_i]; 56 | 57 | always @ (negedge clk or negedge rst) begin 58 | if (!rst || clr) begin 59 | board_black[0] <= 15'b0; 60 | board_black[1] <= 15'b0; 61 | board_black[2] <= 15'b0; 62 | board_black[3] <= 15'b0; 63 | board_black[4] <= 15'b0; 64 | board_black[5] <= 15'b0; 65 | board_black[6] <= 15'b0; 66 | board_black[7] <= 15'b0; 67 | board_black[8] <= 15'b0; 68 | board_black[9] <= 15'b0; 69 | board_black[10] <= 15'b0; 70 | board_black[11] <= 15'b0; 71 | board_black[12] <= 15'b0; 72 | board_black[13] <= 15'b0; 73 | board_black[14] <= 15'b0; 74 | 75 | board_white[0] <= 15'b0; 76 | board_white[1] <= 15'b0; 77 | board_white[2] <= 15'b0; 78 | board_white[3] <= 15'b0; 79 | board_white[4] <= 15'b0; 80 | board_white[5] <= 15'b0; 81 | board_white[6] <= 15'b0; 82 | board_white[7] <= 15'b0; 83 | board_white[8] <= 15'b0; 84 | board_white[9] <= 15'b0; 85 | board_white[10] <= 15'b0; 86 | board_white[11] <= 15'b0; 87 | board_white[12] <= 15'b0; 88 | board_white[13] <= 15'b0; 89 | board_white[14] <= 15'b0; 90 | end 91 | else if (write) 92 | if (write_color == BLACK) 93 | board_black[write_i] <= board_black[write_i] | 94 | (15'b1 << write_j); 95 | else 96 | board_white[write_i] <= board_white[write_i] | 97 | (15'b1 << write_j); 98 | end 99 | 100 | always @ (*) begin 101 | i = consider_i; 102 | j = consider_j; 103 | 104 | // Fetch the data of the rows from i-4 to i+4 105 | if (i - 4 >= 0) begin 106 | row_4b = board_black[i - 4]; 107 | row_4w = board_white[i - 4]; 108 | end 109 | else begin 110 | row_4b = 15'b0; 111 | row_4w = 15'b0; 112 | end 113 | 114 | if (i - 3 >= 0) begin 115 | row_3b = board_black[i - 3]; 116 | row_3w = board_white[i - 3]; 117 | end 118 | else begin 119 | row_3b = 15'b0; 120 | row_3w = 15'b0; 121 | end 122 | 123 | if (i - 2 >= 0) begin 124 | row_2b = board_black[i - 2]; 125 | row_2w = board_white[i - 2]; 126 | end 127 | else begin 128 | row_2b = 15'b0; 129 | row_2w = 15'b0; 130 | end 131 | 132 | if (i - 1 >= 0) begin 133 | row_1b = board_black[i - 1]; 134 | row_1w = board_white[i - 1]; 135 | end 136 | else begin 137 | row_1b = 15'b0; 138 | row_1w = 15'b0; 139 | end 140 | 141 | if (i >= 0 && i < BOARD_SIZE) begin 142 | row0b = board_black[i]; 143 | row0w = board_white[i]; 144 | end 145 | else begin 146 | row0b = 15'b0; 147 | row0w = 15'b0; 148 | end 149 | 150 | if (i + 1 < BOARD_SIZE) begin 151 | row1b = board_black[i + 1]; 152 | row1w = board_white[i + 1]; 153 | end 154 | else begin 155 | row1b = 15'b0; 156 | row1w = 15'b0; 157 | end 158 | 159 | if (i + 2 < BOARD_SIZE) begin 160 | row2b = board_black[i + 2]; 161 | row2w = board_white[i + 2]; 162 | end 163 | else begin 164 | row2b = 15'b0; 165 | row2w = 15'b0; 166 | end 167 | 168 | if (i + 3 < BOARD_SIZE) begin 169 | row3b = board_black[i + 3]; 170 | row3w = board_white[i + 3]; 171 | end 172 | else begin 173 | row3b = 15'b0; 174 | row3w = 15'b0; 175 | end 176 | 177 | if (i + 4 < BOARD_SIZE) begin 178 | row4b = board_black[i + 4]; 179 | row4w = board_white[i + 4]; 180 | end 181 | else begin 182 | row4b = 15'b0; 183 | row4w = 15'b0; 184 | end 185 | 186 | // Write the data of each grid to the output 187 | if (j - 4 >= 0) begin 188 | black_i[0] = row0b[j - 4]; 189 | white_i[0] = row0w[j - 4]; 190 | black_ij[0] = row_4b[j - 4]; 191 | white_ij[0] = row_4w[j - 4]; 192 | black_ji[0] = row4b[j - 4]; 193 | white_ji[0] = row4w[j - 4]; 194 | end 195 | else begin 196 | black_i[0] = 1'b0; 197 | white_i[0] = 1'b0; 198 | black_ij[0] = 1'b0; 199 | white_ij[0] = 1'b0; 200 | black_ji[0] = 1'b0; 201 | white_ji[0] = 1'b0; 202 | end 203 | 204 | if (j - 3 >= 0) begin 205 | black_i[1] = row0b[j - 3]; 206 | white_i[1] = row0w[j - 3]; 207 | black_ij[1] = row_3b[j - 3]; 208 | white_ij[1] = row_3w[j - 3]; 209 | black_ji[1] = row3b[j - 3]; 210 | white_ji[1] = row3w[j - 3]; 211 | end 212 | else begin 213 | black_i[1] = 1'b0; 214 | white_i[1] = 1'b0; 215 | black_ij[1] = 1'b0; 216 | white_ij[1] = 1'b0; 217 | black_ji[1] = 1'b0; 218 | white_ji[1] = 1'b0; 219 | end 220 | 221 | if (j - 2 >= 0) begin 222 | black_i[2] = row0b[j - 2]; 223 | white_i[2] = row0w[j - 2]; 224 | black_ij[2] = row_2b[j - 2]; 225 | white_ij[2] = row_2w[j - 2]; 226 | black_ji[2] = row2b[j - 2]; 227 | white_ji[2] = row2w[j - 2]; 228 | end 229 | else begin 230 | black_i[2] = 1'b0; 231 | white_i[2] = 1'b0; 232 | black_ij[2] = 1'b0; 233 | white_ij[2] = 1'b0; 234 | black_ji[2] = 1'b0; 235 | white_ji[2] = 1'b0; 236 | end 237 | 238 | if (j - 1 >= 0) begin 239 | black_i[3] = row0b[j - 1]; 240 | white_i[3] = row0w[j - 1]; 241 | black_ij[3] = row_1b[j - 1]; 242 | white_ij[3] = row_1w[j - 1]; 243 | black_ji[3] = row1b[j - 1]; 244 | white_ji[3] = row1w[j - 1]; 245 | end 246 | else begin 247 | black_i[3] = 1'b0; 248 | white_i[3] = 1'b0; 249 | black_ij[3] = 1'b0; 250 | white_ij[3] = 1'b0; 251 | black_ji[3] = 1'b0; 252 | white_ji[3] = 1'b0; 253 | end 254 | 255 | if (j >= 0 && j < BOARD_SIZE) begin 256 | black_i[4] = row0b[j]; 257 | white_i[4] = row0w[j]; 258 | black_ij[4] = row0b[j]; 259 | white_ij[4] = row0w[j]; 260 | black_ji[4] = row0b[j]; 261 | white_ji[4] = row0w[j]; 262 | 263 | black_j[0] = row_4b[j]; 264 | black_j[1] = row_3b[j]; 265 | black_j[2] = row_2b[j]; 266 | black_j[3] = row_1b[j]; 267 | black_j[4] = row0b[j]; 268 | black_j[5] = row1b[j]; 269 | black_j[6] = row2b[j]; 270 | black_j[7] = row3b[j]; 271 | black_j[8] = row4b[j]; 272 | white_j[0] = row_4w[j]; 273 | white_j[1] = row_3w[j]; 274 | white_j[2] = row_2w[j]; 275 | white_j[3] = row_1w[j]; 276 | white_j[4] = row0w[j]; 277 | white_j[5] = row1w[j]; 278 | white_j[6] = row2w[j]; 279 | white_j[7] = row3w[j]; 280 | white_j[8] = row4w[j]; 281 | end 282 | else begin 283 | black_i[4] = 1'b0; 284 | white_i[4] = 1'b0; 285 | black_ij[4] = 1'b0; 286 | white_ij[4] = 1'b0; 287 | black_ji[4] = 1'b0; 288 | white_ji[4] = 1'b0; 289 | 290 | black_j[0] = 1'b0; 291 | black_j[1] = 1'b0; 292 | black_j[2] = 1'b0; 293 | black_j[3] = 1'b0; 294 | black_j[4] = 1'b0; 295 | black_j[5] = 1'b0; 296 | black_j[6] = 1'b0; 297 | black_j[7] = 1'b0; 298 | black_j[8] = 1'b0; 299 | white_j[0] = 1'b0; 300 | white_j[1] = 1'b0; 301 | white_j[2] = 1'b0; 302 | white_j[3] = 1'b0; 303 | white_j[4] = 1'b0; 304 | white_j[5] = 1'b0; 305 | white_j[6] = 1'b0; 306 | white_j[7] = 1'b0; 307 | white_j[8] = 1'b0; 308 | end 309 | 310 | if (j + 1 < BOARD_SIZE) begin 311 | black_i[5] = row0b[j + 1]; 312 | white_i[5] = row0w[j + 1]; 313 | black_ij[5] = row1b[j + 1]; 314 | white_ij[5] = row1w[j + 1]; 315 | black_ji[5] = row_1b[j + 1]; 316 | white_ji[5] = row_1w[j + 1]; 317 | end 318 | else begin 319 | black_i[5] = 1'b0; 320 | white_i[5] = 1'b0; 321 | black_ij[5] = 1'b0; 322 | white_ij[5] = 1'b0; 323 | black_ji[5] = 1'b0; 324 | white_ji[5] = 1'b0; 325 | end 326 | 327 | if (j + 2 < BOARD_SIZE) begin 328 | black_i[6] = row0b[j + 2]; 329 | white_i[6] = row0w[j + 2]; 330 | black_ij[6] = row2b[j + 2]; 331 | white_ij[6] = row2w[j + 2]; 332 | black_ji[6] = row_2b[j + 2]; 333 | white_ji[6] = row_2w[j + 2]; 334 | end 335 | else begin 336 | black_i[6] = 1'b0; 337 | white_i[6] = 1'b0; 338 | black_ij[6] = 1'b0; 339 | white_ij[6] = 1'b0; 340 | black_ji[6] = 1'b0; 341 | white_ji[6] = 1'b0; 342 | end 343 | 344 | if (j + 3 < BOARD_SIZE) begin 345 | black_i[7] = row0b[j + 3]; 346 | white_i[7] = row0w[j + 3]; 347 | black_ij[7] = row3b[j + 3]; 348 | white_ij[7] = row3w[j + 3]; 349 | black_ji[7] = row_3b[j + 3]; 350 | white_ji[7] = row_3w[j + 3]; 351 | end 352 | else begin 353 | black_i[7] = 1'b0; 354 | white_i[7] = 1'b0; 355 | black_ij[7] = 1'b0; 356 | white_ij[7] = 1'b0; 357 | black_ji[7] = 1'b0; 358 | white_ji[7] = 1'b0; 359 | end 360 | 361 | if (j + 4 < BOARD_SIZE) begin 362 | black_i[8] = row0b[j + 4]; 363 | white_i[8] = row0w[j + 4]; 364 | black_ij[8] = row4b[j + 4]; 365 | white_ij[8] = row4w[j + 4]; 366 | black_ji[8] = row_4b[j + 4]; 367 | white_ji[8] = row_4w[j + 4]; 368 | end 369 | else begin 370 | black_i[8] = 1'b0; 371 | white_i[8] = 1'b0; 372 | black_ij[8] = 1'b0; 373 | white_ij[8] = 1'b0; 374 | black_ji[8] = 1'b0; 375 | white_ji[8] = 1'b0; 376 | end 377 | end 378 | 379 | endmodule 380 | -------------------------------------------------------------------------------- /src/data/testbench/gobang_datapath_tb.v: -------------------------------------------------------------------------------- 1 | `timescale 1ns / 1ps 2 | 3 | module gobang_datapath_tb; 4 | 5 | // Inputs 6 | reg clk; 7 | reg rst; 8 | reg clr; 9 | reg write; 10 | reg [3:0] write_x; 11 | reg [3:0] write_y; 12 | reg write_color; 13 | reg [3:0] get_x; 14 | reg [3:0] get_y; 15 | 16 | // Outputs 17 | wire [8:0] black_x; 18 | wire [8:0] black_y; 19 | wire [8:0] black_xy; 20 | wire [8:0] black_yx; 21 | wire [8:0] white_x; 22 | wire [8:0] white_y; 23 | wire [8:0] white_xy; 24 | wire [8:0] white_yx; 25 | wire [224:0] black_data; 26 | wire [224:0] white_data; 27 | 28 | // Instantiate the Unit Under Test (UUT) 29 | gobang_datapath uut ( 30 | .clk(clk), 31 | .rst(rst), 32 | .clr(clr), 33 | .write(write), 34 | .write_x(write_x), 35 | .write_y(write_y), 36 | .write_color(write_color), 37 | .get_x(get_x), 38 | .get_y(get_y), 39 | .black_x(black_x), 40 | .black_y(black_y), 41 | .black_xy(black_xy), 42 | .black_yx(black_yx), 43 | .white_x(white_x), 44 | .white_y(white_y), 45 | .white_xy(white_xy), 46 | .white_yx(white_yx), 47 | .black_data(black_data), 48 | .white_data(white_data) 49 | ); 50 | 51 | initial begin 52 | clk = 0; 53 | rst = 1; 54 | write = 0; 55 | write_x = 0; 56 | write_y = 0; 57 | write_color = 0; 58 | get_x = 1; 59 | get_y = 1; 60 | #70; 61 | 62 | rst = 0; 63 | write = 1; 64 | write_x = 1; 65 | write_y = 1; 66 | write_color = 0; 67 | #50; 68 | 69 | write = 0; 70 | #50; 71 | 72 | write = 1; 73 | write_x = 2; 74 | write_y = 1; 75 | write_color = 1; 76 | #50; 77 | 78 | write = 0; 79 | end 80 | 81 | always begin 82 | #50; 83 | clk = ~clk; 84 | end 85 | 86 | endmodule 87 | 88 | -------------------------------------------------------------------------------- /src/display/vga_display.v: -------------------------------------------------------------------------------- 1 | `timescale 1ns / 1ps 2 | 3 | //------------------------------------------------------------------------------ 4 | // Display the color for each pixel 5 | //------------------------------------------------------------------------------ 6 | module vga_display( 7 | input wire clk, // Clock (25MHz) 8 | input wire rst, // Reset 9 | 10 | input wire [3:0] cursor_i, // Cursor position 11 | input wire [3:0] cursor_j, 12 | input wire black_is_player, // If black is not AI 13 | input wire white_is_player, // If white is not AI 14 | input wire crt_player, // Current player 15 | input wire game_running, // If the game is running 16 | input wire [1:0] winner, // Who wins the game 17 | 18 | input wire [14:0] display_black, // Row information for display 19 | input wire [14:0] display_white, 20 | 21 | output wire [3:0] display_i, // Row needed by display 22 | output wire sync_h, // VGA horizontal sync 23 | output wire sync_v, // VGA vertical sync 24 | output wire [3:0] r, // VGA red component 25 | output wire [3:0] g, // VGA green component 26 | output wire [3:0] b // VGA blue component 27 | ); 28 | 29 | // Side parameters 30 | localparam BLACK = 1'b0, 31 | WHITE = 1'b1; 32 | 33 | // Chessboard display parameters 34 | localparam BOARD_SIZE = 15, 35 | GRID_SIZE = 23, 36 | GRID_X_BEGIN = 148, 37 | GRID_X_END = 492, 38 | GRID_Y_BEGIN = 68, 39 | GRID_Y_END = 412; 40 | 41 | // Side information display parameters 42 | localparam SIDE_BLACK_X_BEGIN = 545, 43 | SIDE_BLACK_X_END = 616, 44 | SIDE_BLACK_Y_BEGIN = 182, 45 | SIDE_BLACK_Y_END = 200, 46 | SIDE_WHITE_X_BEGIN = 545, 47 | SIDE_WHITE_X_END = 616, 48 | SIDE_WHITE_Y_BEGIN = 278, 49 | SIDE_WHITE_Y_END = 296; 50 | 51 | // Current player pointer display parameters 52 | localparam CRT_BLACK_X_BEGIN = 510, 53 | CRT_BLACK_X_END = 541, 54 | CRT_BLACK_Y_BEGIN = 185, 55 | CRT_BLACK_Y_END = 198, 56 | CRT_WHITE_X_BEGIN = 510, 57 | CRT_WHITE_X_END = 541, 58 | CRT_WHITE_Y_BEGIN = 281, 59 | CRT_WHITE_Y_END = 294; 60 | 61 | // Title display parameters 62 | localparam TITLE_X_BEGIN = 0, 63 | TITLE_X_END = 140, 64 | TITLE_Y_BEGIN = 62, 65 | TITLE_Y_END = 418; 66 | 67 | // Instruction display parameters 68 | localparam INS_X_BEGIN = 145, 69 | INS_X_END = 494, 70 | INS_Y_BEGIN = 424, 71 | INS_Y_END = 467; 72 | 73 | // Result display parameters 74 | localparam RES_X_BEGIN = 187, 75 | RES_X_END = 452, 76 | RES_Y_BEGIN = 20, 77 | RES_Y_END = 47; 78 | 79 | // Author info display parameters 80 | localparam AUTHOR_X_BEGIN = 510, 81 | AUTHOR_X_END = 634, 82 | AUTHOR_Y_BEGIN = 455, 83 | AUTHOR_Y_END = 476; 84 | 85 | 86 | 87 | // Current display color 88 | reg [11:0] rgb; 89 | assign r = video_on ? rgb[11:8] : 4'b0; 90 | assign g = video_on ? rgb[7:4] : 4'b0; 91 | assign b = video_on ? rgb[3:0] : 4'b0; 92 | 93 | // VGA control signal generator 94 | wire video_on; 95 | wire [9:0] x, y; 96 | vga_sync 97 | sync( 98 | .clk(clk), 99 | .rst(rst), 100 | .sync_h(sync_h), 101 | .sync_v(sync_v), 102 | .video_on(video_on), 103 | .x(x), 104 | .y(y) 105 | ); 106 | 107 | // Chessboard display registers 108 | reg [3:0] row, col; 109 | integer delta_x, delta_y; 110 | assign display_i = row < BOARD_SIZE ? row : 4'b0; 111 | 112 | // Patterns needed to be displayed 113 | wire [22:0] chess_piece_data; 114 | pic_chess_piece chess_piece(x >= GRID_X_BEGIN && x <= GRID_X_END && 115 | y >= GRID_Y_BEGIN && y <= GRID_Y_END, 116 | delta_y + GRID_SIZE/2, chess_piece_data); 117 | 118 | wire [71:0] black_player_data, black_ai_data, 119 | white_player_data, white_ai_data; 120 | pic_side_player black_player(x >= SIDE_BLACK_X_BEGIN && 121 | x <= SIDE_BLACK_X_END && 122 | y >= SIDE_BLACK_Y_BEGIN && 123 | y <= SIDE_BLACK_Y_END, 124 | y - SIDE_BLACK_Y_BEGIN, black_player_data), 125 | white_player(x >= SIDE_WHITE_X_BEGIN && 126 | x <= SIDE_WHITE_X_END && 127 | y >= SIDE_WHITE_Y_BEGIN && 128 | y <= SIDE_WHITE_Y_END, 129 | y - SIDE_WHITE_Y_BEGIN, white_player_data); 130 | pic_side_ai black_ai(x >= SIDE_BLACK_X_BEGIN && x <= SIDE_BLACK_X_END && 131 | y >= SIDE_BLACK_Y_BEGIN && y <= SIDE_BLACK_Y_END, 132 | y - SIDE_BLACK_Y_BEGIN, black_ai_data), 133 | white_ai(x >= SIDE_WHITE_X_BEGIN && x <= SIDE_WHITE_X_END && 134 | y >= SIDE_WHITE_Y_BEGIN && y <= SIDE_WHITE_Y_END, 135 | y - SIDE_WHITE_Y_BEGIN, white_ai_data); 136 | 137 | wire [31:0] black_ptr_data, white_ptr_data; 138 | pic_crt_ptr black_ptr(x >= CRT_BLACK_X_BEGIN && x <= CRT_BLACK_X_END && 139 | y >= CRT_BLACK_Y_BEGIN && y <= CRT_BLACK_Y_END, 140 | y - CRT_BLACK_Y_BEGIN, black_ptr_data), 141 | white_ptr(x >= CRT_WHITE_X_BEGIN && x <= CRT_WHITE_X_END && 142 | y >= CRT_WHITE_Y_BEGIN && y <= CRT_WHITE_Y_END, 143 | y - CRT_WHITE_Y_BEGIN, white_ptr_data); 144 | 145 | wire [140:0] title_data; 146 | pic_title title(x >= TITLE_X_BEGIN && x <= TITLE_X_END && 147 | y >= TITLE_Y_BEGIN && y <= TITLE_Y_END, 148 | y - TITLE_Y_BEGIN, title_data); 149 | 150 | wire [349:0] ins_start_data, ins_player_data, ins_ai_data; 151 | pic_ins_start ins_start(x >= INS_X_BEGIN && x <= INS_X_END && 152 | y >= INS_Y_BEGIN && y <= INS_Y_END, 153 | y - INS_Y_BEGIN, ins_start_data); 154 | pic_ins_player ins_player(x >= INS_X_BEGIN && x <= INS_X_END && 155 | y >= INS_Y_BEGIN && y <= INS_Y_END, 156 | y - INS_Y_BEGIN, ins_player_data); 157 | pic_ins_ai ins_ai(x >= INS_X_BEGIN && x <= INS_X_END && 158 | y >= INS_Y_BEGIN && y <= INS_Y_END, 159 | y - INS_Y_BEGIN, ins_ai_data); 160 | 161 | wire [265:0] black_wins_data, white_wins_data, res_draw_data; 162 | pic_black_wins black_wins(x >= RES_X_BEGIN && x <= RES_X_END && 163 | y >= RES_Y_BEGIN && y <= RES_Y_END, 164 | y - RES_Y_BEGIN, black_wins_data); 165 | pic_white_wins white_wins(x >= RES_X_BEGIN && x <= RES_X_END && 166 | y >= RES_Y_BEGIN && y <= RES_Y_END, 167 | y - RES_Y_BEGIN, white_wins_data); 168 | pic_res_draw res_draw(x >= RES_X_BEGIN && x <= RES_X_END && 169 | y >= RES_Y_BEGIN && y <= RES_Y_END, 170 | y - RES_Y_BEGIN, res_draw_data); 171 | 172 | wire [124:0] author_info_data; 173 | pic_author_info author_info(x >= AUTHOR_X_BEGIN && x <= AUTHOR_X_END && 174 | y >= AUTHOR_Y_BEGIN && y <= AUTHOR_Y_END, 175 | y - AUTHOR_Y_BEGIN, author_info_data); 176 | 177 | // Calculate the current row and column 178 | always @ (x or y) begin 179 | if (y >= GRID_Y_BEGIN && 180 | y < GRID_Y_BEGIN + GRID_SIZE) 181 | row = 4'b0000; 182 | else if (y >= GRID_Y_BEGIN + GRID_SIZE && 183 | y < GRID_Y_BEGIN + GRID_SIZE*2) 184 | row = 4'b0001; 185 | else if (y >= GRID_Y_BEGIN + GRID_SIZE*2 && 186 | y < GRID_Y_BEGIN + GRID_SIZE*3) 187 | row = 4'b0010; 188 | else if (y >= GRID_Y_BEGIN + GRID_SIZE*3 && 189 | y < GRID_Y_BEGIN + GRID_SIZE*4) 190 | row = 4'b0011; 191 | else if (y >= GRID_Y_BEGIN + GRID_SIZE*4 && 192 | y < GRID_Y_BEGIN + GRID_SIZE*5) 193 | row = 4'b0100; 194 | else if (y >= GRID_Y_BEGIN + GRID_SIZE*5 && 195 | y < GRID_Y_BEGIN + GRID_SIZE*6) 196 | row = 4'b0101; 197 | else if (y >= GRID_Y_BEGIN + GRID_SIZE*6 && 198 | y < GRID_Y_BEGIN + GRID_SIZE*7) 199 | row = 4'b0110; 200 | else if (y >= GRID_Y_BEGIN + GRID_SIZE*7 && 201 | y < GRID_Y_BEGIN + GRID_SIZE*8) 202 | row = 4'b0111; 203 | else if (y >= GRID_Y_BEGIN + GRID_SIZE*8 && 204 | y < GRID_Y_BEGIN + GRID_SIZE*9) 205 | row = 4'b1000; 206 | else if (y >= GRID_Y_BEGIN + GRID_SIZE*9 && 207 | y < GRID_Y_BEGIN + GRID_SIZE*10) 208 | row = 4'b1001; 209 | else if (y >= GRID_Y_BEGIN + GRID_SIZE*10 && 210 | y < GRID_Y_BEGIN + GRID_SIZE*11) 211 | row = 4'b1010; 212 | else if (y >= GRID_Y_BEGIN + GRID_SIZE*11 && 213 | y < GRID_Y_BEGIN + GRID_SIZE*12) 214 | row = 4'b1011; 215 | else if (y >= GRID_Y_BEGIN + GRID_SIZE*12 && 216 | y < GRID_Y_BEGIN + GRID_SIZE*13) 217 | row = 4'b1100; 218 | else if (y >= GRID_Y_BEGIN + GRID_SIZE*13 && 219 | y < GRID_Y_BEGIN + GRID_SIZE*14) 220 | row = 4'b1101; 221 | else if (y >= GRID_Y_BEGIN + GRID_SIZE*14 && 222 | y < GRID_Y_BEGIN + GRID_SIZE*15) 223 | row = 4'b1110; 224 | else 225 | row = 4'b1111; 226 | 227 | if (x >= GRID_X_BEGIN && 228 | x < GRID_X_BEGIN + GRID_SIZE) 229 | col = 4'b0000; 230 | else if (x >= GRID_X_BEGIN + GRID_SIZE && 231 | x < GRID_X_BEGIN + GRID_SIZE*2) 232 | col = 4'b0001; 233 | else if (x >= GRID_X_BEGIN + GRID_SIZE*2 && 234 | x < GRID_X_BEGIN + GRID_SIZE*3) 235 | col = 4'b0010; 236 | else if (x >= GRID_X_BEGIN + GRID_SIZE*3 && 237 | x < GRID_X_BEGIN + GRID_SIZE*4) 238 | col = 4'b0011; 239 | else if (x >= GRID_X_BEGIN + GRID_SIZE*4 && 240 | x < GRID_X_BEGIN + GRID_SIZE*5) 241 | col = 4'b0100; 242 | else if (x >= GRID_X_BEGIN + GRID_SIZE*5 && 243 | x < GRID_X_BEGIN + GRID_SIZE*6) 244 | col = 4'b0101; 245 | else if (x >= GRID_X_BEGIN + GRID_SIZE*6 && 246 | x < GRID_X_BEGIN + GRID_SIZE*7) 247 | col = 4'b0110; 248 | else if (x >= GRID_X_BEGIN + GRID_SIZE*7 && 249 | x < GRID_X_BEGIN + GRID_SIZE*8) 250 | col = 4'b0111; 251 | else if (x >= GRID_X_BEGIN + GRID_SIZE*8 && 252 | x < GRID_X_BEGIN + GRID_SIZE*9) 253 | col = 4'b1000; 254 | else if (x >= GRID_X_BEGIN + GRID_SIZE*9 && 255 | x < GRID_X_BEGIN + GRID_SIZE*10) 256 | col = 4'b1001; 257 | else if (x >= GRID_X_BEGIN + GRID_SIZE*10 && 258 | x < GRID_X_BEGIN + GRID_SIZE*11) 259 | col = 4'b1010; 260 | else if (x >= GRID_X_BEGIN + GRID_SIZE*11 && 261 | x < GRID_X_BEGIN + GRID_SIZE*12) 262 | col = 4'b1011; 263 | else if (x >= GRID_X_BEGIN + GRID_SIZE*12 && 264 | x < GRID_X_BEGIN + GRID_SIZE*13) 265 | col = 4'b1100; 266 | else if (x >= GRID_X_BEGIN + GRID_SIZE*13 && 267 | x < GRID_X_BEGIN + GRID_SIZE*14) 268 | col = 4'b1101; 269 | else if (x >= GRID_X_BEGIN + GRID_SIZE*14 && 270 | x < GRID_X_BEGIN + GRID_SIZE*15) 271 | col = 4'b1110; 272 | else 273 | col = 4'b1111; 274 | 275 | delta_x = GRID_X_BEGIN + col*GRID_SIZE + GRID_SIZE/2 - x; 276 | delta_y = GRID_Y_BEGIN + row*GRID_SIZE + GRID_SIZE/2 - y; 277 | end 278 | 279 | // Calculate the color 280 | always @ (posedge clk) begin 281 | if (x >= GRID_X_BEGIN && x <= GRID_X_END && 282 | y >= GRID_Y_BEGIN && y <= GRID_Y_END) begin 283 | // Draw the chessboard 284 | if (display_black[col] && 285 | chess_piece_data[delta_x + GRID_SIZE/2]) 286 | // Draw a black chess 287 | rgb <= 12'h000; 288 | else if (display_white[col] && 289 | chess_piece_data[delta_x + GRID_SIZE/2]) 290 | // Draw a white chess 291 | rgb <= 12'hfff; 292 | else if (row == cursor_i && col == cursor_j && 293 | (delta_x == GRID_SIZE/2 || delta_x == -(GRID_SIZE/2) || 294 | delta_y == GRID_SIZE/2 || delta_y == -(GRID_SIZE/2))) 295 | // Draw a red square as a cursor 296 | rgb <= 12'hf00; 297 | else if (delta_x == 0 || delta_y == 0) 298 | // Draw the light border of a grid 299 | rgb <= 12'hda6; 300 | else if (delta_x == 1 || delta_y == 1) 301 | // Draw the dark border of a grid 302 | rgb <= 12'h751; 303 | else 304 | rgb <= 12'hc81; 305 | end 306 | else if (x >= CRT_BLACK_X_BEGIN && x <= CRT_BLACK_X_END && 307 | y >= CRT_BLACK_Y_BEGIN && y <= CRT_BLACK_Y_END) begin 308 | // Draw the current player pointer for black side 309 | rgb <= game_running && crt_player == BLACK && 310 | black_ptr_data[CRT_BLACK_X_END - x] ? 12'h000 : 12'hc81; 311 | end 312 | else if (x >= CRT_WHITE_X_BEGIN && x <= CRT_WHITE_X_END && 313 | y >= CRT_WHITE_Y_BEGIN && y <= CRT_WHITE_Y_END) begin 314 | // Draw the current player pointer for white side 315 | rgb <= game_running && crt_player == WHITE && 316 | white_ptr_data[CRT_WHITE_X_END - x] ? 12'hfff : 12'hc81; 317 | end 318 | else if (x >= SIDE_BLACK_X_BEGIN && x <= SIDE_BLACK_X_END && 319 | y >= SIDE_BLACK_Y_BEGIN && y <= SIDE_BLACK_Y_END) begin 320 | // Draw who plays the black side 321 | if (black_is_player) 322 | rgb <= black_player_data[SIDE_BLACK_X_END - x] ? 323 | 12'h000 : 12'hc81; 324 | else 325 | rgb <= black_ai_data[SIDE_BLACK_X_END - x] ? 12'h000 : 12'hc81; 326 | end 327 | else if (x >= SIDE_WHITE_X_BEGIN && x <= SIDE_WHITE_X_END && 328 | y >= SIDE_WHITE_Y_BEGIN && y <= SIDE_WHITE_Y_END) begin 329 | // Draw who plays the white side 330 | if (white_is_player) 331 | rgb <= white_player_data[SIDE_WHITE_X_END - x] ? 332 | 12'hfff : 12'hc81; 333 | else 334 | rgb <= white_ai_data[SIDE_WHITE_X_END - x] ? 12'hfff : 12'hc81; 335 | end 336 | else if (x >= INS_X_BEGIN && x <= INS_X_END && 337 | y >= INS_Y_BEGIN && y <= INS_Y_END) begin 338 | // Draw instructions 339 | if (!game_running) 340 | rgb <= ins_start_data[INS_X_END - x] ? 12'h000 : 12'hc81; 341 | else if ((black_is_player && crt_player == BLACK) || 342 | (white_is_player && crt_player == WHITE)) 343 | rgb <= ins_player_data[INS_X_END - x] ? 12'h000 : 12'hc81; 344 | else 345 | rgb <= ins_ai_data[INS_X_END - x] ? 12'h000 : 12'hc81; 346 | end 347 | else if (x >= RES_X_BEGIN && x <= RES_X_END && 348 | y >= RES_Y_BEGIN && y <= RES_Y_END) begin 349 | // Draw the result 350 | case (winner) 351 | 2'b00: rgb <= 12'hc81; 352 | 2'b01: rgb <= black_wins_data[RES_X_END - x] ? 12'h000 : 12'hc81; 353 | 2'b10: rgb <= white_wins_data[RES_X_END - x] ? 12'hfff : 12'hc81; 354 | 2'b11: rgb <= res_draw_data[RES_X_END - x] ? 12'hfff : 12'hc81; 355 | endcase 356 | end 357 | else if (x >= TITLE_X_BEGIN && x <= TITLE_X_END && 358 | y >= TITLE_Y_BEGIN && y <= TITLE_Y_END) begin 359 | // Draw the title 360 | rgb <= title_data[TITLE_X_END - x] ? 12'hfff : 12'hc81; 361 | end 362 | else if (x >= AUTHOR_X_BEGIN && x <= AUTHOR_X_END && 363 | y >= AUTHOR_Y_BEGIN && y <= AUTHOR_Y_END) begin 364 | // Draw the author info 365 | rgb <= author_info_data[AUTHOR_X_END - x] ? 12'h000 : 12'hc81; 366 | end 367 | else 368 | // Draw the background 369 | rgb <= 12'hc81; 370 | end 371 | 372 | endmodule 373 | -------------------------------------------------------------------------------- /src/display/vga_sync.v: -------------------------------------------------------------------------------- 1 | `timescale 1ns / 1ps 2 | 3 | //------------------------------------------------------------------------------ 4 | // Generate the VGA control signal 5 | //------------------------------------------------------------------------------ 6 | module vga_sync( 7 | input wire clk, // Clock (25MHz) 8 | input wire rst, // Reset 9 | output wire sync_h, // VGA horizontal sync 10 | output wire sync_v, // VGA vertical sync 11 | output wire video_on, // True when in the display area 12 | output reg [9:0] x, // X coordinate 13 | output reg [9:0] y // Y coordinate 14 | ); 15 | 16 | assign sync_h = ~(x > 655 && x < 752); 17 | assign sync_v = ~(y > 489 && y < 492); 18 | assign video_on = (x < 640 && y < 480); 19 | 20 | always @ (posedge clk or negedge rst) begin 21 | if (!rst) begin 22 | x <= 0; 23 | y <= 0; 24 | end 25 | else begin 26 | if (x == 799) 27 | x <= 0; 28 | else 29 | x <= x + 1'b1; 30 | if (y == 524) 31 | y <= 0; 32 | else if (x == 799) 33 | y <= y + 1'b1; 34 | end 35 | end 36 | 37 | endmodule 38 | -------------------------------------------------------------------------------- /src/gobang_top.v: -------------------------------------------------------------------------------- 1 | `timescale 1ns / 1ps 2 | 3 | //------------------------------------------------------------------------------ 4 | // Top module 5 | //------------------------------------------------------------------------------ 6 | module gobang_top( 7 | input wire clk, // Clock (100MHz) 8 | input wire rst, // Reset button, 0 = pressed, 1 = released 9 | input wire ps2_clk, // PS2 clock 10 | input wire ps2_data, // PS2 data 11 | output wire sync_h, // VGA horizontal sync 12 | output wire sync_v, // VGA vertical sync 13 | output wire [3:0] r, // VGA red component 14 | output wire [3:0] g, // VGA green component 15 | output wire [3:0] b, // VGA blue component 16 | output wire buz // Arduino buzzer 17 | ); 18 | 19 | wire [3:0] consider_i, consider_j, cursor_i, cursor_j; 20 | wire data_clr, data_write; 21 | wire black_is_player, white_is_player, crt_player, game_running; 22 | wire [1:0] winner; 23 | 24 | wire [8:0] black_i, black_j, black_ij, black_ji, 25 | white_i, white_j, white_ij, white_ji; 26 | wire [14:0] logic_row, display_black, display_white; 27 | 28 | wire key_up, key_down, key_left, key_right, key_ok, key_switch; 29 | 30 | wire [3:0] display_i; 31 | 32 | wire [31:0] rand_num; 33 | wire [31:0] clk_div; 34 | 35 | // Turn off the arduino buzzer 36 | assign buz = 1'b1; 37 | 38 | gobang_logic 39 | game_logic( 40 | .clk_slow(clk_div[16]), 41 | .clk_fast(clk_div[6]), 42 | .rst(rst), 43 | .random(rand_num[0]), 44 | .key_up(key_up), 45 | .key_down(key_down), 46 | .key_left(key_left), 47 | .key_right(key_right), 48 | .key_ok(key_ok), 49 | .key_switch(key_switch), 50 | .black_i(black_i), 51 | .black_j(black_j), 52 | .black_ij(black_ij), 53 | .black_ji(black_ji), 54 | .white_i(white_i), 55 | .white_j(white_j), 56 | .white_ij(white_ij), 57 | .white_ji(white_ji), 58 | .chess_row(logic_row), 59 | .consider_i(consider_i), 60 | .consider_j(consider_j), 61 | .data_clr(data_clr), 62 | .data_write(data_write), 63 | .cursor_i(cursor_i), 64 | .cursor_j(cursor_j), 65 | .black_is_player(black_is_player), 66 | .white_is_player(white_is_player), 67 | .crt_player(crt_player), 68 | .game_running(game_running), 69 | .winner(winner) 70 | ); 71 | 72 | gobang_datapath 73 | data( 74 | .clk(clk_div[16]), 75 | .rst(rst), 76 | .clr(data_clr), 77 | .write(data_write), 78 | .write_i(cursor_i), 79 | .write_j(cursor_j), 80 | .write_color(crt_player), 81 | .logic_i(cursor_i), 82 | .display_i(display_i), 83 | .consider_i(consider_i), 84 | .consider_j(consider_j), 85 | .logic_row(logic_row), 86 | .display_black(display_black), 87 | .display_white(display_white), 88 | .black_i(black_i), 89 | .black_j(black_j), 90 | .black_ij(black_ij), 91 | .black_ji(black_ji), 92 | .white_i(white_i), 93 | .white_j(white_j), 94 | .white_ij(white_ij), 95 | .white_ji(white_ji) 96 | ); 97 | 98 | ps2_input 99 | keyboard( 100 | .clk_slow(clk_div[16]), 101 | .clk_fast(clk_div[6]), 102 | .rst(rst), 103 | .ps2_clk(ps2_clk), 104 | .ps2_data(ps2_data), 105 | .key_up(key_up), 106 | .key_down(key_down), 107 | .key_left(key_left), 108 | .key_right(key_right), 109 | .key_ok(key_ok), 110 | .key_switch(key_switch) 111 | ); 112 | 113 | vga_display 114 | display( 115 | .clk(clk_div[1]), 116 | .rst(rst), 117 | .cursor_i(cursor_i), 118 | .cursor_j(cursor_j), 119 | .black_is_player(black_is_player), 120 | .white_is_player(white_is_player), 121 | .crt_player(crt_player), 122 | .game_running(game_running), 123 | .winner(winner), 124 | .display_black(display_black), 125 | .display_white(display_white), 126 | .display_i(display_i), 127 | .sync_h(sync_h), 128 | .sync_v(sync_v), 129 | .r(r), 130 | .g(g), 131 | .b(b) 132 | ); 133 | 134 | random_generator 135 | rand( 136 | .clk(clk_div[6]), 137 | .rst(rst), 138 | .load(key_ok), 139 | .seed(clk_div), 140 | .rand_num(rand_num) 141 | ); 142 | 143 | clk_divider 144 | divider( 145 | .clk(clk), 146 | .rst(rst), 147 | .clk_div(clk_div) 148 | ); 149 | 150 | endmodule 151 | -------------------------------------------------------------------------------- /src/input/ps2_input.v: -------------------------------------------------------------------------------- 1 | `timescale 1ns / 1ps 2 | 3 | //------------------------------------------------------------------------------ 4 | // Dealing with the input data of the PS2 keyboard 5 | //------------------------------------------------------------------------------ 6 | module ps2_input( 7 | input wire clk_slow, // Slower clock for this module 8 | input wire clk_fast, // Faster clock for the PS2 scanner 9 | input wire rst, // Reset 10 | input wire ps2_clk, // PS2 clock 11 | input wire ps2_data, // PS2 data 12 | 13 | output wire key_up, // If UP key is pressed 14 | output wire key_down, // If DOWN key is pressed 15 | output wire key_left, // If LEFT key is pressed 16 | output wire key_right, // If RIGHT key is pressed 17 | output wire key_ok, // If OK key is pressed 18 | output wire key_switch // If SWITCH key is pressed 19 | ); 20 | 21 | wire [8:0] crt_data; // Input data of the PS2 keyboard 22 | 23 | // Key state recorders 24 | reg [1:0] key_up_state, key_down_state, key_left_state, 25 | key_right_state, key_ok_state, key_switch_state; 26 | // Only becomes true at the posedge of each key 27 | assign key_up = key_up_state[0] & ~key_up_state[1]; 28 | assign key_down = key_down_state[0] & ~key_down_state[1]; 29 | assign key_left = key_left_state[0] & ~key_left_state[1]; 30 | assign key_right = key_right_state[0] & ~key_right_state[1]; 31 | assign key_ok = key_ok_state[0] & ~key_ok_state[1]; 32 | assign key_switch = key_switch_state[0] & ~key_switch_state[1]; 33 | 34 | // PS2 keyboard scanner 35 | ps2_scan 36 | scanner( 37 | .clk(clk_fast), 38 | .rst(rst), 39 | .ps2_clk(ps2_clk), 40 | .ps2_data(ps2_data), 41 | .crt_data(crt_data) 42 | ); 43 | 44 | always @ (posedge clk_slow or negedge rst) 45 | if (!rst) begin 46 | key_up_state <= 2'b0; 47 | key_down_state <= 2'b0; 48 | key_left_state <= 2'b0; 49 | key_right_state <= 2'b0; 50 | key_ok_state <= 2'b0; 51 | key_switch_state <= 2'b0; 52 | end 53 | else begin 54 | // Record the key state 55 | key_up_state <= {key_up_state[0], crt_data == 9'h175}; 56 | key_down_state <= {key_down_state[0], crt_data == 9'h172}; 57 | key_left_state <= {key_left_state[0], crt_data == 9'h16b}; 58 | key_right_state <= {key_right_state[0], crt_data == 9'h174}; 59 | key_ok_state <= {key_ok_state[0], crt_data == 9'h029}; 60 | key_switch_state <= {key_switch_state[0], crt_data == 9'h014}; 61 | end 62 | 63 | endmodule 64 | -------------------------------------------------------------------------------- /src/input/ps2_scan.v: -------------------------------------------------------------------------------- 1 | `timescale 1ns / 1ps 2 | 3 | //------------------------------------------------------------------------------ 4 | // PS2 keyboard scanner 5 | //------------------------------------------------------------------------------ 6 | module ps2_scan( 7 | input wire clk, // Clock 8 | input wire rst, // Reset 9 | input wire ps2_clk, // PS2 clock 10 | input wire ps2_data, // PS2 data 11 | 12 | output reg [8:0] crt_data // Input data of the keyboard 13 | ); 14 | 15 | reg [1:0] ps2_clk_state; // PS2 clock recorder 16 | wire ps2_clk_neg; // True at the negedge of the PS2 clock 17 | assign ps2_clk_neg = ~ps2_clk_state[0] & ps2_clk_state[1]; 18 | 19 | // Registers for data reading 20 | reg [3:0] read_state; 21 | reg [7:0] read_data; 22 | 23 | // Registers for special signals 24 | reg is_f0, is_e0; 25 | 26 | // Record the PS2 clock 27 | always @ (posedge clk or negedge rst) 28 | if (!rst) 29 | ps2_clk_state <= 2'b0; 30 | else 31 | ps2_clk_state <= {ps2_clk_state[0], ps2_clk}; 32 | 33 | always @ (posedge clk or negedge rst) begin 34 | if (!rst) begin 35 | read_state <= 4'b0; 36 | read_data <= 8'b0; 37 | 38 | is_f0 <= 1'b0; 39 | is_e0 <= 1'b0; 40 | crt_data <= 9'b0; 41 | end 42 | else if (ps2_clk_neg) begin 43 | // Reads in the data 44 | if (read_state > 4'b1001) 45 | read_state <= 4'b0; 46 | else begin 47 | if (read_state > 4'b0 && read_state < 4'b1001) 48 | read_data[read_state - 1] <= ps2_data; 49 | read_state <= read_state + 1'b1; 50 | end 51 | end 52 | else if (read_state == 4'b1010 && |read_data) begin 53 | if (read_data == 8'hf0) 54 | is_f0 <= 1'b1; 55 | else if (read_data == 8'he0) 56 | is_e0 <= 1'b1; 57 | else 58 | if (is_f0) begin 59 | // A key is released 60 | is_f0 <= 1'b0; 61 | is_e0 <= 1'b0; 62 | crt_data <= 9'b0; 63 | end 64 | else if (is_e0) begin 65 | is_e0 <= 1'b0; 66 | crt_data <= {1'b1, read_data}; 67 | end 68 | else 69 | crt_data <= {1'b0, read_data}; 70 | 71 | read_data <= 8'b0; 72 | end 73 | end 74 | 75 | endmodule 76 | -------------------------------------------------------------------------------- /src/input/testbench/ps2_scan_tb.v: -------------------------------------------------------------------------------- 1 | `timescale 1ns / 1ps 2 | 3 | module ps2_scan_tb; 4 | 5 | // Inputs 6 | reg clk; 7 | reg rst; 8 | reg ps2_clk; 9 | reg ps2_data; 10 | 11 | // Outputs 12 | wire [8:0] crt_data; 13 | 14 | // Instantiate the Unit Under Test (UUT) 15 | ps2_scan uut ( 16 | .clk(clk), 17 | .rst(rst), 18 | .ps2_clk(ps2_clk), 19 | .ps2_data(ps2_data), 20 | .crt_data(crt_data) 21 | ); 22 | 23 | reg [3:0] i; 24 | 25 | localparam [7:0] SPACE = 8'h29, UP = 8'h75; 26 | localparam [7:0] E0 = 8'he0, F0 = 8'hf0; 27 | 28 | initial begin 29 | clk = 0; 30 | rst = 1; 31 | ps2_clk = 1; 32 | ps2_data = 0; 33 | #50; 34 | 35 | rst = 0; 36 | #30; 37 | 38 | rst = 1; 39 | #30; 40 | 41 | // space 42 | for (i=0;i<11;i=i+1) begin 43 | ps2_clk = 1; 44 | if (i > 0 && i < 9) 45 | ps2_data = SPACE[i-1]; 46 | #30; 47 | 48 | ps2_clk = 0; 49 | #30; 50 | end 51 | 52 | ps2_clk = 1; 53 | #30; 54 | 55 | // e0 56 | for (i=0;i<11;i=i+1) begin 57 | ps2_clk = 1; 58 | if (i > 0 && i < 9) 59 | ps2_data = E0[i-1]; 60 | #30; 61 | 62 | ps2_clk = 0; 63 | #30; 64 | end 65 | 66 | ps2_clk = 1; 67 | #30; 68 | 69 | // up 70 | for (i=0;i<11;i=i+1) begin 71 | ps2_clk = 1; 72 | if (i > 0 && i < 9) 73 | ps2_data = UP[i-1]; 74 | #30; 75 | 76 | ps2_clk = 0; 77 | #30; 78 | end 79 | 80 | ps2_clk = 1; 81 | #30; 82 | 83 | // f0 84 | for (i=0;i<11;i=i+1) begin 85 | ps2_clk = 1; 86 | if (i > 0 && i < 9) 87 | ps2_data = F0[i-1]; 88 | #30; 89 | 90 | ps2_clk = 0; 91 | #30; 92 | end 93 | 94 | ps2_clk = 1; 95 | #30; 96 | 97 | // space 98 | for (i=0;i<11;i=i+1) begin 99 | ps2_clk = 1; 100 | if (i > 0 && i < 9) 101 | ps2_data = SPACE[i-1]; 102 | #30; 103 | 104 | ps2_clk = 0; 105 | #30; 106 | end 107 | 108 | ps2_clk = 1; 109 | #30; 110 | end 111 | 112 | always begin 113 | #5; 114 | clk = ~clk; 115 | end 116 | 117 | endmodule 118 | 119 | -------------------------------------------------------------------------------- /src/logic/gobang_logic.v: -------------------------------------------------------------------------------- 1 | `timescale 1ns / 1ps 2 | 3 | //------------------------------------------------------------------------------ 4 | // The logic part of the gobang game 5 | //------------------------------------------------------------------------------ 6 | module gobang_logic( 7 | input wire clk_slow, // Slower clock for main FSM 8 | input wire clk_fast, // Faster clock for strategy and checker 9 | input wire rst, // Reset 10 | input wire random, // Random signal 11 | 12 | input wire key_up, // If UP key is pressed 13 | input wire key_down, // If DOWN key is pressed 14 | input wire key_left, // If LEFT key is pressed 15 | input wire key_right, // If RIGHT key is pressed 16 | input wire key_ok, // If OK key is pressed 17 | input wire key_switch, // If SWITCH key is pressed 18 | 19 | input wire [8:0] black_i, // Row information for strategy/checker 20 | input wire [8:0] black_j, // Column information for s/c 21 | input wire [8:0] black_ij, // Main diagonal information for s/c 22 | input wire [8:0] black_ji, // Counter diagonal information for s/c 23 | input wire [8:0] white_i, 24 | input wire [8:0] white_j, 25 | input wire [8:0] white_ij, 26 | input wire [8:0] white_ji, 27 | input wire [14:0] chess_row, // Row information for main logic 28 | 29 | output wire [3:0] consider_i, // The row s/c is considering 30 | output wire [3:0] consider_j, // The column s/c is considering 31 | 32 | output reg data_clr, // Clear the datapath 33 | output reg data_write, // Writing-enable signal of the datapath 34 | 35 | output reg [3:0] cursor_i, // Row of the cursor 36 | output reg [3:0] cursor_j, // Column of the cursor 37 | output reg black_is_player, // If black is not AI 38 | output reg white_is_player, // If white is not AI 39 | output reg crt_player, // Current player 40 | output reg game_running, // If the game is running 41 | output reg [1:0] winner // Who wins the game 42 | ); 43 | 44 | // Side parameters 45 | localparam BLACK = 1'b0, 46 | WHITE = 1'b1; 47 | 48 | // Chessboard parameters 49 | localparam BOARD_SIZE = 15; 50 | 51 | // State parameters 52 | localparam STATE_IDLE = 3'b000, 53 | STATE_MOVE = 3'b001, 54 | STATE_WAIT = 3'b010, 55 | STATE_DECIDE = 3'b011, 56 | STATE_PUT_CHESS = 3'b100, 57 | STATE_PUT_END = 3'b101, 58 | STATE_CHECK = 3'b110, 59 | STATE_GAME_END = 3'b111; 60 | 61 | // Lasting time for STATE_WAIT 62 | localparam WAIT_TIME = 400; 63 | 64 | reg [2:0] state; // Current game state 65 | reg [8:0] wait_count; 66 | reg [7:0] move_count; // How many moves have been played 67 | 68 | // A simple strategy for the game 69 | reg strategy_clr, strategy_active; 70 | wire [3:0] strategy_i, strategy_j; 71 | wire [12:0] black_best_score; 72 | wire [3:0] black_best_i, black_best_j; 73 | wire [12:0] white_best_score; 74 | wire [3:0] white_best_i, white_best_j; 75 | gobang_strategy 76 | strategy( 77 | .clk(clk_fast), 78 | .rst(rst), 79 | .clr(strategy_clr), 80 | .active(strategy_active), 81 | .random(random), 82 | .black_i(black_i), 83 | .black_j(black_j), 84 | .black_ij(black_ij), 85 | .black_ji(black_ji), 86 | .white_i(white_i), 87 | .white_j(white_j), 88 | .white_ij(white_ij), 89 | .white_ji(white_ji), 90 | .get_i(strategy_i), 91 | .get_j(strategy_j), 92 | .black_best_score(black_best_score), 93 | .black_best_i(black_best_i), 94 | .black_best_j(black_best_j), 95 | .white_best_score(white_best_score), 96 | .white_best_i(white_best_i), 97 | .white_best_j(white_best_j) 98 | ); 99 | 100 | // A checker to check if someone wins the game 101 | reg win_clr, win_active; 102 | wire [3:0] win_i, win_j; 103 | wire is_win; 104 | win_checker 105 | checker( 106 | .clk(clk_fast), 107 | .rst(rst), 108 | .clr(win_clr), 109 | .active(win_active), 110 | .black_i(black_i), 111 | .black_j(black_j), 112 | .black_ij(black_ij), 113 | .black_ji(black_ji), 114 | .white_i(white_i), 115 | .white_j(white_j), 116 | .white_ij(white_ij), 117 | .white_ji(white_ji), 118 | .get_i(win_i), 119 | .get_j(win_j), 120 | .is_win(is_win) 121 | ); 122 | 123 | // The strategy and the checker uses the same port to get information, 124 | // but they will not use it at the same time 125 | assign consider_i = strategy_i | win_i; 126 | assign consider_j = strategy_j | win_j; 127 | 128 | // Main FSM of the game 129 | always @ (posedge clk_slow or negedge rst) begin 130 | if (!rst) begin 131 | cursor_i <= BOARD_SIZE; 132 | cursor_j <= BOARD_SIZE; 133 | {white_is_player, black_is_player} <= 2'b01; 134 | crt_player <= BLACK; 135 | game_running <= 1'b0; 136 | winner <= 2'b00; 137 | 138 | state <= STATE_IDLE; 139 | move_count <= 8'b0; 140 | data_clr <= 1'b0; 141 | data_write <= 1'b0; 142 | strategy_clr <= 1'b0; 143 | strategy_active <= 1'b0; 144 | win_clr <= 1'b0; 145 | win_active <= 1'b0; 146 | end 147 | else begin 148 | case (state) 149 | STATE_IDLE: 150 | if (key_ok) begin 151 | // Press OK key to start the game 152 | cursor_i <= BOARD_SIZE/2; 153 | cursor_j <= BOARD_SIZE/2; 154 | crt_player <= BLACK; 155 | game_running <= 1'b1; 156 | winner <= 2'b00; 157 | 158 | state <= STATE_MOVE; 159 | move_count <= 8'b0; 160 | data_clr <= 1'b1; 161 | strategy_clr <= 1'b1; 162 | win_clr <= 1'b1; 163 | end 164 | else if (key_switch) 165 | // Switch player 166 | {white_is_player, black_is_player} <= 167 | {white_is_player, black_is_player} + 2'b1; 168 | else 169 | state <= STATE_IDLE; 170 | 171 | STATE_MOVE: begin 172 | data_clr <= 1'b0; 173 | strategy_clr <= 1'b0; 174 | win_clr <= 1'b0; 175 | 176 | if ((crt_player == BLACK && black_is_player) || 177 | (crt_player == WHITE && white_is_player)) begin 178 | // Player's move 179 | 180 | // Move the cursor 181 | if (key_up && cursor_i > 0) 182 | cursor_i <= cursor_i - 1'b1; 183 | else if (key_down && cursor_i < BOARD_SIZE - 1) 184 | cursor_i <= cursor_i + 1'b1; 185 | if (key_left && cursor_j > 0) 186 | cursor_j <= cursor_j - 1'b1; 187 | else if (key_right && cursor_j < BOARD_SIZE - 1) 188 | cursor_j <= cursor_j + 1'b1; 189 | 190 | if (key_ok) 191 | // Press OK key to put the chess 192 | state <= STATE_PUT_CHESS; 193 | end 194 | else begin 195 | // CPU's move 196 | strategy_active <= 1'b1; 197 | state <= STATE_WAIT; 198 | wait_count <= 0; 199 | end 200 | end 201 | 202 | STATE_WAIT: 203 | // Wait for a while, otherwise the CPU will deicide too fast 204 | if (wait_count >= WAIT_TIME) 205 | state <= STATE_DECIDE; 206 | else 207 | wait_count <= wait_count + 1'b1; 208 | 209 | STATE_DECIDE: begin 210 | // Compare the best possible score for my side and the opposite, 211 | // and choose the best position 212 | strategy_active <= 1'b0; 213 | if (black_best_score > white_best_score || 214 | (black_best_score == white_best_score && 215 | crt_player == BLACK)) begin 216 | cursor_i <= black_best_i; 217 | cursor_j <= black_best_j; 218 | end 219 | else begin 220 | cursor_i <= white_best_i; 221 | cursor_j <= white_best_j; 222 | end 223 | 224 | state <= STATE_PUT_CHESS; 225 | end 226 | 227 | STATE_PUT_CHESS: 228 | // Check if the position is occupied. If not, put the chess 229 | if (!chess_row[cursor_j]) begin 230 | move_count <= move_count + 8'b1; 231 | data_write <= 1'b1; 232 | state <= STATE_PUT_END; 233 | end 234 | else 235 | state <= STATE_MOVE; 236 | 237 | STATE_PUT_END: begin 238 | data_write <= 1'b0; 239 | win_active <= 1'b1; 240 | state <= STATE_CHECK; 241 | end 242 | 243 | STATE_CHECK: begin 244 | // Check if someone wins the game or there is a draw 245 | win_active <= 1'b0; 246 | if (is_win || move_count == BOARD_SIZE * BOARD_SIZE) 247 | state <= STATE_GAME_END; 248 | else begin 249 | crt_player <= ~crt_player; 250 | state <= STATE_MOVE; 251 | end 252 | end 253 | 254 | STATE_GAME_END: begin 255 | if (is_win) 256 | // Someone wins the game 257 | winner <= 2'b01 << crt_player; 258 | else 259 | // There is a draw 260 | winner <= 2'b11; 261 | 262 | state <= STATE_IDLE; 263 | game_running <= 1'b0; 264 | end 265 | 266 | endcase 267 | end 268 | end 269 | 270 | endmodule 271 | -------------------------------------------------------------------------------- /src/logic/gobang_patterns.v: -------------------------------------------------------------------------------- 1 | `timescale 1ns / 1ps 2 | //------------------------------------------------------------------------------ 3 | // _ = empty | * = my chess | o = opponent's chess 4 | //------------------------------------------------------------------------------ 5 | 6 | //------------------------------------------------------------------------------ 7 | // Recognize ***** 8 | //------------------------------------------------------------------------------ 9 | module pattern_five( 10 | input wire [8:0] my, 11 | output reg ret 12 | ); 13 | 14 | always @ (*) 15 | if ((my[0] && my[1] && my[2] && my[3] && my[4]) || 16 | (my[1] && my[2] && my[3] && my[4] && my[5]) || 17 | (my[2] && my[3] && my[4] && my[5] && my[6]) || 18 | (my[3] && my[4] && my[5] && my[6] && my[7]) || 19 | (my[4] && my[5] && my[6] && my[7] && my[8])) 20 | ret = 1'b1; 21 | else 22 | ret = 1'b0; 23 | 24 | endmodule 25 | 26 | //------------------------------------------------------------------------------ 27 | // Recognize _****_ 28 | //------------------------------------------------------------------------------ 29 | module pattern_four( 30 | input wire [8:0] my, 31 | input wire [8:0] op, 32 | output reg ret 33 | ); 34 | 35 | wire [8:0] empty; 36 | assign empty = ~(my | op); 37 | 38 | always @ (*) 39 | if ((empty[0] && my[1] && my[2] && my[3] && my[4] && empty[5]) || 40 | (empty[1] && my[2] && my[3] && my[4] && my[5] && empty[6]) || 41 | (empty[2] && my[3] && my[4] && my[5] && my[6] && empty[7]) || 42 | (empty[3] && my[4] && my[5] && my[6] && my[7] && empty[8])) 43 | ret = 1'b1; 44 | else 45 | ret = 1'b0; 46 | 47 | endmodule 48 | 49 | //------------------------------------------------------------------------------ 50 | // Recognize o****_ | _****o | *_*** | ***_* | **_** 51 | //------------------------------------------------------------------------------ 52 | module pattern_ffour( 53 | input wire [8:0] my, 54 | input wire [8:0] op, 55 | output reg ret 56 | ); 57 | 58 | wire [8:0] empty; 59 | assign empty = ~(my | op); 60 | 61 | always @ (*) 62 | if ((op[0] && my[1] && my[2] && my[3] && my[4] && empty[5]) || 63 | (op[1] && my[2] && my[3] && my[4] && my[5] && empty[6]) || 64 | (op[2] && my[3] && my[4] && my[5] && my[6] && empty[7]) || 65 | (op[3] && my[4] && my[5] && my[6] && my[7] && empty[8]) || 66 | (empty[0] && my[1] && my[2] && my[3] && my[4] && op[5]) || 67 | (empty[1] && my[2] && my[3] && my[4] && my[5] && op[6]) || 68 | (empty[2] && my[3] && my[4] && my[5] && my[6] && op[7]) || 69 | (empty[3] && my[4] && my[5] && my[6] && my[7] && op[8]) || 70 | (my[0] && empty[1] && my[2] && my[3] && my[4]) || 71 | (my[1] && empty[2] && my[3] && my[4] && my[5]) || 72 | (my[2] && empty[3] && my[4] && my[5] && my[6]) || 73 | (my[3] && empty[4] && my[5] && my[6] && my[7]) || 74 | (my[4] && empty[5] && my[6] && my[7] && my[8]) || 75 | (my[0] && my[1] && my[2] && empty[3] && my[4]) || 76 | (my[1] && my[2] && my[3] && empty[4] && my[5]) || 77 | (my[2] && my[3] && my[4] && empty[5] && my[6]) || 78 | (my[3] && my[4] && my[5] && empty[6] && my[7]) || 79 | (my[4] && my[5] && my[6] && empty[7] && my[8]) || 80 | (my[0] && my[1] && empty[2] && my[3] && my[4]) || 81 | (my[1] && my[2] && empty[3] && my[4] && my[5]) || 82 | (my[2] && my[3] && empty[4] && my[5] && my[6]) || 83 | (my[3] && my[4] && empty[5] && my[6] && my[7]) || 84 | (my[4] && my[5] && empty[6] && my[7] && my[8])) 85 | ret = 1'b1; 86 | else 87 | ret = 1'b0; 88 | 89 | endmodule 90 | 91 | //------------------------------------------------------------------------------ 92 | // Recognize _***_ | _**_*_ | _*_**_ 93 | //------------------------------------------------------------------------------ 94 | module pattern_three( 95 | input wire [8:0] my, 96 | input wire [8:0] op, 97 | output reg ret 98 | ); 99 | 100 | wire [8:0] empty; 101 | assign empty = ~(my | op); 102 | 103 | always @ (*) 104 | if ((empty[0] && my[1] && my[2] && my[3] && empty[4]) || 105 | (empty[1] && my[2] && my[3] && my[4] && empty[5]) || 106 | (empty[2] && my[3] && my[4] && my[5] && empty[6]) || 107 | (empty[3] && my[4] && my[5] && my[6] && empty[7]) || 108 | (empty[4] && my[5] && my[6] && my[7] && empty[8]) || 109 | (empty[0] && my[1] && my[2] && empty[3] && my[4] && empty[5]) || 110 | (empty[1] && my[2] && my[3] && empty[4] && my[5] && empty[6]) || 111 | (empty[2] && my[3] && my[4] && empty[5] && my[6] && empty[7]) || 112 | (empty[3] && my[4] && my[5] && empty[6] && my[7] && empty[8]) || 113 | (empty[0] && my[1] && empty[2] && my[3] && my[4] && empty[5]) || 114 | (empty[1] && my[2] && empty[3] && my[4] && my[5] && empty[6]) || 115 | (empty[2] && my[3] && empty[4] && my[5] && my[6] && empty[7]) || 116 | (empty[3] && my[4] && empty[5] && my[6] && my[7] && empty[8])) 117 | ret = 1'b1; 118 | else 119 | ret = 1'b0; 120 | 121 | endmodule 122 | 123 | //------------------------------------------------------------------------------ 124 | // Recognize o_*** | ***_o 125 | //------------------------------------------------------------------------------ 126 | module pattern_fthree( 127 | input wire [8:0] my, 128 | input wire [8:0] op, 129 | output reg ret 130 | ); 131 | 132 | wire [8:0] empty; 133 | assign empty = ~(my | op); 134 | 135 | always @ (*) 136 | if ((op[0] && empty[1] && my[2] && my[3] && my[4]) || 137 | (op[1] && empty[2] && my[3] && my[4] && my[5]) || 138 | (op[2] && empty[3] && my[4] && my[5] && my[6]) || 139 | (op[3] && empty[4] && my[5] && my[6] && my[7]) || 140 | (op[4] && empty[5] && my[6] && my[7] && my[8]) || 141 | (my[0] && my[1] && my[2] && empty[3] && op[4]) || 142 | (my[1] && my[2] && my[3] && empty[4] && op[5]) || 143 | (my[2] && my[3] && my[4] && empty[5] && op[6]) || 144 | (my[3] && my[4] && my[5] && empty[6] && op[7]) || 145 | (my[4] && my[5] && my[6] && empty[7] && op[8])) 146 | ret = 1'b1; 147 | else 148 | ret = 1'b0; 149 | 150 | endmodule 151 | 152 | //------------------------------------------------------------------------------ 153 | // Recognize _**_ | _*_*_ 154 | //------------------------------------------------------------------------------ 155 | module pattern_two( 156 | input wire [8:0] my, 157 | input wire [8:0] op, 158 | output reg ret 159 | ); 160 | 161 | wire [8:0] empty; 162 | assign empty = ~(my | op); 163 | 164 | always @ (*) 165 | if ((empty[0] && my[1] && my[2] && empty[3]) || 166 | (empty[1] && my[2] && my[3] && empty[4]) || 167 | (empty[2] && my[3] && my[4] && empty[5]) || 168 | (empty[3] && my[4] && my[5] && empty[6]) || 169 | (empty[4] && my[5] && my[6] && empty[7]) || 170 | (empty[5] && my[6] && my[7] && empty[8]) || 171 | (empty[0] && my[1] && empty[2] && my[3] && empty[4]) || 172 | (empty[1] && my[2] && empty[3] && my[4] && empty[5]) || 173 | (empty[2] && my[3] && empty[4] && my[5] && empty[6]) || 174 | (empty[3] && my[4] && empty[5] && my[6] && empty[7]) || 175 | (empty[4] && my[5] && empty[6] && my[7] && empty[8])) 176 | ret = 1'b1; 177 | else 178 | ret = 1'b0; 179 | 180 | endmodule 181 | 182 | //------------------------------------------------------------------------------ 183 | // Recognize o***_ | _***o 184 | //------------------------------------------------------------------------------ 185 | module pattern_sthree( 186 | input wire [8:0] my, 187 | input wire [8:0] op, 188 | output reg ret 189 | ); 190 | 191 | wire [8:0] empty; 192 | assign empty = ~(my | op); 193 | 194 | always @ (*) 195 | if ((op[0] && my[1] && my[2] && my[3] && empty[4]) || 196 | (op[1] && my[2] && my[3] && my[4] && empty[5]) || 197 | (op[2] && my[3] && my[4] && my[5] && empty[6]) || 198 | (op[3] && my[4] && my[5] && my[6] && empty[7]) || 199 | (op[4] && my[5] && my[6] && my[7] && empty[8]) || 200 | (empty[0] && my[1] && my[2] && my[3] && op[4]) || 201 | (empty[1] && my[2] && my[3] && my[4] && op[5]) || 202 | (empty[2] && my[3] && my[4] && my[5] && op[6]) || 203 | (empty[3] && my[4] && my[5] && my[6] && op[7]) || 204 | (empty[4] && my[5] && my[6] && my[7] && op[8])) 205 | ret = 1'b1; 206 | else 207 | ret = 1'b0; 208 | 209 | endmodule 210 | 211 | //------------------------------------------------------------------------------ 212 | // Recognize o_** | **_o 213 | //------------------------------------------------------------------------------ 214 | module pattern_ftwo( 215 | input wire [8:0] my, 216 | input wire [8:0] op, 217 | output reg ret 218 | ); 219 | 220 | wire [8:0] empty; 221 | assign empty = ~(my | op); 222 | 223 | always @ (*) 224 | if ((op[0] && empty[1] && my[2] && my[3]) || 225 | (op[1] && empty[2] && my[3] && my[4]) || 226 | (op[2] && empty[3] && my[4] && my[5]) || 227 | (op[3] && empty[4] && my[5] && my[6]) || 228 | (op[4] && empty[5] && my[6] && my[7]) || 229 | (op[5] && empty[6] && my[7] && my[8]) || 230 | (my[0] && my[1] && empty[2] && op[3]) || 231 | (my[1] && my[2] && empty[3] && op[4]) || 232 | (my[2] && my[3] && empty[4] && op[5]) || 233 | (my[3] && my[4] && empty[5] && op[6]) || 234 | (my[4] && my[5] && empty[6] && op[7]) || 235 | (my[5] && my[6] && empty[7] && op[8])) 236 | ret = 1'b1; 237 | else 238 | ret = 1'b0; 239 | 240 | endmodule 241 | 242 | //------------------------------------------------------------------------------ 243 | // Recognize o**_ | _**o 244 | //------------------------------------------------------------------------------ 245 | module pattern_stwo( 246 | input wire [8:0] my, 247 | input wire [8:0] op, 248 | output reg ret 249 | ); 250 | 251 | wire [8:0] empty; 252 | assign empty = ~(my | op); 253 | 254 | always @ (*) 255 | if ((op[0] && my[1] && my[2] && empty[3]) || 256 | (op[1] && my[2] && my[3] && empty[4]) || 257 | (op[2] && my[3] && my[4] && empty[5]) || 258 | (op[3] && my[4] && my[5] && empty[6]) || 259 | (op[4] && my[5] && my[6] && empty[7]) || 260 | (op[5] && my[6] && my[7] && empty[8]) || 261 | (empty[0] && my[1] && my[2] && op[3]) || 262 | (empty[1] && my[2] && my[3] && op[4]) || 263 | (empty[2] && my[3] && my[4] && op[5]) || 264 | (empty[3] && my[4] && my[5] && op[6]) || 265 | (empty[4] && my[5] && my[6] && op[7]) || 266 | (empty[5] && my[6] && my[7] && op[8])) 267 | ret = 1'b1; 268 | else 269 | ret = 1'b0; 270 | 271 | endmodule 272 | -------------------------------------------------------------------------------- /src/logic/gobang_strategy.v: -------------------------------------------------------------------------------- 1 | `timescale 1ns / 1ps 2 | 3 | //------------------------------------------------------------------------------ 4 | // A simple strategy for the gobang game. 5 | //------------------------------------------------------------------------------ 6 | module gobang_strategy( 7 | input wire clk, // Clock 8 | input wire rst, // Reset 9 | input wire clr, // Clear 10 | input wire active, // Active signal 11 | input wire random, // Random signal 12 | 13 | input wire [8:0] black_i, // Row information 14 | input wire [8:0] black_j, // Column information 15 | input wire [8:0] black_ij, // Main diagonal information 16 | input wire [8:0] black_ji, // Counter diagonal information 17 | input wire [8:0] white_i, 18 | input wire [8:0] white_j, 19 | input wire [8:0] white_ij, 20 | input wire [8:0] white_ji, 21 | 22 | output reg [3:0] get_i, // Current row considered 23 | output reg [3:0] get_j, // Current column considered 24 | 25 | output reg [12:0] black_best_score, // Best possible score 26 | output reg [3:0] black_best_i, // Best row 27 | output reg [3:0] black_best_j, // Best column 28 | output reg [12:0] white_best_score, 29 | output reg [3:0] white_best_i, 30 | output reg [3:0] white_best_j 31 | ); 32 | 33 | // Chessboard parameters 34 | localparam BOARD_SIZE = 15; 35 | 36 | // State parameters 37 | localparam STATE_IDLE = 1'b0, 38 | STATE_WORKING = 1'b1; 39 | 40 | reg state; // Current state 41 | 42 | // Scores of the four directions 43 | wire [12:0] black_score_i, black_score_j, black_score_ij, black_score_ji; 44 | wire [12:0] white_score_i, white_score_j, white_score_ij, white_score_ji; 45 | 46 | // Total scores 47 | wire [12:0] black_score, white_score; 48 | assign black_score = black_score_i + black_score_j + 49 | black_score_ij + black_score_ji; 50 | assign white_score = white_score_i + white_score_j + 51 | white_score_ij + white_score_ji; 52 | 53 | // Score calculators 54 | score_calculator 55 | calc_black_i( 56 | .my(black_i), 57 | .op(white_i), 58 | .score(black_score_i) 59 | ), 60 | calc_black_j( 61 | .my(black_j), 62 | .op(white_j), 63 | .score(black_score_j) 64 | ), 65 | calc_black_ij( 66 | .my(black_ij), 67 | .op(white_ij), 68 | .score(black_score_ij) 69 | ), 70 | calc_black_ji( 71 | .my(black_ji), 72 | .op(white_ji), 73 | .score(black_score_ji) 74 | ), 75 | calc_white_i( 76 | .my(white_i), 77 | .op(black_i), 78 | .score(white_score_i) 79 | ), 80 | calc_white_j( 81 | .my(white_j), 82 | .op(black_j), 83 | .score(white_score_j) 84 | ), 85 | calc_white_ij( 86 | .my(white_ij), 87 | .op(black_ij), 88 | .score(white_score_ij) 89 | ), 90 | calc_white_ji( 91 | .my(white_ji), 92 | .op(black_ji), 93 | .score(white_score_ji) 94 | ); 95 | 96 | // FSM of the strategy 97 | // Every time the active signal comes, the strategy will run once 98 | always @ (posedge clk or negedge rst) begin 99 | if (!rst || clr) begin 100 | get_i <= 4'b0; 101 | get_j <= 4'b0; 102 | black_best_score <= 0; 103 | black_best_i <= BOARD_SIZE / 2; 104 | black_best_j <= BOARD_SIZE / 2; 105 | white_best_score <= 0; 106 | white_best_i <= BOARD_SIZE / 2; 107 | white_best_j <= BOARD_SIZE / 2; 108 | 109 | state <= STATE_IDLE; 110 | end 111 | else if (!active && state == STATE_IDLE) 112 | state <= STATE_WORKING; 113 | else if (active && state == STATE_WORKING) begin 114 | // Calculate the best positions 115 | if ((get_i == 4'b0 && get_j == 4'b0) || 116 | black_score > black_best_score || 117 | (black_score == black_best_score && random)) begin 118 | black_best_score <= black_score; 119 | black_best_i <= get_i; 120 | black_best_j <= get_j; 121 | end 122 | if ((get_i == 4'b0 && get_j == 4'b0) || 123 | white_score > white_best_score || 124 | (white_score == white_best_score && random)) begin 125 | white_best_score <= white_score; 126 | white_best_i <= get_i; 127 | white_best_j <= get_j; 128 | end 129 | 130 | // Move to the next position 131 | if (get_j == BOARD_SIZE - 1) begin 132 | if (get_i == BOARD_SIZE - 1) begin 133 | get_i <= 4'b0; 134 | get_j <= 4'b0; 135 | state <= STATE_IDLE; 136 | end 137 | else begin 138 | get_i <= get_i + 1'b1; 139 | get_j <= 4'b0; 140 | end 141 | end 142 | else 143 | get_j <= get_j + 1'b1; 144 | end 145 | end 146 | 147 | endmodule 148 | -------------------------------------------------------------------------------- /src/logic/score_calculator.v: -------------------------------------------------------------------------------- 1 | `timescale 1ns / 1ps 2 | 3 | //------------------------------------------------------------------------------ 4 | // Calculate the score of a given pattern 5 | //------------------------------------------------------------------------------ 6 | module score_calculator( 7 | input wire [8:0] my, // Pattern of my side 8 | input wire [8:0] op, // Pattern of the opposite side 9 | output reg [12:0] score // The score of the given pattern 10 | ); 11 | 12 | wire [8:0] my_next; 13 | assign my_next = my | 9'b000010000; 14 | 15 | wire score2, score4, score5, score8, score15, 16 | score40, score70, score300, score2000; 17 | 18 | // Pattern recognizers 19 | pattern_stwo pattern2(my_next, op, score2); 20 | pattern_ftwo pattern4(my_next, op, score4); 21 | pattern_sthree pattern5(my_next, op, score5); 22 | pattern_two pattern8(my_next, op, score8); 23 | pattern_fthree pattern15(my_next, op, score15); 24 | pattern_three pattern40(my_next, op, score40); 25 | pattern_ffour pattern70(my_next, op, score70); 26 | pattern_four pattern300(my_next, op, score300); 27 | pattern_five pattern2000(my_next, score2000); 28 | 29 | always @ (*) 30 | if (my[4] || op[4]) 31 | // Invalid pattern 32 | score = 0; 33 | else if (score2000) 34 | score = 2000; 35 | else if (score300) 36 | score = 300; 37 | else if (score70) 38 | score = 70; 39 | else if (score40) 40 | score = 40; 41 | else if (score15) 42 | score = 15; 43 | else if (score8) 44 | score = 8; 45 | else if (score5) 46 | score = 5; 47 | else if (score4) 48 | score = 4; 49 | else if (score2) 50 | score = 2; 51 | else 52 | score = 1; 53 | 54 | endmodule 55 | -------------------------------------------------------------------------------- /src/logic/win_checker.v: -------------------------------------------------------------------------------- 1 | `timescale 1ns / 1ps 2 | 3 | //------------------------------------------------------------------------------ 4 | // Checker to check if someone wins the game 5 | //------------------------------------------------------------------------------ 6 | module win_checker( 7 | input wire clk, // Clock 8 | input wire rst, // Reset 9 | input wire clr, // Clear 10 | input wire active, // Active signal 11 | 12 | input wire [8:0] black_i, // Row information 13 | input wire [8:0] black_j, // Column information 14 | input wire [8:0] black_ij, // Main diagonal information 15 | input wire [8:0] black_ji, // Counter diagonal information 16 | input wire [8:0] white_i, 17 | input wire [8:0] white_j, 18 | input wire [8:0] white_ij, 19 | input wire [8:0] white_ji, 20 | 21 | output reg [3:0] get_i, // Current row considered 22 | output reg [3:0] get_j, // Current column considered 23 | output reg is_win // If someone wins the game 24 | ); 25 | 26 | // Chessboard parameters 27 | localparam BOARD_SIZE = 15; 28 | 29 | // State parameters 30 | localparam STATE_IDLE = 1'b0, 31 | STATE_WORKING = 1'b1; 32 | 33 | reg state; // Current state 34 | 35 | // Pattern recognizers 36 | wire b0, b1, b2, b3, w0, w1, w2, w3; 37 | pattern_five pattern_b0(black_i, b0), 38 | pattern_b1(black_j, b1), 39 | pattern_b2(black_ij, b2), 40 | pattern_b3(black_ji, b3), 41 | pattern_w0(white_i, w0), 42 | pattern_w1(white_j, w1), 43 | pattern_w2(white_ij, w2), 44 | pattern_w3(white_ji, w3); 45 | 46 | // FSM of the checker 47 | // Every time the active signal comes, the checker will run once 48 | always @ (posedge clk or negedge rst) begin 49 | if (!rst || clr) begin 50 | get_i <= 4'b0; 51 | get_j <= 4'b0; 52 | is_win <= 0; 53 | 54 | state <= STATE_IDLE; 55 | end 56 | else if (!active && state == STATE_IDLE) 57 | state <= STATE_WORKING; 58 | else if (active && state == STATE_WORKING) begin 59 | // Check if someone wins the game 60 | if (get_i == 4'b0 && get_j == 4'b0) 61 | is_win <= b0 | b1 | b2 | b3 | w0 | w1 | w2 | w3; 62 | else 63 | is_win <= is_win | b0 | b1 | b2 | b3 | w0 | w1 | w2 | w3; 64 | 65 | // Move to the next position 66 | if (get_j == BOARD_SIZE - 1) begin 67 | if (get_i == BOARD_SIZE - 1) begin 68 | get_i <= 4'b0; 69 | get_j <= 4'b0; 70 | state <= STATE_IDLE; 71 | end 72 | else begin 73 | get_i <= get_i + 1'b1; 74 | get_j <= 4'b0; 75 | end 76 | end 77 | else 78 | get_j <= get_j + 1'b1; 79 | end 80 | end 81 | 82 | endmodule 83 | -------------------------------------------------------------------------------- /src/random/random_generator.v: -------------------------------------------------------------------------------- 1 | `timescale 1ns / 1ps 2 | 3 | //------------------------------------------------------------------------------ 4 | // Generate a random number 5 | //------------------------------------------------------------------------------ 6 | module random_generator( 7 | input wire clk, // Clock 8 | input wire rst, // Reset 9 | input wire load, // Load signal 10 | input wire [31:0] seed, // Random seed 11 | output reg [31:0] rand_num // A random number 12 | ); 13 | 14 | always @ (posedge clk or negedge rst) 15 | if (!rst) 16 | rand_num <= 32'b0; 17 | else if (load) 18 | // Load the random seed 19 | rand_num <= seed; 20 | else 21 | rand_num <= {rand_num[30:0], 22 | rand_num[31] ^ rand_num[29] ^ rand_num[28] ^ 23 | rand_num[27] ^ rand_num[23] ^ rand_num[20] ^ 24 | rand_num[19] ^ rand_num[17] ^ rand_num[15] ^ 25 | rand_num[14] ^ rand_num[12] ^ rand_num[11] ^ 26 | rand_num[9] ^ rand_num[4] ^ rand_num[3] ^ 27 | rand_num[2]}; 28 | 29 | endmodule 30 | --------------------------------------------------------------------------------