Last active
August 29, 2015 14:14
-
-
Save Measter/90a0f0bb77749a058b9b to your computer and use it in GitHub Desktop.
Prime Visualiser
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| using System; | |
| using System.Collections.Generic; | |
| using System.Drawing; | |
| using System.Linq; | |
| using System.Net.Mime; | |
| namespace ConsoleTestApp | |
| { | |
| public class PrimeVisualiser | |
| { | |
| private const int BORDER_WIDTH = 5; | |
| private const int SQUARE_SIZE = 64; | |
| private const int CLOSE_BOUND = 60; | |
| private const int SUBDIV_GAP = 2; | |
| private readonly SolidBrush m_white = new SolidBrush( Color.White ); | |
| private readonly SolidBrush m_textBackground = new SolidBrush( Color.FromArgb( 128, Color.Black ) ); | |
| private readonly Dictionary<int, SolidBrush> m_usedColors = new Dictionary<int, SolidBrush>(); | |
| private Font m_font; | |
| private int m_seed; | |
| public Bitmap Run( int max, int columns = 10 ) | |
| { | |
| m_usedColors.Clear(); | |
| m_usedColors[0] = new SolidBrush( Color.Black ); | |
| m_usedColors[1] = new SolidBrush( Color.White ); | |
| m_font = new Font( FontFamily.GenericSansSerif, 20 ); | |
| m_seed = DateTime.Now.Millisecond; | |
| int width = ( columns * SQUARE_SIZE ) + ( BORDER_WIDTH * ( columns + 1 ) ); | |
| int rows = max / columns; | |
| int height = ( rows * SQUARE_SIZE ) + ( BORDER_WIDTH * ( rows + 1 ) ); | |
| Bitmap b = new Bitmap( width, height ); | |
| using( Graphics g = Graphics.FromImage( b ) ) | |
| { | |
| g.FillRectangle( m_white, 0, 0, width, height ); | |
| for( int y = 0; y < max; y++ ) | |
| { | |
| for( int x = 0; x < 10 && ( y * columns ) + x < max; x++ ) | |
| { | |
| int val = ( ( y * columns ) + x ) + 1; | |
| DrawSquare( g, val, x, y ); | |
| } | |
| } | |
| } | |
| return b; | |
| } | |
| private void DrawSquare( Graphics g, int value, int col, int row ) | |
| { | |
| int x = ( col * SQUARE_SIZE ) + ( BORDER_WIDTH * col ); | |
| int y = ( row * SQUARE_SIZE ) + ( BORDER_WIDTH * row ); | |
| List<int> factors = GetPrimeFactors( value ).ToList(); | |
| SolidBrush brush; | |
| if( factors.Count == 1 ) // prime number | |
| { | |
| brush = GetNextColor( value ); | |
| m_usedColors.Add( value, brush ); | |
| g.FillRectangle( brush, x + BORDER_WIDTH, y + BORDER_WIDTH, SQUARE_SIZE, SQUARE_SIZE ); | |
| } else if( factors.Count == 0 ) | |
| { | |
| // Is 1 | |
| brush = m_usedColors[1]; | |
| g.FillRectangle( brush, x + BORDER_WIDTH, y + BORDER_WIDTH, SQUARE_SIZE, SQUARE_SIZE ); | |
| } else | |
| { | |
| // Subdivide, and get colours by factors. | |
| int gapCount = factors.Count - 1; | |
| int subdivWidth = ( SQUARE_SIZE - ( gapCount * SUBDIV_GAP ) ) / factors.Count; | |
| for( int i = 0; i < factors.Count; i++ ) | |
| { | |
| int subdivX = ( i * subdivWidth ) + ( i * SUBDIV_GAP ); | |
| g.FillRectangle( m_usedColors[factors[i]], x + subdivX + BORDER_WIDTH, y + BORDER_WIDTH, subdivWidth, SQUARE_SIZE ); | |
| } | |
| } | |
| int textY = SQUARE_SIZE - 25; | |
| g.FillRectangle( m_textBackground, x + BORDER_WIDTH, y + textY - 1 + BORDER_WIDTH, SQUARE_SIZE, SQUARE_SIZE - textY + 1 ); | |
| g.DrawString( value.ToString(), m_font, m_white, x + 3, y + textY ); | |
| } | |
| private SolidBrush GetNextColor( int val ) | |
| { | |
| Random rand = new Random( val + m_seed ); | |
| int r, g, b; | |
| do | |
| { | |
| r = rand.Next( 255 ); | |
| g = rand.Next( 255 ); | |
| b = rand.Next( 255 ); | |
| } while( ColourTooClose( r, g, b ) ); | |
| return new SolidBrush( Color.FromArgb( r, g, b ) ); | |
| } | |
| private bool ColourTooClose( int r, int g, int b ) | |
| { | |
| foreach( var brush in m_usedColors ) | |
| { | |
| Color col = brush.Value.Color; | |
| if( Math.Abs( r - col.R ) < CLOSE_BOUND && | |
| Math.Abs( g - col.G ) < CLOSE_BOUND && | |
| Math.Abs( b - col.B ) < CLOSE_BOUND ) | |
| { | |
| return true; | |
| } | |
| } | |
| return false; | |
| } | |
| private IEnumerable<int> GetPrimeFactors( int n ) | |
| { | |
| // 2 first, save time later. | |
| while( n > 1 ) | |
| { | |
| if( n % 2 != 0 ) | |
| break; | |
| yield return 2; | |
| n >>= 1; | |
| } | |
| int div = 3; | |
| while( n > 1 ) | |
| { | |
| if( n % div != 0 ) | |
| { | |
| div += 2; | |
| continue; | |
| } | |
| yield return div; | |
| n /= div; | |
| } | |
| } | |
| } | |
| } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment