列表与LT;>获取满足条件的下一个或上一个元素

时间:2010-10-16 13:16:35

标签: c# linq list

我正在写一个纸牌游戏,并且一直在使用以下方法让下一个玩家转过身来

游戏的方向可以是前进或后退,它也需要尊重这一点

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);

3 个答案:

答案 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));
        }