我正在写一个纸牌游戏,并且一直在使用以下方法让下一个玩家转过身来
游戏的方向可以是前进或后退,它也需要尊重这一点
private Player GetNextPlayer()
{
int currentPlayerIndex = Players.FindIndex(o => o.IsThisPlayersTurn);
Player nextPlayer;
if (_direction.Equals(Direction.Forwards))
{
nextPlayer = currentPlayerIndex == Players.Count - 1 ? Players[0] : Players[currentPlayerIndex + 1];
}
else
{
nextPlayer = currentPlayerIndex == 0 ? Players[Players.Count - 1] : Players[currentPlayerIndex - 1];
}
return nextPlayer;
}
这一点很好,直到玩家完成游戏。然后它可能会返回不再在游戏中的玩家。
当玩家完成游戏时,他们的PlayerState是HasNoCards
所以我把它改成了这个,但在某些情况下似乎有些错误
public Player GetNextPlayer()
{
var players = Players.Where(o => o.PlayerState != PlayerState.HasNoCards);
if (Direction.Equals(Direction.Backwards))
{
players = players.Reverse();
}
bool selectNextPlayer = false;
foreach (Player player in players)
{
if (selectNextPlayer)
{
return player;
}
if (player.IsThisPlayersTurn)
{
selectNextPlayer = true;
}
}
return players.First();
}
我认为必须有一个聪明的方法让linq说“获得下一个玩家,其中Player.PlayerState不是PlayerState.HasNoCards”
有什么想法吗?
我应该补充一点,我无法从列表中删除播放器来解决问题,因为它会阻止我的数据绑定
修改
我对第二种方法无法处理的场景进行了单元测试失败。当一个玩家在方向向后时播放他们的最后一张牌时。当我立即从列表中过滤当前玩家时,使用
var players = Players.Where(o => o.PlayerState != PlayerState.HasNoCards);
答案 0 :(得分:2)
public Player GetNextPlayer()
{
int currentPlayerIndex = Players.FindIndex(o => o.IsThisPlayersTurn);
int next = _direction.Equals(Direction.Forwards) ? 1 : -1;
int nextPlayerIndex = currentPlayerIndex;
do
{
nextPlayerIndex = (nextPlayerIndex + next + Players.Count) % Players.Count;
}while(Players[nextPlayerIndex].HasNoCards && nextPlayerIndex != currentPlayerIndex);
return Players[nextPlayerIndex];
}
答案 1 :(得分:2)
LINQ的技巧是仔细设计您的起始序列,使其按逻辑顺序包含所有可能的输出值。在这种情况下,您希望起始序列是所有其他玩家,依次是当前玩家之后的玩家。一旦你表达了这一点,就可以处理像向后方向这样的情况,或者没有牌照的玩家。
private Player GetNextPlayer() {
if (!Players.Any()) throw new InvalidOperationException("No players.");
if (Players.Count(p => p.IsThisPlayersTurn) != 1) {
throw new InvalidOperationException(
"It must be one--and only one--player's turn.");
}
var current = Players.Single(p => p.IsThisPlayersTurn);
var subsequent = Players.Concat(Players)
.SkipWhile(p => p != current)
.Skip(1) // skip current player
.TakeWhile(p => p != current);
if (_direction == Direction.Backwards) {
subsequent = subsequent.Reverse();
}
return subsequent
.FirstOrDefault(p => p.PlayerState != PlayerState.HasNoCards);
}
答案 2 :(得分:0)
已经提出以下内容,但它会对任何更优雅的解决方案感兴趣
private Player GetNextPlayer()
{
var players = Players.AsEnumerable();
if (Direction.Equals(Direction.Backwards))
{
players = players.Reverse();
}
bool selectNextPlayer = false;
foreach (Player player in players)
{
if (selectNextPlayer && !player.PlayerState.Equals(PlayerState.HasNoCards))
{
return player;
}
if (player.IsThisPlayersTurn)
{
selectNextPlayer = true;
}
}
return players.First(o => !o.PlayerState.Equals(PlayerState.HasNoCards));
}