Skip to content

Instantly share code, notes, and snippets.

@oerpli
Last active August 29, 2015 14:01
Show Gist options
  • Save oerpli/99651ff88f3354e37a54 to your computer and use it in GitHub Desktop.
Save oerpli/99651ff88f3354e37a54 to your computer and use it in GitHub Desktop.
using System;
using System.Collections.Generic;
using System.Linq;
namespace flood {
class MainClass {
public static void Main(string[] args) {
while(true) {
Console.Clear();
Console.WriteLine("Welcome to Flood Fill™!");
Console.WriteLine("Press S to start, O to change options, or Q to quit.");
switch(Console.ReadKey(true).KeyChar) {
case 'S': //Start
case 's': Game();
continue;
case 'O': //Options
case 'o': Settings();
continue;
case 'Q'://Quit
case 'q':
return;
}
}
}
private static void Game() {
Console.Clear();
Grid grid = new Grid(); ;
grid.PrintOut();
while(!grid.Solved()) {
char c = Console.ReadKey(true).KeyChar;
if(c == 'H' || c == 'h') {
grid.Solve(false);
grid.PrintOut();
break;
}
if(!char.IsDigit(c))
continue;
int k = int.Parse(c.ToString());
if(k > Grid.MAX || k == 0)
continue;
grid.Fill(k - 1);
Console.Clear();
grid.PrintOut();
}
Console.WriteLine("You win! \nPress any key continue.");
Console.ReadKey(true);
}
private static void Settings() {
Grid.HEIGHT = PromptNumber("Enter grid height(must be an odd number)", Grid.HEIGHT);
Grid.WIDTH = PromptNumber("Enter grid width(must be an odd number)", Grid.WIDTH);
Grid.MAX = Math.Min(PromptNumber("Enter maximum value (max 9)", Grid.MAX), 9);
if(Grid.HEIGHT % 2 == 0) Grid.HEIGHT++;
if(Grid.WIDTH % 2 == 0) Grid.WIDTH++;
}
public static int PromptNumber(string msg, int def = -1) {
if(def == -1) {
Console.Write(msg + ": ");
int of = 0;
string ss = Console.ReadLine();
if(!int.TryParse(ss, out of))
return PromptNumber(msg, def);
return of;
}
Console.Write(msg + "[" + def + "]: ");
int o = 0;
string s = Console.ReadLine();
if(s.Trim() == string.Empty)
return def;
if(!int.TryParse(s, out o))
return PromptNumber(msg, def);
return o;
}
}
class Grid {
public static int WIDTH = 19;
public static int HEIGHT = 19;
public static int MAX = 6;
int[,] arr = new int[WIDTH, HEIGHT];
ConsoleColor[] COLORS = new ConsoleColor[]{
ConsoleColor.DarkRed,
ConsoleColor.DarkGreen,
ConsoleColor.DarkYellow,
ConsoleColor.DarkCyan,
ConsoleColor.DarkBlue,
ConsoleColor.DarkGray,
ConsoleColor.Blue,
ConsoleColor.Red,
ConsoleColor.Green,
};
public Grid() {
Random rnd = new Random();
for(int x = 0; x < WIDTH; x++) {
for(int y = 0; y < HEIGHT; y++) {
arr[x, y] = rnd.Next(Grid.MAX);
}
}
}
public string Solve(bool returnSolvingSequence) {
if(returnSolvingSequence) {
string ret = "";
while(!this.Solved()) {
int k = this.GetBestColor();
ret += k.ToString();
this.Fill(k);
System.Threading.Thread.Sleep(150);
this.PrintOut();
}
return ret;
} else {
while(!this.Solved()) {
this.Fill(GetBestColor());
System.Threading.Thread.Sleep(150);
this.PrintOut();
}
return "";
}
}
public bool Solved() {
int reference = arr[0, 0];//if not everything has this color it's not solved yet.
for(int x = 0; x < WIDTH; x++) {
for(int y = 0; y < HEIGHT; y++) {
if(arr[x, y] != reference)
return false;
}
}
return true;
}
public void Fill(int color) {
int originalcolor = arr[WIDTH / 2, HEIGHT / 2];
bool[,] visited = new bool[WIDTH, HEIGHT];
var nodes = new Stack<KeyValuePair<int, int>>();
nodes.Push(new KeyValuePair<int, int>(WIDTH / 2, HEIGHT / 2));
while(nodes.Count > 0) {
var active = nodes.Pop();
int x = active.Key;
int y = active.Value;
visited[x, y] = true;
if(arr[x, y] != originalcolor) {
continue;
}
arr[x, y] = color;
if(x + 1 < WIDTH && !visited[x + 1, y])
nodes.Push(new KeyValuePair<int, int>(x + 1, y));
if(x - 1 >= 0 && !visited[x - 1, y])
nodes.Push(new KeyValuePair<int, int>(x - 1, y));
if(y - 1 >= 0 && !visited[x, y - 1])
nodes.Push(new KeyValuePair<int, int>(x, y - 1));
if(y + 1 < HEIGHT && !visited[x, y + 1])
nodes.Push(new KeyValuePair<int, int>(x, y + 1));
}
}
public List<KeyValuePair<int, int>> GetNeighbors(int x, int y) {
var ret = new List<KeyValuePair<int, int>>();
ret.Add(new KeyValuePair<int, int>(x, y));
ret.Add(new KeyValuePair<int, int>(x + 1, y));
ret.Add(new KeyValuePair<int, int>(x - 1, y));
ret.Add(new KeyValuePair<int, int>(x, y + 1));
ret.Add(new KeyValuePair<int, int>(x, y - 1));
return ret;
}
public int GetBestColor() {
//basically the same algorithm as the landfill but it doesn't fill but stores
//which neighbouring color is the most common. Only a heuristic - not really the best option.
int[] colors = new int[Grid.MAX];
int originalcolor = arr[WIDTH / 2, HEIGHT / 2];
bool[,] visited = new bool[WIDTH, HEIGHT];
var nodes = new Stack<KeyValuePair<int, int>>();
nodes.Push(new KeyValuePair<int, int>(WIDTH / 2, HEIGHT / 2));
while(nodes.Count > 0) {
var active = nodes.Pop();
int x = active.Key;
int y = active.Value;
visited[x, y] = true;
if(arr[x, y] != originalcolor) {
colors[arr[x, y]]++;//this line differs!
continue;
}
if(x + 1 < WIDTH && !visited[x + 1, y])
nodes.Push(new KeyValuePair<int, int>(x + 1, y));
if(x - 1 >= 0 && !visited[x - 1, y])
nodes.Push(new KeyValuePair<int, int>(x - 1, y));
if(y - 1 >= 0 && !visited[x, y - 1])
nodes.Push(new KeyValuePair<int, int>(x, y - 1));
if(y + 1 < HEIGHT && !visited[x, y + 1])
nodes.Push(new KeyValuePair<int, int>(x, y + 1));
}
return colors.ToList().IndexOf(colors.Max());
}
public void PrintOut() {
Console.Clear();
for(int x = 0; x < WIDTH; x++) {
for(int y = 0; y < HEIGHT; y++) {
Console.BackgroundColor = COLORS[arr[y, x]];
Console.Write(arr[y, x] + 1);
}
Console.WriteLine();
}
Console.BackgroundColor = ConsoleColor.Black;
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment