Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
39 changes: 39 additions & 0 deletions .github/workflows/CI.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
name: CI
on:
push:
branches:
- master
tags: '*'
pull_request:
concurrency:
# Skip intermediate builds: always.
# Cancel intermediate builds: only if it is a pull request build.
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: ${{ startsWith(github.ref, 'refs/pull/') }}
jobs:
test:
name: Julia ${{ matrix.version }} - ${{ matrix.os }} - ${{ matrix.arch }} - ${{ github.event_name }}
runs-on: ${{ matrix.os }}
strategy:
fail-fast: false
matrix:
version:
- '1'
- '1.6'
os:
- ubuntu-latest
arch:
- x64
steps:
- uses: actions/checkout@v2
- uses: julia-actions/setup-julia@v1
with:
version: ${{ matrix.version }}
arch: ${{ matrix.arch }}
- uses: julia-actions/cache@v1
- uses: julia-actions/julia-buildpkg@v1
- uses: julia-actions/julia-runtest@v1
- uses: julia-actions/julia-processcoverage@v1
- uses: codecov/codecov-action@v2
with:
files: lcov.info
8 changes: 4 additions & 4 deletions Project.toml
Original file line number Diff line number Diff line change
@@ -1,16 +1,16 @@
name = "OpenSpiel"
uuid = "ceb70bd2-fe3f-44f0-b81f-41608acaf2f2"
authors = ["Jun Tian <[email protected]>"]
version = "0.1.3"
version = "0.1.4"

[deps]
CxxWrap = "1f15a43c-97ca-5a2a-ae31-89f07a497df4"
OpenSpiel_jll = "bd10a763-4654-5023-a028-c4918c6cd33e"

[compat]
CxxWrap = "0.10"
OpenSpiel_jll = "0.1"
julia = "1.3"
CxxWrap = "0.12"
OpenSpiel_jll = "1"
julia = "1.6"

[extras]
Random = "9a3f8284-a2c9-5f02-9a11-845980a1fd5c"
Expand Down
215 changes: 110 additions & 105 deletions test/games_simulation.jl
Original file line number Diff line number Diff line change
@@ -1,136 +1,141 @@
@testset "games simulation" begin

MAX_ACTIONS_PER_GAME = 1000
MAX_ACTIONS_PER_GAME = 1000

SPIEL_GAMES_LIST = registered_games()
SPIEL_GAMES_LIST = registered_games()

SPIEL_LOADABLE_GAMES_LIST = [
g for g in SPIEL_GAMES_LIST if default_loadable(g)
]
SPIEL_LOADABLE_GAMES_LIST = [
g for g in SPIEL_GAMES_LIST if default_loadable(g)
]

@test length(SPIEL_LOADABLE_GAMES_LIST) >= 38
@test length(SPIEL_LOADABLE_GAMES_LIST) >= 38

SPIEL_SIMULTANEOUS_GAMES_LIST = [
g for g in SPIEL_LOADABLE_GAMES_LIST
if dynamics(g) == SIMULTANEOUS
]
SPIEL_SIMULTANEOUS_GAMES_LIST = [
g for g in SPIEL_LOADABLE_GAMES_LIST
if dynamics(g) == SIMULTANEOUS
]

@test length(SPIEL_SIMULTANEOUS_GAMES_LIST) >= 14
@test length(SPIEL_SIMULTANEOUS_GAMES_LIST) >= 14

SPIEL_MULTIPLAYER_GAMES_LIST = [
(g, p)
for g in SPIEL_LOADABLE_GAMES_LIST
for p in max(min_num_players(g), 2) : min(max_num_players(g), 6)
if (max_num_players(g) > 2) &&
SPIEL_MULTIPLAYER_GAMES_LIST = [
(g, p)
for g in SPIEL_LOADABLE_GAMES_LIST
for p in max(min_num_players(g), 2):min(max_num_players(g), 6)
if (max_num_players(g) > 2) &&
(max_num_players(g) > min_num_players(g)) &&
(short_name(g) != "tiny_hanabi") && # default payoff only works for 2p
(short_name(g) != "universal_poker")
]
]

@test length(SPIEL_MULTIPLAYER_GAMES_LIST) >= 35
@test length(SPIEL_MULTIPLAYER_GAMES_LIST) >= 35

function apply_action_test_clone(state, action)
state_copy = copy(state)
@test string(state) == string(state_copy)
@test history(state) == history(state_copy)
function apply_action_test_clone(state, action)
state_copy = copy(state)
@test string(state) == string(state_copy)
@test history(state) == history(state_copy)

apply_action(state, action)
apply_action(state_copy, action)
apply_action(state, action)
apply_action(state_copy, action)

@test string(state) == string(state_copy)
@test history(state) == history(state_copy)
end
@test string(state) == string(state_copy)
@test history(state) == history(state_copy)
end

function serialize_deserialize(game, state)
ser_str = serialize_game_and_state(game, state)
new_game, new_state = deserialize_game_and_state(ser_str)
@test string(game) == string(new_game)
@test string(state) == string(new_state)
end
function serialize_deserialize(game, state)
ser_str = serialize_game_and_state(game, state)
new_game, new_state = deserialize_game_and_state(ser_str)
@test string(game) == string(new_game)
@test string(state) == string(new_state)
end

function simulate_game(game)
@info "simulating game $(short_name(get_type(game)))"
min_u, max_u = min_utility(game), max_utility(game)
@test min_u < max_u
function simulate_game(game)
@info "simulating game $(short_name(get_type(game)))"
min_u, max_u = min_utility(game), max_utility(game)
@test min_u < max_u

state = new_initial_state(game)
total_actions = 0

next_serialize_check = 1

while !is_terminal(state) && (total_actions <= MAX_ACTIONS_PER_GAME)
total_actions += 1

# Serialize/Deserialize is costly. Only do it every power of 2 actions.
if total_actions >= next_serialize_check
serialize_deserialize(game, state)
next_serialize_check *= 2
end

# The state can be of four different types: chance node,
# simultaneous node, decision node or mean field node.
if is_chance_node(state)
# Chance node: sample an outcome
outcomes = chance_outcomes(state)
@test length(outcomes) > 0
action_list, prob_list = zip(outcomes...)
action = action_list[sample(weights(collect(prob_list)))]
apply_action(state, action)
elseif is_simultaneous_node(state)
chosen_actions = [
rand(legal_actions(state, pid - 1))
for pid in 1:num_players(game)
] # in julia, index starts with 1
# Apply the joint action and test cloning states.
apply_action_test_clone(state, chosen_actions)
elseif is_mean_field_node(state)
num_states = length(distribution_support(state))
update_distribution(
state, StdVector([1.0 / num_states for _ in 1:num_states]))
else
@test is_player_node(state)
# Decision node: sample action for the single current player
action = rand(legal_actions(state, current_player(state)))
# Apply action and test state cloning.
apply_action_test_clone(state, action)
end
end

state = new_initial_state(game)
total_actions = 0
@test total_actions > 0

next_serialize_check = 1
if is_terminal(state)
# Check there are no legal actions.
@test length(legal_actions(state)) == 0
for player in 0:(num_players(game)-1)
@test length(legal_actions(state, player)) == 0
end

while !is_terminal(state) && (total_actions <= MAX_ACTIONS_PER_GAME)
total_actions += 1
utilities = returns(state)

# Serialize/Deserialize is costly. Only do it every power of 2 actions.
if total_actions >= next_serialize_check
serialize_deserialize(game, state)
next_serialize_check *= 2
end
for u in utilities
@test u >= min_utility(game)
@test u <= max_utility(game)
end

# The state can be three different types: chance node,
# simultaneous node, or decision node
if is_chance_node(state)
# Chance node: sample an outcome
outcomes = chance_outcomes(state)
@test length(outcomes) > 0
action_list, prob_list = zip(outcomes...)
action = action_list[sample(weights(collect(prob_list)))]
apply_action(state, action)
elseif is_simultaneous_node(state)
chosen_actions = [
rand(legal_actions(state, pid-1))
for pid in 1:num_players(game)
] # in julia, index starts with 1
# Apply the joint action and test cloning states.
apply_action_test_clone(state, chosen_actions)
@info "Simulation of game $game" total_actions utilities
else
# Decision node: sample action for the single current player
action = rand(legal_actions(state, current_player(state)))
# Apply action and test state cloning.
apply_action_test_clone(state, action)
@info "Simulation of game $game terminated after maximum number of actions $MAX_ACTIONS_PER_GAME"
end
end

@test total_actions > 0

if is_terminal(state)
# Check there are no legal actions.
@test length(legal_actions(state)) == 0
for player in 0:(num_players(game)-1)
@test length(legal_actions(state, player)) == 0
end

utilities = returns(state)

for u in utilities
@test u >= min_utility(game)
@test u <= max_utility(game)
end

@info "Simulation of game $game" total_actions utilities
else
@info "Simulation of game $game terminated after maximum number of actions $MAX_ACTIONS_PER_GAME"
for game_info in SPIEL_LOADABLE_GAMES_LIST
game = load_game(short_name(game_info))
@test num_players(game) >= min_num_players(game_info)
@test num_players(game) <= max_num_players(game_info)
simulate_game(game)
end
end

for game_info in SPIEL_LOADABLE_GAMES_LIST
game = load_game(short_name(game_info))
@test num_players(game) >= min_num_players(game_info)
@test num_players(game) <= max_num_players(game_info)
simulate_game(game)
end

for game_info in SPIEL_SIMULTANEOUS_GAMES_LIST
converted_game = load_game_as_turn_based(short_name(game_info))
simulate_game(converted_game)
end
for game_info in SPIEL_SIMULTANEOUS_GAMES_LIST
converted_game = load_game_as_turn_based(short_name(game_info))
simulate_game(converted_game)
end

for (game_info, n) in SPIEL_MULTIPLAYER_GAMES_LIST
game = load_game(short_name(game_info); players=GameParameter(n))
simulate_game(game)
end
for (game_info, n) in SPIEL_MULTIPLAYER_GAMES_LIST
game = load_game(short_name(game_info); players=GameParameter(n))
simulate_game(game)
end

simulate_game(load_game("breakthrough(rows=6,columns=6)"))
simulate_game(load_game("pig(players=2,winscore=15)"))
simulate_game(load_game("breakthrough(rows=6,columns=6)"))
simulate_game(load_game("pig(players=2,winscore=15)"))

end
end