From d86dd7c8edf1e365c1ffcdd54a02ba19660484b1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C8=98tefan-Iulian=20Alecu?= <165364995+pascalecu@users.noreply.github.com> Date: Mon, 28 Jul 2025 23:59:02 +0300 Subject: [PATCH 1/2] Add Convex Hull in C# --- archive/c/c-sharp/ConvexHull.cs | 129 ++++++++++++++++++++++++++++++++ 1 file changed, 129 insertions(+) create mode 100644 archive/c/c-sharp/ConvexHull.cs diff --git a/archive/c/c-sharp/ConvexHull.cs b/archive/c/c-sharp/ConvexHull.cs new file mode 100644 index 000000000..5e95f9100 --- /dev/null +++ b/archive/c/c-sharp/ConvexHull.cs @@ -0,0 +1,129 @@ +using System; +using System.Collections.Generic; +using System.Linq; + +public record Point(int X, int Y) : IComparable +{ + public int CompareTo(Point? other) + => other is null ? 1 : X != other.X ? X.CompareTo(other.X) : Y.CompareTo(other.Y); + + public override string ToString() => $"({X}, {Y})"; + + public static bool operator <(Point left, Point right) => left.CompareTo(right) < 0; + public static bool operator >(Point left, Point right) => left.CompareTo(right) > 0; +} + +public static class ConvexHull +{ + private static void ShowUsage() + { + Console.Error.WriteLine("Usage: please provide at least 3 x and y coordinates as separate lists (e.g. \"100, 440, 210\")"); + } + + private static List ParseIntegerList(string input) + { + if (string.IsNullOrWhiteSpace(input)) + ShowUsage(); + + var list = input + .Split(',', StringSplitOptions.RemoveEmptyEntries | StringSplitOptions.TrimEntries) + .Select(part => int.TryParse(part, out var val) + ? val + : throw new ArgumentException($"Invalid integer value: '{part}'")) + .ToList(); + + if (list.Count < 3) + ShowUsage(); + + return list; + } + + + /// + /// Calculates the cross product of vectors OA and OB. + /// Positive result means counter-clockwise turn. + /// Negative result means clockwise turn. + /// Zero means points are colinear. + /// + private static long Cross(Point o, Point a, Point b) + { + var (ox, oy) = (o.X, o.Y); + var (ax, ay) = (a.X, a.Y); + var (bx, by) = (b.X, b.Y); + return (long)(ax - ox) * (by - oy) - (long)(ay - oy) * (bx - ox); + } + + + /// + /// Constructs the convex hull using the Jarvis March algorithm. + /// + private static List BuildHull(List points) + { + int n = points.Count; + if (n < 3) return [.. points]; + + int startIndex = 0; + for (int i = 1; i < n; i++) + { + if (points[i] < points[startIndex]) + startIndex = i; + } + + var hull = new List(); + int currentIndex = startIndex; + + do + { + hull.Add(points[currentIndex]); + int candidateIndex = (currentIndex + 1) % n; + + for (int i = 0; i < n; i++) + { + if (Cross(points[currentIndex], points[i], points[candidateIndex]) > 0) + candidateIndex = i; + } + + currentIndex = candidateIndex; + + } while (currentIndex != startIndex); + + return hull; + } + + public static int Main(string[] args) + { + if (args.Length != 2) + { + ShowUsage(); + return 1; + } + + try + { + var xCoords = ParseIntegerList(args[0]); + var yCoords = ParseIntegerList(args[1]); + if (xCoords.Count != yCoords.Count) + { + ShowUsage(); + return 1; + } + + if (xCoords.Count < 3) + { + ShowUsage(); + return 1; + } + + var points = xCoords.Zip(yCoords, (x, y) => new Point(x, y)).ToList(); + + BuildHull(points).ForEach(Console.WriteLine); + + return 0; + } + catch + { + ShowUsage(); + return 1; + } + } +} From 2f199d28343e03229361a7b0da5eface097af532 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C8=98tefan-Iulian=20Alecu?= <165364995+pascalecu@users.noreply.github.com> Date: Tue, 29 Jul 2025 00:04:36 +0300 Subject: [PATCH 2/2] Add stronger early exits for ParseIntegerList --- archive/c/c-sharp/ConvexHull.cs | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/archive/c/c-sharp/ConvexHull.cs b/archive/c/c-sharp/ConvexHull.cs index 5e95f9100..1eeebc51f 100644 --- a/archive/c/c-sharp/ConvexHull.cs +++ b/archive/c/c-sharp/ConvexHull.cs @@ -23,7 +23,10 @@ private static void ShowUsage() private static List ParseIntegerList(string input) { if (string.IsNullOrWhiteSpace(input)) + { ShowUsage(); + Environment.Exit(1); + } var list = input .Split(',', StringSplitOptions.RemoveEmptyEntries | StringSplitOptions.TrimEntries) @@ -33,7 +36,10 @@ private static List ParseIntegerList(string input) .ToList(); if (list.Count < 3) + { ShowUsage(); + Environment.Exit(1); + } return list; } @@ -94,7 +100,7 @@ public static int Main(string[] args) { if (args.Length != 2) { - ShowUsage(); + ShowUsage(); return 1; } @@ -104,13 +110,13 @@ public static int Main(string[] args) var yCoords = ParseIntegerList(args[1]); if (xCoords.Count != yCoords.Count) { - ShowUsage(); + ShowUsage(); return 1; } if (xCoords.Count < 3) { - ShowUsage(); + ShowUsage(); return 1; }