Skip to content

Commit

Permalink
Migrate player and strategy support
Browse files Browse the repository at this point in the history
  • Loading branch information
tturocy committed Sep 1, 2023
1 parent 01a551d commit 21b6ad1
Show file tree
Hide file tree
Showing 3 changed files with 25 additions and 41 deletions.
5 changes: 3 additions & 2 deletions src/pygambit/core/mixed.pxi
Original file line number Diff line number Diff line change
Expand Up @@ -87,7 +87,7 @@ cdef class MixedStrategyProfile:
elif isinstance(index, Strategy):
return self._getprob_strategy(index)
elif isinstance(index, Player):
class MixedStrategy(object):
class MixedStrategy:
def __init__(self, profile, player):
self.profile = profile
self.player = player
Expand Down Expand Up @@ -129,7 +129,8 @@ cdef class MixedStrategyProfile:
index.__class__.__name__)

def _setprob_player(self, Player player, value):
class Filler(object): pass
class Filler:
pass
try:
for (s, v) in zip_longest(player.strategies, value, fillvalue=Filler()):
if isinstance(s, Filler) or isinstance(v, Filler):
Expand Down
53 changes: 18 additions & 35 deletions src/pygambit/core/player.pxi
Original file line number Diff line number Diff line change
Expand Up @@ -20,25 +20,27 @@
# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#

cdef class Infosets(Collection):
@cython.cclass
class Infosets(Collection):
"""The set of information sets at which a player has the decision."""
cdef c_GamePlayer player
player = cython.declare(c_GamePlayer)

def __len__(self):
"""The number of information sets at which the player has the decision."""
return self.player.deref().NumInfosets()

def __getitem__(self, iset):
if not isinstance(iset, int):
return Collection.__getitem__(self, iset)
cdef Infoset s
s = Infoset()
s.infoset = self.player.deref().GetInfoset(iset+1)
return s


cdef class Strategies(Collection):
@cython.cclass
class Strategies(Collection):
"""The set of strategies available to a player."""
cdef c_GamePlayer player
player = cython.declare(c_GamePlayer)

def add(self, label="") -> Strategy:
"""Add a new strategy to the set of the player's strategies.
Expand All @@ -52,12 +54,10 @@ cdef class Strategies(Collection):
TypeError
If called on a game which has an extensive representation.
"""
cdef Game g
g = Game()
g.game = self.player.deref().GetGame()
if g.is_tree:
raise TypeError("Adding strategies is only applicable to games in strategic form")
cdef Strategy s
s = Strategy()
s.strategy = self.player.deref().NewStrategy()
s.label = str(label)
Expand All @@ -70,7 +70,6 @@ cdef class Strategies(Collection):
def __getitem__(self, st):
if not isinstance(st, int):
return Collection.__getitem__(self, st)
cdef Strategy s
s = Strategy()
s.strategy = self.player.deref().GetStrategy(st+1)
return s
Expand Down Expand Up @@ -103,10 +102,11 @@ cdef class PlayerSupportStrategies(Collection):
return s


cdef class Player:
@cython.cclass
class Player:
"""Represents a player in a :py:class:`Game`."""
cdef c_GamePlayer player
cdef StrategicRestriction restriction
player = cython.declare(c_GamePlayer)
restriction = cython.declare(StrategicRestriction)

def __repr__(self):
if self.is_chance:
Expand All @@ -117,29 +117,18 @@ cdef class Player:
f"in game '{self.game.title}'>"
)

def __richcmp__(self, other, whichop):
if isinstance(other, Player):
if whichop == 2:
return self.player.deref() == (<Player>other).player.deref()
elif whichop == 3:
return self.player.deref() != (<Player>other).player.deref()
else:
raise NotImplementedError
else:
if whichop == 2:
return False
elif whichop == 3:
return True
else:
raise NotImplementedError
def __eq__(self, other: typing.Any) -> bool:
return isinstance(other, Player) and self.player.deref() == cython.cast(Player, other).player.deref()

def __ne__(self, other: typing.Any) -> bool:
return not isinstance(other, Player) or self.player.deref() == cython.cast(Player, other).player.deref()

def __hash__(self):
return long(<long>self.player.deref())
def __hash__(self) -> int:
return cython.cast(cython.long, self.player.deref())

@property
def game(self) -> Game:
"""Gets the :py:class:`Game` to which the player belongs."""
cdef Game g
if self.restriction is not None:
return self.restriction
g = Game()
Expand Down Expand Up @@ -175,8 +164,6 @@ cdef class Player:
@property
def strategies(self) -> Strategies:
"""Returns the set of strategies belonging to the player."""
cdef Strategies s
cdef PlayerSupportStrategies ps
if self.restriction is not None:
ps = PlayerSupportStrategies(self, self.restriction)
return ps
Expand All @@ -187,29 +174,25 @@ cdef class Player:
@property
def infosets(self) -> Infosets:
"""Returns the set of information sets at which the player has the decision."""
cdef Infosets s
s = Infosets()
s.player = self.player
return s

@property
def min_payoff(self) -> Rational:
"""Returns the smallest payoff for the player in any outcome of the game."""
cdef Game g
g = Game()
g.game = self.player.deref().GetGame()
return rat_to_py(g.game.deref().GetMinPayoff(self.number + 1))

@property
def max_payoff(self) -> Rational:
"""Returns the largest payoff for the player in any outcome of the game."""
cdef Game g
g = Game()
g.game = self.player.deref().GetGame()
return rat_to_py(g.game.deref().GetMaxPayoff(self.number + 1))

def unrestrict(self):
cdef Game g
g = Game()
g.game = self.player.deref().GetGame()
return g.players[self.number]
8 changes: 4 additions & 4 deletions src/pygambit/core/stratspt.pxi
Original file line number Diff line number Diff line change
Expand Up @@ -19,16 +19,17 @@
# along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#

import cython
from cython.operator cimport dereference as deref
from libcpp.memory cimport unique_ptr

cdef class StrategySupportProfile(Collection):
@cython.cclass
class StrategySupportProfile(Collection):
"""A set-like object representing a subset of the strategies in game.
A StrategySupportProfile always contains at least one strategy for each player
in the game.
"""
cdef unique_ptr[c_StrategySupportProfile] support
support = cython.declare(unique_ptr[c_StrategySupportProfile])

def __init__(self, strategies, Game game not None):
if len(set([strat.player.number for strat in strategies])) != len(game.players):
Expand All @@ -44,7 +45,6 @@ cdef class StrategySupportProfile(Collection):
@property
def game(self) -> Game:
"""The `Game` on which the support profile is defined."""
cdef Game g
g = Game()
g.game = deref(self.support).GetGame()
return g
Expand Down

0 comments on commit 21b6ad1

Please sign in to comment.