Search code examples
wpfsilverlightwcfarchitecturepoker

Poker lobby architecture


I have created an online poker system using WCF net.tcp and WPF for the front end. It works great, but I feel there are some things I can improve upon when I convert the front end to Silverlight.

One of the questions I have for fellow architects is how should the game lobby be refreshed? A poker game lobby is continually updated with statistics like number of players, hands per hour, and flop percentage.

Since there could be hundreds of games in progress at any given time, I am not so sure that returning the entire list of games every 5 seconds (polling) is optimum. I was thinking of using a delta query since many games will not have status updates (e.g.: no players on the table).

I was thinking of using an update time so every time a client (which may be hundreds or even thousands!) poll, only the records updated within say 5, 10, or more seconds are returned.

The game lobby client will of course be responsible for reconciling the new data, but I think this could help relieve some of the burden on the game servers.

Any ideas?


Solution

  • <Window x:Class="TestListUpdate.Window1"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="Window1" Height="300" Width="300">
        <Grid>
            <ListView Name="listView1">
                <ListView.View>
                    <GridView>
                        <GridViewColumn Width="140" Header="Name" DisplayMemberBinding="{Binding Value.Name}" />
                        <GridViewColumn Width="140" Header="Creator" DisplayMemberBinding="{Binding Value.Creator}" />
                        <GridViewColumn Width="140" Header="Publisher" DisplayMemberBinding="{Binding Value.Publisher}" />
                    </GridView>
                </ListView.View>
            </ListView>
        </Grid>
    </Window>
    
    
    namespace TestListUpdate
    {
        /// <summary>
        /// Interaction logic for Window1.xaml
        /// </summary>
        public partial class Window1 : Window
        {
            Dictionary<int, GameData> _gameData = null;
    
            // This is a test, real data will be retrieved via a web service
            List<GameData> _updates = null;
    
            public Window1()
            {
                InitializeComponent();
    
                // This is the original data bound to the ListView control
                this._gameData = new Dictionary<int, GameData>();
                this._gameData.Add(1, new GameData { Id = 1, Creator = "ABC", Name = "One", Publisher = "123" });
                this._gameData.Add(2, new GameData { Id = 2, Creator = "DEF", Name = "Two", Publisher = "456" });
                this._gameData.Add(3, new GameData { Id = 3, Creator = "GHI", Name = "Three", Publisher = "789" });
                this._gameData.Add(4, new GameData { Id = 4, Creator = "JKL", Name = "Four", Publisher = "abc" });
                this._gameData.Add(5, new GameData { Id = 5, Creator = "MNO", Name = "Five", Publisher = "def" });
    
                // This is test data, some Ids are duplicates of the original data above
                // other items represent new items
                this._updates = new List<GameData>();
                this._updates.Add(new GameData { Id = 2, Creator = "DDD", Name = "Two", Publisher = "123" });
                this._updates.Add(new GameData { Id = 3, Creator = "TTT", Name = "Three", Publisher = "456" });
                this._updates.Add(new GameData { Id = 5, Creator = "FFF", Name = "Five", Publisher = "789" });
                this._updates.Add(new GameData { Id = 6, Creator = "XXX", Name = "Six", Publisher = "abc" });
                this._updates.Add(new GameData { Id = 7, Creator = "VVV", Name = "Seven", Publisher = "def" });
    
                System.Windows.Threading.DispatcherTimer timer = new System.Windows.Threading.DispatcherTimer();
                timer.Interval = new TimeSpan(0, 0, 5);
                timer.Tick += new EventHandler(timer_Tick);
                timer.Start();
            }
    
            void timer_Tick(object sender, EventArgs e)
            {
                // Get a list of Ids from the new data
                var ids = (from l in this._updates
                           select l.Id);
    
                // Get a list of items that have matching Ids,
                // this data will be updated
                var updates = (from g in this._gameData
                               where ids.Contains(g.Value.Id)
                               select g);
    
                // Update the current items
                for (int i = 0; i < updates.Count(); ++i)
                {
                    KeyValuePair<int, GameData> kvp = updates.ElementAt(i);
                    kvp.Value.Publisher = DateTime.Now.ToLongTimeString();
                }
    
                // This represents new items to add
                this._gameData = this._gameData.Concat(
                        (from n in this._updates
                         where !this._gameData.ContainsKey(n.Id)
                         select n).ToDictionary(a => a.Id, a => a)
                     ).ToDictionary(q => q.Key, q => q.Value);
    
                // This is a simple trick to rebind the ListView control
                this.listView1.ItemsSource = null;
                this.listView1.ItemsSource = GameList;
            }
    
            // Databinding property
            public Dictionary<int, GameData> GameList
            {
                get { return this._gameData; }
            }
        }
    
        // Data class
        public class GameData
        {
            public int Id { get; set; }
            public string Name { get; set; }
            public string Creator { get; set; }
            public string Publisher { get; set; }
        }
    }