private void pictureBox1_Paint(object sender, PaintEventArgs e) { var g = e.Graphics; g.Clear(Color.White); // Find scale float scale = Math.Min(pictureBox1.Width, pictureBox1.Height); g.ScaleTransform(scale, scale); // Draw grid Queue <Tuple <PointF, PointF> > gridLines = new Queue <Tuple <PointF, PointF> >(); // Split = 1/9 then 2/9 ... for (int i = 0; i < 8; i++) { float split = (i + 1.0f) / 9.0f; // Add vertical then horizontal line gridLines.Enqueue(new Tuple <PointF, PointF>( new PointF(split, 0.0f), new PointF(split, 1.0f) )); gridLines.Enqueue(new Tuple <PointF, PointF>( new PointF(0.0f, split), new PointF(1.0f, split) )); } // Draw each 3rd grid pair thicker for (int i = 0; i < 8; i++) { var pen = (i + 1) % 3 != 0 ? new Pen(Brushes.Black, 0.01f) : new Pen(Brushes.Black, 0.02f); var points = gridLines.Dequeue(); g.DrawLine(pen, points.Item1, points.Item2); points = gridLines.Dequeue(); g.DrawLine(pen, points.Item1, points.Item2); } // Draw each digit Font f = new Font(SystemFonts.DefaultFont.FontFamily, 1.0f / 9, FontStyle.Regular, GraphicsUnit.Pixel); Font f_bold = new Font(f, FontStyle.Bold); StringFormat sf = new StringFormat() { Alignment = StringAlignment.Center, LineAlignment = StringAlignment.Center }; for (byte row = 0; row < 9; row++) { for (byte col = 0; col < 9; col++) { byte index = (byte)(row * 9 + col); byte digit = Sudoku[index]; if (digit == NDEF_VALUE) { continue; } Brush brush = Heatmap.TryGetValue(index, out double heat) ? new SolidBrush(Color.FromArgb((int)(heat * 255), 125, 125)) : Brushes.Black; Font font = Heatmap.ContainsKey(index) ? f : f_bold; RectangleF layoutRectangle = new RectangleF(col * 1.0f / 9.0f, row * 1.0f / 9.0f, 1.0f / 9.0f, 1.0f / 9.0f); g.DrawString(digit.ToString(), font, brush, layoutRectangle, sf); } } }