Click here to Skip to main content
15,891,136 members
Articles / Mobile Apps / Windows Mobile

Reversi for Windows Mobile

Rate me:
Please Sign up or sign in to vote.
4.86/5 (4 votes)
12 May 2009CPOL3 min read 27K   531   17  
The game Reversi for Windows Mobile using the Compact Framework.
using System;
using System.Linq;
using System.Collections.Generic;
using System.Text;
using System.Drawing;
using System.Drawing.Imaging;
using System.Windows.Forms;
using System.Media;
using System.IO;

namespace GameExample.Reversi
{
    /// <summary>
    /// Handles game video, input, and sounds.
    /// </summary>
    public class GameRender : IDisposable
    {
        /// <summary>
        /// The height of the status bar
        /// </summary>
        private const int _statusMessageHeight = 14;
        /// <summary>
        /// The size of the score circle.
        /// </summary>
        private const float _circleSize = .85f;
        /// <summary>
        /// Instance of the active game.
        /// </summary>
        private Game _game;
        /// <summary>
        /// The control to paint the game board
        /// </summary>
        private Control _renderArea;
        /// <summary>
        /// Control that has status info
        /// </summary>
        private Control _statusArea;
        /// <summary>
        /// Backbuffer.
        /// </summary>
        private Image _backBuffer;
        /// <summary>
        /// Graphics object for the backbuffer.
        /// </summary>
        private Graphics _gameGraphics;
        /// <summary>
        /// The position size.
        /// </summary>
        private Size _positionSize;
        /// <summary>
        /// The sound player.
        /// </summary>
        private SoundPlayer _soundPlayer = new SoundPlayer();
        /// <summary>
        /// The game options.
        /// </summary>
        private GameOptions _options;
        /// <summary>
        /// Player one
        /// </summary>
        private IPlayer _playerOne;
        /// <summary>
        /// Player two.
        /// </summary>
        private IPlayer _playerTwo;
        /// <summary>
        /// The game timer.
        /// </summary>
        private Timer _timer;
        /// <summary>
        /// The game manager.
        /// </summary>
        private GameManager _gameManager;
        /// <summary>
        /// The message to display in the status bar.
        /// </summary>
        private string _message;
        /// <summary>
        /// The duration to display the message if no moves are made.
        /// </summary>
        private static readonly TimeSpan _defaultMessage = TimeSpan.FromSeconds(2);
        private static readonly TimeSpan _skipWaitTime = TimeSpan.FromSeconds(1.5);
        private TimeSpan _messageWait = TimeSpan.FromSeconds(2);
        private DateTime _messageStart;

        private Image _statusBackBuffer;
        /// <summary>
        /// Graphics object for the backbuffer.
        /// </summary>
        private Graphics _statusGraphics;

        /// <summary>
        /// Initializes a new instance of the <see cref="GameRender"/> class.
        /// </summary>
        /// <param name="game">The game.</param>
        /// <param name="renderControl">The render control.</param>
        public GameRender(GameManager manager, GameOptions options, Game game, Control renderControl, Control statusControl)
        {
            // Verify params
            if (manager == null)
            {
                throw new ArgumentNullException("manager");
            }
            if (options == null)
            {
                throw new ArgumentNullException("options");
            }
            if (game == null)
            {
                throw new ArgumentNullException("game");
            }
            if (renderControl == null)
            {
                throw new ArgumentNullException("renderControl");
            }
            if (statusControl == null)
            {
                throw new ArgumentNullException("statusControl");
            }
            _gameManager = manager;
            _game = game;
            _options = options;
            _renderArea = renderControl;
            _statusArea = statusControl;



            // Create the game timer.
            _timer = new Timer();
            _timer.Site = _renderArea.Site;
            _timer.Tick += new EventHandler(Timer_Tick);
            _timer.Interval = 200;
            _timer.Enabled = true;

            ResetScreen();

            // Create the players.
            _playerOne = _options.PlayerOne == PlayerType.Computer ? (IPlayer)new ComputerPlayer() : (IPlayer)new HumanPlayer();
            _playerTwo = _options.PlayerTwo == PlayerType.Computer ? (IPlayer)new ComputerPlayer() : (IPlayer)new HumanPlayer();
            
            // Play the start sound.
            PlaySound(GameStyles.StartSound);

            // Set the first turn.
            CurrentPlayer.SetTurn(_game.CurrentPlayer, _game);
        }
        public void ResetScreen()
        {            
            // The size of each position/cell
            _positionSize = new Size(
                _renderArea.Width / _game.Board.BoardWidth,
                _renderArea.Height / _game.Board.BoardHeight
                );
            // setup the controls
            SetupRenderArea();
            SetupStatusArea();

            _renderArea.Invalidate();
            _statusArea.Invalidate();
            _renderArea.Update();
            _statusArea.Update();
        }

        /// <summary>
        /// Shows a hint.
        /// </summary>
        public void ShowHint()
        {
            
        }
        public void Dispose()
        {
            if (_timer != null)
            {
                _timer.Dispose();
            }
        }

        /// <summary>
        /// Handles the Tick event of the Timer control.
        /// </summary>
        /// <param name="sender">The source of the event.</param>
        /// <param name="e">The <see cref="System.EventArgs"/> instance containing the event data.</param>
        private void Timer_Tick(object sender, EventArgs e)
        {
            if (!_game.GameOver)
            {
                IPlayer currentPlayer = this.CurrentPlayer;
                if (currentPlayer.HasMove)
                {
                    if (Move(currentPlayer.Move))
                    {
                        currentPlayer.Clear();
                        CurrentPlayer.SetTurn(_game.CurrentPlayer, _game);

                    }
                    else
                    {
                        currentPlayer.Clear();
                    }
                }
                else if (_game.CurrentPlayerMoves.Count == 0)
                {
                    
                    // Skip the current player.
                    _game.Skip();
                    currentPlayer.Clear();

                    // If the current player is a computer player than wait longer.
                    ComputerPlayer computer = CurrentPlayer as ComputerPlayer;
                    if (computer != null)
                    {
                        computer.SetTurn(_game.CurrentPlayer, _game, _skipWaitTime);
                    }
                    else
                    {
                        CurrentPlayer.SetTurn(_game.CurrentPlayer, _game);
                    }
                    PlaySound(GameStyles.SkipSound);
                    SetMessage(string.Format("{0} skipped", _game.CurrentPlayer == Player.PlayerOne ?
                        Player.PlayerTwo : Player.PlayerOne));
                }
            }
            else
            {
                // Game over.  Print the winner.
                Player player = _game.Leader;
                if ( player == Player.NotSet )
                {
                    SetMessage("Gameover.  Tie");
                }
                else
                {
                    SetMessage(string.Format("Gameover.  {0} wins !", player));
                }
            }
            
            // Clear the message.
            if (DateTime.Now > (_messageStart + _messageWait))
            {
                SetMessage(null, TimeSpan.MaxValue);
            }
        }
        
        /// <summary>
        /// Event handler that quits the game.
        /// </summary>
        /// <param name="sender">The source of the event.</param>
        /// <param name="e">The <see cref="System.EventArgs"/> instance containing the event data.</param>
        private void QuitGame_Click(object sender, EventArgs e)
        {
            _gameManager.Quit();
        }

        /// <summary>
        /// Event handler that shows game hint.
        /// </summary>
        /// <param name="sender">The source of the event.</param>
        /// <param name="e">The <see cref="System.EventArgs"/> instance containing the event data.</param>
        private void ShowHint_Click(object sender, EventArgs e)
        {
            ShowHint();
        }


        /// <summary>
        /// Handles the Paint event of the hostControl control.
        /// </summary>
        /// <param name="sender">The source of the event.</param>
        /// <param name="e">The <see cref="System.Windows.Forms.PaintEventArgs"/> instance containing the event data.</param>
        private void hostControl_Paint(object sender, PaintEventArgs e)
        {

            // Render the screen 
            RenderScreen(_gameGraphics);
           
            // Flip the backbuffer.
            e.Graphics.DrawImage(_backBuffer, 0, 0);
        }
        private void statusArea_Paint(object sender, PaintEventArgs e)
        {
            RenderStatusArea(_statusGraphics);

            e.Graphics.DrawImage(_statusBackBuffer, 0, 0);
        }
        /// <summary>
        /// Handles the Paint event of the statusArea control.
        /// </summary>
        /// <param name="sender">The source of the event.</param>
        /// <param name="e">The <see cref="System.Windows.Forms.PaintEventArgs"/> instance containing the event data.</param>

        /// <summary>
        /// Handles the Click event of the hostControl control.
        /// </summary>
        /// <param name="sender">The source of the event.</param>
        /// <param name="e">The <see cref="System.EventArgs"/> instance containing the event data.</param>
        private void RenderControl_Click(object sender, EventArgs e)
        {
            // Ignore the move if not our return.
            HumanPlayer player = CurrentPlayer as HumanPlayer;
            if (player == null)
            {
                return;
            }
            // Translate the move
            Point translatedPoint = TranslatePoint(_renderArea.PointToClient(Control.MousePosition));
            // Try to move.
            player.SetPosition(translatedPoint);
        }

        /// <summary>
        /// Setups the render area.
        /// </summary>
        private void SetupRenderArea()
        {
            // Clear host control and subscribe to events.
            _renderArea.Controls.Clear();
            _renderArea.Click -= new EventHandler(RenderControl_Click);
            _renderArea.Paint -= new PaintEventHandler(hostControl_Paint);

            _renderArea.Click += new EventHandler(RenderControl_Click);
            _renderArea.Paint += new PaintEventHandler(hostControl_Paint);

            // Create the backbuffer and graphics.
            _backBuffer = new Bitmap(_renderArea.Width, _renderArea.Height, 
                System.Drawing.Imaging.PixelFormat.Format24bppRgb);
            _gameGraphics = Graphics.FromImage(_backBuffer);
        }

        /// <summary>
        /// Setups the status area.
        /// </summary>
        private void SetupStatusArea()
        {
            const int buttonWidth = 40;

            _statusArea.Controls.Clear();

            GameButton exitGame = new GameButton();
            exitGame.ButtonText = "  Quit";
            exitGame.Click += new EventHandler(QuitGame_Click);
            exitGame.Location = new Point(_statusArea.Width - (buttonWidth+5), 1);
            exitGame.Size = new Size(buttonWidth, (_statusArea.Height - _statusMessageHeight) - 1);
            exitGame.VerticalAlignment = VerticalAlignment.Center;
            exitGame.HorizontalAlignment = HorizontalAlignment.Left;
            exitGame.BorderStyle = BorderStyle.Fixed3D;
            exitGame.BackColor = Color.White;
            _statusArea.Controls.Add(exitGame);

            //GameButton showHint = new GameButton();
            //showHint.ButtonText = "  Hint";
            //showHint.Click += new EventHandler(ShowHint_Click);
            //showHint.Location = new Point(exitGame.Left - buttonWidth, 0);
            //showHint.Size = new Size(_statusArea.Width, _statusArea.Height - _statusMessageHeight);
            //showHint.VerticalAlignment = VerticalAlignment.Center;
            //showHint.HorizontalAlignment = HorizontalAlignment.Left;
            //showHint.BorderStyle = BorderStyle.Fixed3D;
            //_statusArea.Controls.Add(showHint);


            // Create the backbuffer and graphics.
            _statusBackBuffer = new Bitmap(_statusArea.Width, _statusArea.Height,
                System.Drawing.Imaging.PixelFormat.Format24bppRgb);
            _statusGraphics = Graphics.FromImage(_statusBackBuffer);

            _statusArea.Paint += new PaintEventHandler(statusArea_Paint);
            
        }



        /// <summary>
        /// Renders the screen.
        /// </summary>
        private void RenderScreen(Graphics graphics)
        {
            const float circleReduce = .2F;
            // Get the positions and board width,height
            Position[] positions = _game.Board.Data;
            int boardWidth = _game.Board.BoardWidth, boardHeight = _game.Board.BoardHeight;
            Rectangle positionRectangle;
            int x = 0, y = 0;

            // Draw the background.
            TransparentControl.PaintBackground(graphics, _renderArea);

            Player player;
            for (int i = 0; i < positions.Length; i++)
            {
                // Get the position rectangle.
                positionRectangle = new Rectangle(
                        x, y,
                        (int)(_positionSize.Width),
                        (int)(_positionSize.Height));

                // Draw the grid.
                graphics.DrawRectangle(new Pen(Color.Black, 2),
                    positionRectangle);

                // Get the player.
                player = positions[i].Player;
                Rectangle playerPosition = positionRectangle;

                // Render any circles for any positions that are occupied.
                if (player != Player.NotSet)
                {
                    playerPosition.Inflate(-(int)(positionRectangle.Width * circleReduce), -(int)(positionRectangle.Height * circleReduce));
                    graphics.FillEllipse(
                        new SolidBrush(player == Player.PlayerOne ? Color.Black : Color.White),
                        playerPosition
                        );
                }

                // Move to next position.
                if (i != 0 && ((i + 1) % boardWidth) == 0)
                {
                    x = 0;
                    y += (int)_positionSize.Height;
                }
                else
                {
                    x += (int)_positionSize.Width;
                }
            }
        }

        /// <summary>
        /// Renders the status area.
        /// </summary>
        /// <param name="sender">The sender.</param>
        /// <param name="e">The <see cref="System.Windows.Forms.PaintEventArgs"/> instance containing the event data.</param>
        private void RenderStatusArea(Graphics graphics)
        {
            TransparentControl.PaintBackground(graphics,_statusArea);
            if (!string.IsNullOrEmpty(_message))
            {
                graphics.DrawString(_message, GameStyles.MessageFont, new SolidBrush(Color.Black), 0, _statusArea.Height - _statusMessageHeight);
            }
            const int scoreWidth = 20;
            int statusHeight = _statusArea.Height - _statusMessageHeight;
            int circleSize = (int)(statusHeight * _circleSize);

            Rectangle area = new Rectangle(0, 0, 30, _statusArea.Height - _statusMessageHeight);
            area.Inflate(circleSize - statusHeight, circleSize - statusHeight);

            string value = "Score : ";
            area.Width = (int)(graphics.MeasureString("Score : ", GameStyles.MessageFont).Width);
            graphics.DrawString(value,
                GameStyles.ScoreHeaderFont,
                new SolidBrush(Color.Black),
                area
                );


            // Draw the black player circle.
            area.X += area.Width;
            area.Width = circleSize;
            graphics.FillEllipse(new SolidBrush(Color.Black),
                area
                );

            // Draw the black player score.
            area.X += area.Width;
            area.Width = scoreWidth;
            graphics.DrawString(_game.PlayerOnePositions.Count.ToString(),
                GameStyles.MessageFont, new SolidBrush(Color.Black),
                area,
                new StringFormat() { Alignment = StringAlignment.Center, LineAlignment = StringAlignment.Center }
                );

            // Draw the white player circle
            area.X += area.Width;
            area.Width = circleSize;
            graphics.FillEllipse(new SolidBrush(Color.White),
                area
            );

            // Draw the white player score
            area.X += area.Width;
            area.Width = scoreWidth;
            graphics.DrawString(_game.PlayerTwoPositions.Count.ToString(),
                GameStyles.MessageFont, new SolidBrush(Color.Black),
                area,
                new StringFormat() { Alignment = StringAlignment.Center, LineAlignment = StringAlignment.Center }
                );

        }


        /// <summary>
        /// Sets the message displayed at the bottom of the screen.
        /// </summary>
        /// <param name="message">The message.</param>
        private void SetMessage(string message)
        {
            SetMessage(message, _defaultMessage);
        }
        /// <summary>
        /// Sets the message displayed at the bottom of the screen.
        /// </summary>
        /// <param name="message">The message.</param>
        /// <param name="waitTime">The wait time.</param>
        private void SetMessage(string message, TimeSpan waitTime)
        {
            _messageStart = DateTime.Now;
            _message = message;
            _statusArea.Invalidate();
            _statusArea.Update();
        }

        /// <summary>
        /// Moves to the specified point.
        /// </summary>
        /// <param name="point">The point.</param>
        /// <returns></returns>
        private bool Move(Point point)
        {
            Player player = _game.CurrentPlayer;
            if (_game.Move(point, player))
            {
                _renderArea.Invalidate();
                _renderArea.Update();
                
                SetMessage(string.Format("{0} move ({1},{2})", player, point.X, point.Y));

                PlaySound(GameStyles.MoveSound);
                return true;
            }
            PlaySound(GameStyles.InvalidMoveSound);
            return false; 
        }
        
        /// <summary>
        /// Translates a point from pixels to game board coordinates.
        /// </summary>
        /// <param name="point">The point.</param>
        /// <returns></returns>
        private Point TranslatePoint(Point point)
        {
            int x = (int)((point.X) / _positionSize.Width),
                y = (int)((point.Y) / _positionSize.Height);
            return new Point(x, y);
            
        }

        /// <summary>
        /// Plays a sound.
        /// </summary>
        /// <param name="stream">The stream.</param>
        private void PlaySound(Stream stream)
        {
            if (!_options.SoundsEnabled)
            {
                return;
            }
            _soundPlayer.Stop();
            stream.Seek(0, SeekOrigin.Begin);
            _soundPlayer.Stream = stream;
            _soundPlayer.Play();
            
        }

        /// <summary>
        /// Gets the current player.
        /// </summary>
        /// <value>The current player.</value>
        internal IPlayer CurrentPlayer
        {
            get
            {
                return _game.CurrentPlayer == Player.PlayerOne ?
                    _playerOne : _playerTwo;
                   
            }
        }



    }
}

By viewing downloads associated with this article you agree to the Terms of Service and the article's licence.

If a file you wish to view isn't highlighted, and is a text file (not binary), please let us know and we'll add colourisation support for it.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
United States United States
This member has not yet provided a Biography. Assume it's interesting and varied, and probably something to do with programming.

Comments and Discussions