Skip to content

Instantly share code, notes, and snippets.

@Measter
Last active August 29, 2015 14:14
Show Gist options
  • Select an option

  • Save Measter/90a0f0bb77749a058b9b to your computer and use it in GitHub Desktop.

Select an option

Save Measter/90a0f0bb77749a058b9b to your computer and use it in GitHub Desktop.
Prime Visualiser
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