Advertisement

Thursday, 26 March 2015

Moving on to C# 6: Spirograph

Spirograph

Just for fun I've translated one of Nonki Takahash's Spirograph programs into C#.

Nonki's original was very nice ad this should be pretty much the same, though I'd be very glad of any feedback if I've made any errors in the translation.

I've taken a couple of liberties, for example, I've simplified the way the random numbers are generated and I've used the built-in SB function for getting a random color instead of the one in the original program.

If you've worked through the other tutorials in this series you should be familiar with most of the code below. One thing to point out is the use of global variables. You've seen local variables in the functions tutorial, these are private to the the function in which they are declared. Global variables are declared outside of all functions and are accessible to all functions. You can see them all declared just before the Main function.

You can find further comments on the program at the end of this post, otherwise that's it. Enjoy.

/*
 * Spirograph 26/03/15
 * Based on a Small Basic program by Nonki Takahashi written on 2015-03-02
 * The original program was released under the MIT license, for this version
 * no rights are reserved.
 * 
 * 28/03/15 Removed apparently redundant variable 'show' and various if(show)... constructs
*/

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.SmallBasic.Library;

namespace CS_SB_Lib1
{
    class Program
    {
        static String showColor = "#CCCCCC";
        static Primitive ox, oy;
        static Primitive r1, r2, r3;
        static Primitive e1, e2;
        static Primitive x, y, x2, y2;
        static Primitive a1, a2, _a1, _a2, da;
        static void Main(string[] args)
        {
            GraphicsWindow.Title = "Spirograph";

            //int '/lf? = Text.GetCharacter(10);

            int gw = 598;
            int gh = 428;
            GraphicsWindow.Width = gw;
            GraphicsWindow.Height = gh;

            GraphicsWindow.BrushColor = showColor;
            ox = gw / 2;
            oy = gh / 2;
            int n1 = 19;
            r1 = n1 * 10;

            while (true)
            {
                GraphicsWindow.BrushColor = "Black";
                Primitive shpTxt = Shapes.AddText("");
                Shapes.Move(shpTxt, 10, 10);
                if (true)
                {
                    GraphicsWindow.PenColor = showColor;
                    GraphicsWindow.BrushColor = "#00FFFFFF";
                    e1 = Shapes.AddEllipse(r1 * 2, r1 * 2);
                    Shapes.Move(e1, ox - r1, oy - r1);
                }
                String txt = "";
                int max = Microsoft.SmallBasic.Library.Math.GetRandomNumber(4) + 1;

                // Fill the array with 1 to n1
                Primitive[] num = new Primitive[n1];
                for (int j = 0; j < n1; j++)
                {
                    num[j] = j + 1;
                }
                // Shuffle array
                for (int j = 0; j < n1 - 1; j++)
                {
                    // Swap elements randomly 10 times
                    for (int k = 0; k < 10; k++)
                    {
                        if (Microsoft.SmallBasic.Library.Math.GetRandomNumber(2) > 1)
                        {
                            int temp = num[j];
                            num[j] = num[j + 1];
                            num[j + 1] = num[j];
                        }
                    }
                }


                int n2;
                int n3;
                for (int i = 1; i <= max * 2; i = i + 2)
                {
                    n2 = num[i];
                    n3 = num[i + 1];
                    if (n2 < n3)
                    {
                        int wk;
                        wk = n2;
                        n2 = n3;
                        n3 = wk;
                    }
                    r2 = n2 * 10;
                    r3 = n3 * 10;
                    txt = "";
                    txt = txt + "r1 = " + r1 + ", ";
                    txt = txt + "r2 = " + r2 + ", ";
                    txt = txt + "r3 = " + r3 ;
                    Shapes.SetText(shpTxt, txt);

                    Spirograph();
                }

               
                Shapes.Remove(e1);
                
                Microsoft.SmallBasic.Library.Program.Delay(3000);
                GraphicsWindow.Clear();
            }
        }

        static void Spirograph()
        {
            GraphicsWindow.PenColor = showColor;
            GraphicsWindow.BrushColor = showColor;
            e2 = Shapes.AddEllipse(r2 * 2, r2 * 2);
            Shapes.SetOpacity(e2, 50);

            a1 = 0;
            a2 = 0;
            da = 1;
            PenPosition();

            Shapes.Move(e2, x2 - r2, y2 - r2);
            int xLast = x;
            int yLast = y;
            int xStart = x;
            int yStart = y;
            Increment();
            PenPosition();
            GraphicsWindow.PenColor = GraphicsWindow.GetRandomColor();

            while ((x != xStart) || (y != yStart))
            {

                Microsoft.SmallBasic.Library.Program.Delay(1);
                Shapes.Move(e2, x2 - r2, y2 - r2);
                
                GraphicsWindow.DrawLine(xLast, yLast, x, y);
                xLast = x;
                yLast = y;
                Increment();
                PenPosition();
            }
            Shapes.Move(e2, x2 - r2, y2 - r2);
            GraphicsWindow.DrawLine(xLast, yLast, x, y);
            
            Shapes.Remove(e2);    
        }

        static void Increment()
        {
            a1 = a1 + da;
            a2 = -a1 * r1 / r2;
        }

        static void PenPosition()
        {

            _a1 = Microsoft.SmallBasic.Library.Math.GetRadians(a1);
            x2 = ox + (r1 - r2) * Microsoft.SmallBasic.Library.Math.Sin(_a1);
            y2 = oy - (r1 - r2) * Microsoft.SmallBasic.Library.Math.Cos(_a1);
            _a2 = Microsoft.SmallBasic.Library.Math.GetRadians(a2);
            x = x2 + r3 * Microsoft.SmallBasic.Library.Math.Sin(_a2);
            y = y2 - r3 * Microsoft.SmallBasic.Library.Math.Cos(_a2);
        }


    }
}
        
    

        
    

1. The original method of picking numbers from 1 to 19 from an array, in a random order, was ingenious but a little long-winded. The way it is done here is to randomise the order of the numbers in the array first and then read them out in order.

2. I´ve changed the variable show to be a Boolean (i.e. it takes the values either true or false). Although to be honest I'm not sure why it's there in the first place!
3. The Primitive type come from SB. It´s used to hold things like shapes and is the standard type in SB. Other variables are typed as int.
4. Global variables: these are global in the SB version (of course) and remain so here as they are shared between more than one function. I would not normally write code like this. I prefer to pass parameters into functions and get returned values back. This works the way it is but I may well write a new version in a better C# style in the future.

No comments:

Post a Comment