Deep CFR 정보 상태 encoding 확장
This commit is contained in:
@@ -1,11 +1,23 @@
|
||||
# cython: language_level=3, boundscheck=False, wraparound=False, cdivision=True, initializedcheck=False
|
||||
"""Minimal deterministic information-state encoding for Deep CFR scaffolding."""
|
||||
"""Deterministic information-state encoding for Deep CFR."""
|
||||
|
||||
from coolrl_lost_cities.games.classic.game cimport GameState
|
||||
|
||||
|
||||
cdef int input_dim_c(GameState state) noexcept:
|
||||
return 5 + state.hand_size * 3 + 2 * state.hand_size + 1 + state.n_colors
|
||||
cdef int action_size = 2 * state.hand_size + 1 + state.n_colors
|
||||
cdef int card_type_size = state.n_colors * (state.n_ranks + 1)
|
||||
return (
|
||||
5
|
||||
+ state.hand_size * 3
|
||||
+ 2 * state.n_colors * 4
|
||||
+ state.n_colors * 4
|
||||
+ card_type_size
|
||||
+ 3
|
||||
+ 1
|
||||
+ state.n_colors + 1
|
||||
+ action_size
|
||||
)
|
||||
|
||||
|
||||
cdef int encode_info_state_c(GameState state, int player, float* out) except -1:
|
||||
@@ -15,6 +27,16 @@ cdef int encode_info_state_c(GameState state, int player, float* out) except -1:
|
||||
cdef int color
|
||||
cdef int rank
|
||||
cdef int action_size = 2 * state.hand_size + 1 + state.n_colors
|
||||
cdef int card_type_size = state.n_colors * (state.n_ranks + 1)
|
||||
cdef int public_base
|
||||
cdef int player_index
|
||||
cdef int length
|
||||
cdef int top_card
|
||||
cdef int card_index
|
||||
cdef int max_expedition_len = state.n_ranks + state.n_handshakes
|
||||
cdef float score_denom = <float>(
|
||||
max(1, state.bonus_amount + (state.n_ranks * (state.n_ranks + 1)) * (state.n_handshakes + 1))
|
||||
)
|
||||
cdef int action_count
|
||||
cdef int actions[64]
|
||||
cdef int i
|
||||
@@ -49,6 +71,61 @@ cdef int encode_info_state_c(GameState state, int player, float* out) except -1:
|
||||
out[idx + 2] = 0.0
|
||||
idx += 3
|
||||
|
||||
for player_index in range(2):
|
||||
for color in range(state.n_colors):
|
||||
card_index = state._expedition_len_index(player_index, color)
|
||||
length = state.expedition_lens[card_index]
|
||||
out[idx] = <float>length / <float>max_expedition_len
|
||||
out[idx + 1] = <float>state.last_numeric_ranks[card_index] / <float>state.n_ranks
|
||||
out[idx + 2] = <float>state.handshake_counts[card_index] / <float>max(1, state.n_handshakes)
|
||||
out[idx + 3] = <float>state.expedition_scores[card_index] / score_denom
|
||||
idx += 4
|
||||
|
||||
for color in range(state.n_colors):
|
||||
length = state.discard_lens[color]
|
||||
out[idx] = <float>length / <float>max_expedition_len
|
||||
if length > 0:
|
||||
top_card = state.discard_cards[state._discard_index(color, length - 1)]
|
||||
out[idx + 1] = 1.0
|
||||
out[idx + 2] = <float>(state._card_color(top_card) + 1) / <float>state.n_colors
|
||||
out[idx + 3] = <float>state._card_rank(top_card) / <float>state.n_ranks
|
||||
else:
|
||||
out[idx + 1] = 0.0
|
||||
out[idx + 2] = 0.0
|
||||
out[idx + 3] = 0.0
|
||||
idx += 4
|
||||
|
||||
public_base = idx
|
||||
for i in range(card_type_size):
|
||||
out[public_base + i] = 0.0
|
||||
for player_index in range(2):
|
||||
for color in range(state.n_colors):
|
||||
card_index = state._expedition_len_index(player_index, color)
|
||||
for i in range(state.expedition_lens[card_index]):
|
||||
card = state.expedition_cards[state._expedition_index(player_index, color, i)]
|
||||
out[public_base + state._card_color(card) * (state.n_ranks + 1) + state._card_rank(card)] += 1.0
|
||||
for color in range(state.n_colors):
|
||||
for i in range(state.discard_lens[color]):
|
||||
card = state.discard_cards[state._discard_index(color, i)]
|
||||
out[public_base + state._card_color(card) * (state.n_ranks + 1) + state._card_rank(card)] += 1.0
|
||||
idx += card_type_size
|
||||
|
||||
out[idx] = <float>state.total_scores[player] / score_denom
|
||||
out[idx + 1] = <float>state.total_scores[1 - player] / score_denom
|
||||
out[idx + 2] = <float>(state.total_scores[player] - state.total_scores[1 - player]) / score_denom
|
||||
idx += 3
|
||||
|
||||
out[idx] = <float>state.turn_count / <float>max(1, state.total_cards * 2)
|
||||
idx += 1
|
||||
|
||||
for i in range(state.n_colors + 1):
|
||||
out[idx + i] = 0.0
|
||||
if state.pending_discarded_color < 0:
|
||||
out[idx + state.n_colors] = 1.0
|
||||
else:
|
||||
out[idx + state.pending_discarded_color] = 1.0
|
||||
idx += state.n_colors + 1
|
||||
|
||||
for i in range(action_size):
|
||||
out[idx + i] = 0.0
|
||||
action_count = state._unified_legal_actions_c(actions)
|
||||
|
||||
@@ -92,6 +92,7 @@ def test_encode_info_state_is_deterministic_and_matches_legal_mask_tail() -> Non
|
||||
|
||||
assert encoded.dtype == np.float32
|
||||
assert encoded.shape == (input_dim(state),)
|
||||
assert input_dim(state) > 5 + state.config.hand_size * 3 + len(legal_mask)
|
||||
np.testing.assert_array_equal(encoded, encoded_again)
|
||||
np.testing.assert_array_equal(encoded[-len(legal_mask) :], legal_mask)
|
||||
|
||||
|
||||
Reference in New Issue
Block a user