Click here to Skip to main content
15,891,607 members
Articles / Programming Languages / C# 4.0

Lock Puzzle: A Perplexing Puzzle

Rate me:
Please Sign up or sign in to vote.
4.68/5 (26 votes)
22 Jun 2010CPOL3 min read 34K   840   31  
A brain melting puzzle in which you must turn several interconnected keys to unlock the solution
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Drawing;
using System.Data;
using System.Linq;
using System.Text;
using System.Windows.Forms;

using System.Drawing.Drawing2D;

namespace LockProblemCS
{

    /// <summary>
    /// Coded by Christopher Denmark in 2010
    /// </summary>
    public partial class Key : UserControl
    {
        #region Internals and Proprties
        
        // internals
        int Degrees = 0;
        int degreeOffset = 58; // I don't know why.  58 just worked through tiral & error.  I'd love an explaination
        private bool m_isLocked = false;
        private bool m_isTurning = false;

        public bool IsLocked
        {
            get{return m_isLocked; }
            set { m_isLocked = value;}
        }
        public bool IsTurning
        {
            get{return m_isTurning;}
            set{m_isTurning = value;}
        }
        #endregion

        #region Constructor
        public Key()
        {       
            InitializeComponent();
        }
        #endregion

        #region Methods

        /// <summary>
        /// Draws the key and defines the center point and outer circular path on which the edges of the key are to follow.  
        /// </summary>
        /// <param name="g">g as Graphics object.</param>
        public void DrawKey(Graphics g)
        {
            // ake sure all graphics are smooth, not blocky.
            g.SmoothingMode = SmoothingMode.AntiAlias;
            g.CompositingQuality = CompositingQuality.HighQuality;
            g.InterpolationMode = InterpolationMode.HighQualityBicubic;

            // Declare Brush and pen objects
            Brush brshREC = new SolidBrush(Color.White);
            Pen p = new Pen(brshREC, 10);
            
            // Declare surface and origin of circle
            int x_center;
            int y_center;
            float x_path;
            float y_path;
            float x_path2;
            float y_path2;
            DefineSurfacePath(out x_center, out y_center, out x_path, out y_path, out x_path2, out y_path2);
           
            // draw previously defined points
            g.DrawLine(p, x_center, y_center, x_path, y_path);
            g.DrawLine(p, x_center, y_center, x_path2, y_path2);

        }

        /// <summary>
        /// Defines the surface path of the circle.  This is the origin and outer most lines of the key durring rotation.  one center and two lines stem outward.
        /// </summary>
        /// <param name="x_center">The x_center.</param>
        /// <param name="y_center">The y_center.</param>
        /// <param name="x_path">The x_path.</param>
        /// <param name="y_path">The y_path.</param>
        /// <param name="x_path2">The x_path2.</param>
        /// <param name="y_path2">The y_path2.</param>
        private void DefineSurfacePath(out int x_center, out int y_center, out float x_path, out float y_path, out float x_path2, out float y_path2)
        {
            int Radius = 30;
            x_center = this.Width / 2;
            y_center = this.Height / 2;

            // define outer rotation path for first line
            x_path = (GetCos(360 + Degrees + x_center + degreeOffset) * Radius) + x_center;
            y_path = (GetSin(360 + Degrees + y_center + degreeOffset) * Radius) + y_center;

            // define outer rotation path for second line
            x_path2 = (GetCos(360 + Degrees + 180 + x_center + degreeOffset) * Radius) + x_center;
            y_path2 = (GetSin(360 + Degrees + 180 + y_center + degreeOffset) * Radius) + y_center;
        }

        /// <summary>
        /// Turns the key and toggles the relevant variables.
        /// </summary>
        public void TurnKey()
        {
            // toggle status of 'turning flag'
            m_isTurning = !m_isTurning;

            // remains locked until turn is complete
            m_isLocked = true;

            // toggle timer           
            this.timer1.Enabled = !this.timer1.Enabled;     
        }

        /// <summary>
        /// Defines the limits of rotation.
        /// </summary>
        private void DefinePositions()
        {
            // Rotate and stop at the 3, 6, 9, and 12 o'clock positions.
            if (Degrees == 360)
            {
                Degrees = 0;                    // reset
                this.timer1.Enabled = false;    // stop timer
                m_isTurning = !m_isTurning;     // toggle turning flag
                m_isLocked = false;             // toggle locked flag
            }
            else if (Degrees == 90)
            {
                this.timer1.Enabled = false;
                m_isTurning = !m_isTurning;
                m_isLocked = true;
                Degrees++;
            }
            else if (Degrees == 180)
            {
                this.timer1.Enabled = false;
                m_isTurning = !m_isTurning;
                m_isLocked = false;
                Degrees++;
            }
            else if (Degrees == 270)
            {
                this.timer1.Enabled = false;
                m_isTurning = !m_isTurning;
                m_isLocked = true;
                Degrees++;
            }
            else  // keep moving and let us know that you are moving.
            {
                Degrees++;
                m_isTurning = true;
            }

            // Update the form and controls.
            this.Refresh();
        }

        /// <summary>
        /// Gets the sin.
        /// </summary>
        /// <param name="degAngle">The angle of the Degree.</param>
        /// <returns></returns>
        private static float GetSin(float degAngle)
        {
            return (float)Math.Sin(Math.PI * degAngle / 180f);
        }

        /// <summary>
        /// Gets the cos.
        /// </summary>
        /// <param name="degAngle">The angle of the Degree.</param>
        /// <returns></returns>
        private static float GetCos(float degAngle)
        {
            return (float)Math.Cos(Math.PI * degAngle / 180f);
        }
        #endregion

        #region Override(s)
        protected override void OnPaint(PaintEventArgs e)
        {
            // give .net the first try
            base.OnPaint(e);

            // then take over
            Graphics g = e.Graphics;
            DrawKey(g);
        }

        #endregion
        
        #region Events
        private void timer1_Tick(object sender, EventArgs e)
        {
            // Defines postion of the key
            DefinePositions();
        }


        /// <summary>
        /// Handles the Click event of the Key control.  Makes sure the key is not already turning before you turn it.  
        /// </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 Lock_Click(object sender, EventArgs e)
        {
            // make sure your not in the process turning already
            if(m_isTurning == false)
                TurnKey();
        }
        #endregion

    }
}

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
Software Developer (Senior)
United States United States
Technical professional with 11 years of experience in designing, developing and implementing sophisticated software solutions.

Comments and Discussions