using System; using System.Collections.Generic; using System.Linq; using System.Windows; using System.Windows.Controls; using System.Windows.Input; using System.Windows.Media; using myOSity.API; namespace solitaire { public partial class moSol : UserControl { private Stack _deck = new Stack(); //Represents a deck of cards private Random _r = new Random(); //Randome number generator private bool _mouseCaptured = false; //flags whether something is being dragged or not private Point _offSet; //Offsets _draggableColumn position while dragging it with the mouse private DiscardPile _discardPile; //Represents face-up cards that have been turn over from the _startPile private StartPile _startPile; //Represents face-down cards that are not yet in play private FinishPile[] _finishPiles = new FinishPile[4]; //Contains objects representing where finished cards go private CardColumn[] _cardColumns = new CardColumn[7]; //Contains objects representing each column of cards in the playfield private CardColumn _draggableColumn = new CardColumn(); //Used as a container to drag cards around the playfield private PreferencesDialog _prefDialog = new PreferencesDialog(); private System.Windows.Threading.DispatcherTimer _timer; private bool _firstLoad = true; #region Initialization and UI Methods //Class Constructor public moSol() { InitializeComponent(); this.Loaded += new RoutedEventHandler(Page_Loaded); Canvas.SetZIndex(_draggableColumn, 999); //set the draggable column to the highest z-index } /// /// Fires after this UserControl has completely loaded into the Silverlight rendered display /// /// /// void Page_Loaded(object sender, RoutedEventArgs e) { if (_firstLoad) { _firstLoad = false; #region Reset Elements GameStatus.GameOver = false; GameStatus.Passes = 0; GameStatus.BankRoll = 0; GameStatus.ElapsedSeconds = new TimeSpan(); _timer = new System.Windows.Threading.DispatcherTimer(); _timer.Interval = new TimeSpan(0, 0, 1); _timer.Tick += new EventHandler(_timer_Tick); _discardPile = new DiscardPile(); _startPile = new StartPile(); _startPile.StartCardClicked += new EventHandler(_startPile_StartCardClicked); _startPile.ellipse1.Visibility = Visibility.Visible; _startPile.cvX.Visibility = Visibility.Collapsed; _finishPiles[0] = new FinishPile(); _finishPiles[1] = new FinishPile(); _finishPiles[2] = new FinishPile(); _finishPiles[3] = new FinishPile(); Canvas.SetZIndex(_discardPile, 0); Canvas.SetZIndex(_startPile, 0); Canvas.SetZIndex(_finishPiles[0], 0); Canvas.SetZIndex(_finishPiles[1], 0); Canvas.SetZIndex(_finishPiles[2], 0); Canvas.SetZIndex(_finishPiles[3], 0); //set positions Canvas.SetLeft(_startPile, 20); Canvas.SetTop(_startPile, 30); Canvas.SetLeft(_discardPile, 120); Canvas.SetTop(_discardPile, 30); Canvas.SetLeft(_finishPiles[0], 320); Canvas.SetTop(_finishPiles[0], 30); Canvas.SetLeft(_finishPiles[1], 420); Canvas.SetTop(_finishPiles[1], 30); Canvas.SetLeft(_finishPiles[2], 520); Canvas.SetTop(_finishPiles[2], 30); Canvas.SetLeft(_finishPiles[3], 620); Canvas.SetTop(_finishPiles[3], 30); //CardColumns for (int i = 0; i < 7; i++) { _cardColumns[i] = new CardColumn(); Canvas.SetZIndex(_cardColumns[i], 0); Canvas.SetTop(_cardColumns[i], 175); Canvas.SetLeft(_cardColumns[i], (i * 100) + 20); this.LayoutRoot.Children.Add(_cardColumns[i]); } this.LayoutRoot.Children.Add(_startPile); this.LayoutRoot.Children.Add(_discardPile); this.LayoutRoot.Children.Add(_finishPiles[0]); this.LayoutRoot.Children.Add(_finishPiles[1]); this.LayoutRoot.Children.Add(_finishPiles[2]); this.LayoutRoot.Children.Add(_finishPiles[3]); #endregion DealCards(); InitPrefs(); btnResetBalance.Visibility = tbBalance.Visibility = (GameStatus.Preferences.EnableVegasRules) ? Visibility.Visible : Visibility.Collapsed; tbTimer.Visibility = (GameStatus.Preferences.EnableTimer) ? Visibility.Visible : Visibility.Collapsed; this.LayoutRoot.MouseMove += new MouseEventHandler(LayoutRoot_MouseMove); _startPile.LayoutRoot.MouseLeftButtonDown += new MouseButtonEventHandler(LayoutRoot_MouseLeftButtonDown); } } void _timer_Tick(object sender, EventArgs e) { GameStatus.ElapsedSeconds += TimeSpan.FromSeconds(1); UpdateTimeDisplay(); } /// /// Resets the board and starts a new game /// /// /// private void btnNewGame_Click(object sender, RoutedEventArgs e) { StartNewGame(); } private void StartNewGame() { for (int i = 0; i < 7; i++) { _cardColumns[i].Clear(); } _startPile.ellipse1.Visibility = Visibility.Visible; _startPile.cvX.Visibility = Visibility.Collapsed; GameStatus.GameOver = false; GameStatus.Passes = 0; btnResetBalance.Visibility = tbBalance.Visibility = (GameStatus.Preferences.EnableVegasRules) ? Visibility.Visible : Visibility.Collapsed; tbTimer.Visibility = (GameStatus.Preferences.EnableTimer) ? Visibility.Visible : Visibility.Collapsed; _finishPiles[0].Clear(); _finishPiles[1].Clear(); _finishPiles[2].Clear(); _finishPiles[3].Clear(); _startPile.Clear(); _discardPile.Clear(); if (GameStatus.Preferences.EnableVegasRules) { GameStatus.BankRoll -= 50; UpdateBankRollDisplay(); } if (GameStatus.Preferences.EnableTimer) { GameStatus.ElapsedSeconds = TimeSpan.FromSeconds(0); UpdateTimeDisplay(); _timer.Start(); } DealCards(); } /// /// Initializes default preferences /// TODO: allow user to change/save/load preferences /// private void InitPrefs() { GameStatus.Preferences = new GameSettings(); GameStatus.Preferences.DrawMode = DrawModes.DrawThree; GameStatus.Preferences.EnableScoring = false; GameStatus.Preferences.EnableTimer = false; GameStatus.Preferences.EnableVegasRules = false; } #endregion #region Event Handlers for the Options Dialog private void btnPrefs_Click(object sender, RoutedEventArgs e) { ModalCoverEnabled = true; CenterInLayout(_prefDialog); _prefDialog.btnCancelPrefs.Click += new RoutedEventHandler(btnCancelPrefs_Click); _prefDialog.btnSubmitPrefs.Click += new RoutedEventHandler(btnSubmitPrefs_Click); if (GameStatus.Preferences.DrawMode == DrawModes.DrawOne) _prefDialog.rbDrawOne.IsChecked = true; else _prefDialog.rbDrawThree.IsChecked = true; _prefDialog.cbTimedGame.IsChecked = GameStatus.Preferences.EnableTimer; _prefDialog.cbEnableVegas.IsChecked = GameStatus.Preferences.EnableVegasRules; LayoutRoot.Children.Add(_prefDialog); } void btnSubmitPrefs_Click(object sender, RoutedEventArgs e) { bool _changeFlag = false; DrawModes cdm = GameStatus.Preferences.DrawMode; if ((bool)_prefDialog.rbDrawOne.IsChecked) GameStatus.Preferences.DrawMode = DrawModes.DrawOne; else GameStatus.Preferences.DrawMode = DrawModes.DrawThree; if (cdm != GameStatus.Preferences.DrawMode) _changeFlag = true; if (GameStatus.Preferences.EnableVegasRules != _prefDialog.cbEnableVegas.IsChecked) { GameStatus.Preferences.EnableVegasRules = (bool)_prefDialog.cbEnableVegas.IsChecked; if ((bool)_prefDialog.cbEnableVegas.IsChecked) GameStatus.BankRoll = 0; _changeFlag = true; } if (GameStatus.Preferences.EnableTimer != _prefDialog.cbTimedGame.IsChecked) { GameStatus.Preferences.EnableTimer = (bool)_prefDialog.cbTimedGame.IsChecked; if ((bool)_prefDialog.cbTimedGame.IsChecked) _timer.Start(); else _timer.Stop(); _changeFlag = true; } LayoutRoot.Children.Remove(_prefDialog); ModalCoverEnabled = false; if (_changeFlag) StartNewGame(); } void btnCancelPrefs_Click(object sender, RoutedEventArgs e) { LayoutRoot.Children.Remove(_prefDialog); ModalCoverEnabled = false; } #endregion #region Click, Drag, And Drop Handlers void Card_MouseLeftButtonDown(object sender, MouseButtonEventArgs e) { if (!GameStatus.GameOver) { Card c = (Card)sender; if (((IDraggable)c).DragEnabled) { this.AddCardsToDraggableColumn(c.FromContainer.RetrieveCardAndDescendants(c)); _offSet = new Point(38, 20); Canvas.SetLeft(_draggableColumn, e.GetPosition(LayoutRoot).X - _offSet.X); Canvas.SetTop(_draggableColumn, e.GetPosition(LayoutRoot).Y - _offSet.Y); _mouseCaptured = true; this.LayoutRoot.MouseLeftButtonUp += new MouseButtonEventHandler(Handler_MouseLeftButtonUp); _draggableColumn.MouseLeftButtonUp += new MouseButtonEventHandler(Handler_MouseLeftButtonUp); } e.Handled = true; } } /// /// Determines what action to take after the users has completed a drag operation /// /// /// void Handler_MouseLeftButtonUp(object sender, MouseButtonEventArgs e) { _mouseCaptured = false; //remove the mouseup events from the elements, we don't need them until the next drag try { _draggableColumn.MouseLeftButtonUp -= new MouseButtonEventHandler(Handler_MouseLeftButtonUp); this.LayoutRoot.MouseLeftButtonUp -= new MouseButtonEventHandler(Handler_MouseLeftButtonUp); } catch { } //Check card columns to see if the card landed inside foreach (ICardContainer cc in _cardColumns) { if (cc.IsInside(e.GetPosition(LayoutRoot))) { //if the column reports that the card(s) can validly be placed in this column if (((CardColumn)cc).IsGoodCardCandidate(_draggableColumn.BottomCard)) { PlaceCards(cc); //Put the cards into the column e.Handled = true; return; } } } //If the player is dragging a single card, see if it landed in one of the finish piles if (_draggableColumn.TotalCards == 1) { foreach (ICardContainer cc in _finishPiles) { if (cc.IsInside(e.GetPosition(LayoutRoot))) { //if the finished pile reports that the card can validly be placed there if (((FinishPile)cc).IsGoodCardCandidate(_draggableColumn.BottomCard)) { PlaceCards(cc); //Put the card into the pile e.Handled = true; return; } } } } //If the card(s) where not dropped into a valid location, set the card(s) back to the previous location... Card c = _draggableColumn.BottomCard; PlaceCards(c.FromContainer); e.Handled = true; } /// /// Repositions the draggable column around the playfield as the user drags it /// /// /// void LayoutRoot_MouseMove(object sender, MouseEventArgs e) { if (_mouseCaptured) { Point _mousePos = e.GetPosition(LayoutRoot); Canvas.SetLeft(_draggableColumn, _mousePos.X - _offSet.X); Canvas.SetTop(_draggableColumn, _mousePos.Y - _offSet.Y); } } /// /// When the start pile is empty and the user clicks on it, takes the cards from the discard pile and puts them back into the start pile /// /// /// void LayoutRoot_MouseLeftButtonDown(object sender, MouseButtonEventArgs e) { if (!GameStatus.GameOver && _startPile.TotalCards == 0) { //When Vegas Rules are enabled, control the number of passes allowed back to the start pile // DrawModes.DrawOne = 1 Pass only // DrawModes.DrawThree = 3 Passes only if (GameStatus.Preferences.EnableVegasRules) { if ((GameStatus.Preferences.DrawMode == DrawModes.DrawOne && GameStatus.Passes == 0) || (GameStatus.Preferences.DrawMode == DrawModes.DrawThree && GameStatus.Passes == 2)) { return; } else { GameStatus.Passes++; } } while (_discardPile.TotalCards > 0) { _startPile.AddCard(_discardPile.RetrieveTopCard()); } } } /// /// Takes a card from the start pile and places it face up on the discard pile /// /// /// void _startPile_StartCardClicked(object sender, CardReturnEventArgs e) { if (!GameStatus.GameOver) { if (GameStatus.Preferences.DrawMode == DrawModes.DrawOne) { _discardPile.AddCard(e.CardReturned); e.CardReturned.MouseLeftButtonDown += new MouseButtonEventHandler(Card_MouseLeftButtonDown); e.CardReturned.DragEnabled = true; } else if (GameStatus.Preferences.DrawMode == DrawModes.DrawThree) { _discardPile.AddCard(e.CardReturned); e.CardReturned.MouseLeftButtonDown += new MouseButtonEventHandler(Card_MouseLeftButtonDown); if (_startPile.TotalCards > 0) { Card tc1 = _startPile.RetrieveTopCard(); _discardPile.AddCard(tc1); tc1.MouseLeftButtonDown += new MouseButtonEventHandler(Card_MouseLeftButtonDown); } if (_startPile.TotalCards > 0) { Card tc = _startPile.RetrieveTopCard(); _discardPile.AddCard(tc); tc.MouseLeftButtonDown += new MouseButtonEventHandler(Card_MouseLeftButtonDown); } } //Adjust the look of the start pile background, depending on whether or not the user can make a pass if (_startPile.TotalCards == 0) { if (GameStatus.Preferences.EnableVegasRules && (GameStatus.Preferences.DrawMode == DrawModes.DrawOne && GameStatus.Passes == 0) || (GameStatus.Preferences.DrawMode == DrawModes.DrawThree && GameStatus.Passes == 2)) { _startPile.ellipse1.Visibility = Visibility.Collapsed; _startPile.cvX.Visibility = Visibility.Visible; } else { _startPile.ellipse1.Visibility = Visibility.Visible; _startPile.cvX.Visibility = Visibility.Collapsed; } } } } /// /// Takes an array of cards, and puts them into the draggable column so the user can move them around the playfield /// /// public void AddCardsToDraggableColumn(Card[] c) { foreach (Card cc in c) { _draggableColumn.AddCardNoContainerUpdate(cc); } this.LayoutRoot.Children.Add(_draggableColumn); } /// /// Takes cards from the draggablecolumn and places them into the appropriate ICardContainer /// /// public void PlaceCards(ICardContainer c) { this.LayoutRoot.Children.Remove(_draggableColumn); while (_draggableColumn.BottomCard != null) { Card ncc = _draggableColumn.RetrieveCard(_draggableColumn.BottomCard); ncc.MouseLeftButtonDown += new MouseButtonEventHandler(Card_MouseLeftButtonDown); c.AddCard(ncc); } AfterTurn(); } #endregion #region Helper Methods /// /// Updates the game with any changes that need to be made after the player has taken some action. /// private void AfterTurn() { foreach (CardColumn cc in _cardColumns) { cc.FlipBottomCardUp(); } UpdateBankRollDisplay(); DetermineGameOver(); } private void DetermineGameOver() { int x = (from cc in _finishPiles where cc.PeekTopCard() != null && cc.PeekTopCard().CardValue == CardValue.King select cc).Count(); if (x == 4) { GameStatus.GameOver = true; MessageBox.Show("Congratulations! You win!", "Game Over", MessageBoxButton.OK); } } /// /// Returns a randomized deck of cards /// /// private Stack GetShuffledDeck() { Stack newDeck = new Stack(); List _orderedDeck = GetOrderedDeck(); while (_orderedDeck.Count > 0) { int c = _r.Next(0, _orderedDeck.Count); newDeck.Push(_orderedDeck[c].Clone()); _orderedDeck.RemoveAt(c); } return newDeck; } /// /// Initializes an ordered deck of cards /// /// private static List GetOrderedDeck() { List _orderedDeck = new List(52); _orderedDeck.Add(new Card(CardValue.Ace, CardSuit.Hearts)); _orderedDeck.Add(new Card(CardValue.Two, CardSuit.Hearts)); _orderedDeck.Add(new Card(CardValue.Three, CardSuit.Hearts)); _orderedDeck.Add(new Card(CardValue.Four, CardSuit.Hearts)); _orderedDeck.Add(new Card(CardValue.Five, CardSuit.Hearts)); _orderedDeck.Add(new Card(CardValue.Six, CardSuit.Hearts)); _orderedDeck.Add(new Card(CardValue.Seven, CardSuit.Hearts)); _orderedDeck.Add(new Card(CardValue.Eight, CardSuit.Hearts)); _orderedDeck.Add(new Card(CardValue.Nine, CardSuit.Hearts)); _orderedDeck.Add(new Card(CardValue.Ten, CardSuit.Hearts)); _orderedDeck.Add(new Card(CardValue.Jack, CardSuit.Hearts)); _orderedDeck.Add(new Card(CardValue.Queen, CardSuit.Hearts)); _orderedDeck.Add(new Card(CardValue.King, CardSuit.Hearts)); _orderedDeck.Add(new Card(CardValue.Ace, CardSuit.Diamonds)); _orderedDeck.Add(new Card(CardValue.Two, CardSuit.Diamonds)); _orderedDeck.Add(new Card(CardValue.Three, CardSuit.Diamonds)); _orderedDeck.Add(new Card(CardValue.Four, CardSuit.Diamonds)); _orderedDeck.Add(new Card(CardValue.Five, CardSuit.Diamonds)); _orderedDeck.Add(new Card(CardValue.Six, CardSuit.Diamonds)); _orderedDeck.Add(new Card(CardValue.Seven, CardSuit.Diamonds)); _orderedDeck.Add(new Card(CardValue.Eight, CardSuit.Diamonds)); _orderedDeck.Add(new Card(CardValue.Nine, CardSuit.Diamonds)); _orderedDeck.Add(new Card(CardValue.Ten, CardSuit.Diamonds)); _orderedDeck.Add(new Card(CardValue.Jack, CardSuit.Diamonds)); _orderedDeck.Add(new Card(CardValue.Queen, CardSuit.Diamonds)); _orderedDeck.Add(new Card(CardValue.King, CardSuit.Diamonds)); _orderedDeck.Add(new Card(CardValue.Ace, CardSuit.Spades)); _orderedDeck.Add(new Card(CardValue.Two, CardSuit.Spades)); _orderedDeck.Add(new Card(CardValue.Three, CardSuit.Spades)); _orderedDeck.Add(new Card(CardValue.Four, CardSuit.Spades)); _orderedDeck.Add(new Card(CardValue.Five, CardSuit.Spades)); _orderedDeck.Add(new Card(CardValue.Six, CardSuit.Spades)); _orderedDeck.Add(new Card(CardValue.Seven, CardSuit.Spades)); _orderedDeck.Add(new Card(CardValue.Eight, CardSuit.Spades)); _orderedDeck.Add(new Card(CardValue.Nine, CardSuit.Spades)); _orderedDeck.Add(new Card(CardValue.Ten, CardSuit.Spades)); _orderedDeck.Add(new Card(CardValue.Jack, CardSuit.Spades)); _orderedDeck.Add(new Card(CardValue.Queen, CardSuit.Spades)); _orderedDeck.Add(new Card(CardValue.King, CardSuit.Spades)); _orderedDeck.Add(new Card(CardValue.Ace, CardSuit.Clubs)); _orderedDeck.Add(new Card(CardValue.Two, CardSuit.Clubs)); _orderedDeck.Add(new Card(CardValue.Three, CardSuit.Clubs)); _orderedDeck.Add(new Card(CardValue.Four, CardSuit.Clubs)); _orderedDeck.Add(new Card(CardValue.Five, CardSuit.Clubs)); _orderedDeck.Add(new Card(CardValue.Six, CardSuit.Clubs)); _orderedDeck.Add(new Card(CardValue.Seven, CardSuit.Clubs)); _orderedDeck.Add(new Card(CardValue.Eight, CardSuit.Clubs)); _orderedDeck.Add(new Card(CardValue.Nine, CardSuit.Clubs)); _orderedDeck.Add(new Card(CardValue.Ten, CardSuit.Clubs)); _orderedDeck.Add(new Card(CardValue.Jack, CardSuit.Clubs)); _orderedDeck.Add(new Card(CardValue.Queen, CardSuit.Clubs)); _orderedDeck.Add(new Card(CardValue.King, CardSuit.Clubs)); return _orderedDeck; } /// /// Distributes the cards around the playfield /// private void DealCards() { _deck = GetShuffledDeck(); //get a new set of shuffled cards //Deal cards to the field for (int i = 0; i < 7; i++) { for (int ii = 0; ii <= i; ii++) { Card c = _deck.Pop(); c.DragEnabled = true; //Register for a mouse click on the card... c.DraggableElement.MouseLeftButtonDown += new MouseButtonEventHandler(Card_MouseLeftButtonDown); c.FaceUp = (ii < i) ? false : true; _cardColumns[i].AddCard(c); } } //then to the Start Pile... while (_deck.Count > 0) { _startPile.AddCard(_deck.Pop()); } } private bool ModalCoverEnabled { get { return cvModalCover.Visibility == Visibility.Visible ? true : false; } set { if (value) { cvModalCover.Width = LayoutRoot.ActualWidth; cvModalCover.Height = LayoutRoot.ActualHeight; cvModalCover.Visibility = Visibility.Visible; } else { cvModalCover.Visibility = Visibility.Collapsed; } } } private void CenterInLayout(UserControl c) { double w = c.Width; double h = c.Height; if (w == double.NaN || h == double.NaN) return; w = w / 2; h = h / 2; Canvas.SetTop(c, LayoutRoot.ActualHeight / 2 - h); Canvas.SetLeft(c, LayoutRoot.ActualWidth / 2 - w); } private void UpdateBankRollDisplay() { Color lime = new Color() { A = 255, R = 0, G = 255, B = 0 }; tbBalance.Text = "$" + GameStatus.BankRoll.ToString(); tbBalance.Foreground = (GameStatus.BankRoll >= 0) ? new SolidColorBrush(lime) : new SolidColorBrush(Colors.Yellow); } private void UpdateTimeDisplay() { tbTimer.Text = GameStatus.ElapsedSeconds.ToString(); } internal void StopTimer() { _timer.Stop(); } #endregion private void btnResetBalance_Click(object sender, RoutedEventArgs e) { MessageBoxResult r = MessageBox.Show("Resetting your bankroll will restart the current game.", "Are you sure?", MessageBoxButton.OKCancel); if (r == MessageBoxResult.OK) { GameStatus.BankRoll = 0; StartNewGame(); } } } internal static class GameStatus { internal static int Passes { get; set; } internal static bool GameOver { get; set; } internal static GameSettings Preferences { get; set; } internal static TimeSpan ElapsedSeconds { get; set; } internal static int BankRoll { get; set; } } }