Thanks Anamaya, Sanjeev and Sohan for pointing out at new aspects that were missed by initial code.
I combined all the comments and information from above discussion and now have written following code with easier visualization of snapshot.
There will be three state of the snapshot:
- INIT - all empty spaces
- MID_GAME - 2 turns by each player and 5 empty space (anyone may win)
- OVER - game completed, either WON by X/O’s or it’s a DRAW.
I have printed output of 10 games with all three snapshots covered.
Please reply if you find anything that needs correction or any additional functionality needs to be added.
module ttt;
class game;
typedef enum int { _ = 0, X =-1 , O = 1, X_WIN = -3, O_WIN = 3 } E_val;
typedef enum int { INIT = -1, MID_GAME = 0 , OVER = 1} E_game_status;
rand E_val a[3][3];
// current state of the game for snapshot
rand E_game_status state;
// if set then game is won, otherwise it's a draw
rand bit game_won;
constraint C_game_state {
state dist {INIT:=25, MID_GAME:=35, OVER:=40};
}
constraint C_game_play{
solve state before a;
solve game_won before a;
if(state==INIT) {
// init everything to empty
foreach (a[i,j]) {
a[i][j] inside { _ };
}
} else if (state==OVER) {
// valid range
foreach (a[i,j]) {
a[i][j] inside {_, X, O};
}
// game over constraint , no empty space left && minimum 4 turns by each player
// No empley space
a[0].sum() with (int'(item == _)) +
a[1].sum() with (int'(item == _)) +
a[2].sum() with (int'(item == _)) == 0;
// min 4 turns by O's
a[0].sum() with (int'(item == O)) +
a[1].sum() with (int'(item == O)) +
a[2].sum() with (int'(item == O)) >= 4;
// min 4 turns by X's
a[0].sum() with (int'(item == X)) +
a[1].sum() with (int'(item == X)) +
a[2].sum() with (int'(item == X)) >= 4;
// game is won in following conditions, otherwise it will be a draw
if(game_won) {
// row wins
a[0].sum() inside {X_WIN,O_WIN} ||
a[1].sum() inside {X_WIN,O_WIN} ||
a[2].sum() inside {X_WIN,O_WIN} ||
// column wins
a[0][0] + a[1][0] + a[2][0] inside {X_WIN, O_WIN} ||
a[0][1] + a[1][1] + a[2][1] inside {X_WIN, O_WIN} ||
a[0][2] + a[1][2] + a[2][2] inside {X_WIN, O_WIN} ||
// cross wins
a[0][0] + a[1][1] + a[2][2] inside {X_WIN, O_WIN} ||
a[0][2] + a[1][1] + a[2][0] inside {X_WIN, O_WIN} ;
} else {
// No row wins
!( a[0].sum() inside {X_WIN,O_WIN} ) &&
!( a[1].sum() inside {X_WIN,O_WIN} ) &&
!( a[2].sum() inside {X_WIN,O_WIN} ) &&
// No column wins
! ( a[0][0] + a[1][0] + a[2][0] inside {X_WIN, O_WIN} ) &&
! ( a[0][1] + a[1][1] + a[2][1] inside {X_WIN, O_WIN} ) &&
! ( a[0][2] + a[1][2] + a[2][2] inside {X_WIN, O_WIN} ) &&
// No cross wins
! ( a[0][0] + a[1][1] + a[2][2] inside {X_WIN, O_WIN} ) &&
! ( a[0][2] + a[1][1] + a[2][0] inside {X_WIN, O_WIN} ) ;
}
} else if (state==MID_GAME) {
// valid range
foreach (a[i,j]) {
a[i][j] inside {_, X, O};
}
// game NOT over constraint : 2 turns by each player && 5 empty space left
// 5 empty space
a[0].sum() with (int'(item == _)) +
a[1].sum() with (int'(item == _)) +
a[2].sum() with (int'(item == _)) == 5;
// 2 turns by each player, so total sum has to be ZERO
a[0].sum() + a[1].sum() + a[2].sum() == 0;
}
}
endclass:game
initial
begin
game g1;
g1 = new();
repeat (10) begin
assert(g1.randomize());
if (g1.state != game::OVER)
$display("\nGame State : %p", g1.state);
else
$display("\nGame State : %p and %0s ", g1.state, g1.game_won ? "WON" :"DRAW");
$display("%p | %p | %p", g1.a[0][0],g1.a[0][1],g1.a[0][2]);
$display("--+---+---");
$display("%p | %p | %p", g1.a[1][0],g1.a[1][1],g1.a[1][2]);
$display("--+---+---");
$display("%p | %p | %p", g1.a[2][0],g1.a[2][1],g1.a[2][2]);
end
end
endmodule
Here is the output for one of the run:
ncsim> run
Game State : INIT
_ | _ | _
--+---+---
_ | _ | _
--+---+---
_ | _ | _
Game State : OVER and WON
X | X | X
--+---+---
O | O | O
--+---+---
O | X | O
Game State : MID_GAME
O | X | _
--+---+---
_ | O | _
--+---+---
_ | _ | X
Game State : MID_GAME
_ | O | X
--+---+---
_ | _ | X
--+---+---
_ | O | _
Game State : OVER and DRAW
O | O | X
--+---+---
X | X | O
--+---+---
O | X | X
Game State : MID_GAME
_ | _ | O
--+---+---
_ | _ | _
--+---+---
X | X | O
Game State : MID_GAME
O | _ | X
--+---+---
_ | _ | O
--+---+---
_ | _ | X
Game State : OVER and DRAW
O | X | O
--+---+---
O | O | X
--+---+---
X | O | X
Game State : OVER and WON
X | X | O
--+---+---
O | O | O
--+---+---
O | X | X
Game State : MID_GAME
O | _ | _
--+---+---
_ | _ | O
--+---+---
X | X | _