Created
January 6, 2017 10:44
-
-
Save taross-f/1f5cd61df44868ae27930709a4f4d38f to your computer and use it in GitHub Desktop.
This file contains 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
<Query Kind="Program"> | |
<Reference><RuntimeDirectory>\System.dll</Reference> | |
<Reference><RuntimeDirectory>\System.Net.dll</Reference> | |
<Reference><RuntimeDirectory>\System.Net.Http.dll</Reference> | |
<Reference><RuntimeDirectory>\System.Web.dll</Reference> | |
<NuGetReference>Microsoft.Net.Http</NuGetReference> | |
<NuGetReference>Newtonsoft.Json</NuGetReference> | |
<NuGetReference>Sendgrid</NuGetReference> | |
<Namespace>Newtonsoft.Json</Namespace> | |
<Namespace>Newtonsoft.Json.Bson</Namespace> | |
<Namespace>Newtonsoft.Json.Converters</Namespace> | |
<Namespace>Newtonsoft.Json.Linq</Namespace> | |
<Namespace>Newtonsoft.Json.Schema</Namespace> | |
<Namespace>Newtonsoft.Json.Serialization</Namespace> | |
<Namespace>SendGrid.SmtpApi</Namespace> | |
<Namespace>System.IO</Namespace> | |
<Namespace>System.Net</Namespace> | |
<Namespace>System.Web.Mail</Namespace> | |
</Query> | |
//using System; | |
//using System.Linq; | |
//using System.Collections.Generic; | |
//public static class Extension | |
//{ | |
// public static void ForEach<T>(this IEnumerable<T> e, Action<T, int> action) | |
// { | |
// var i = 0; | |
// foreach (var element in e) action(element, i++); | |
// } | |
// | |
//} | |
public class FifteenPuzzle | |
{ | |
public static void Main() | |
{ | |
var inputs = Console.ReadLine().Split(' ').Select(int.Parse) | |
.Concat(Console.ReadLine().Split(' ').Select(int.Parse)) | |
.Concat(Console.ReadLine().Split(' ').Select(int.Parse)) | |
.Concat(Console.ReadLine().Split(' ').Select(int.Parse)) | |
.Cast<int>() | |
.ToArray(); | |
foreach (var max in Enumerable.Range(1, 45)) | |
{ | |
if (!Board.Move(new Board(inputs), 1, max)) | |
continue; | |
Console.WriteLine(max); | |
break; | |
} | |
} | |
} | |
public class Board | |
{ | |
public Node[] Nodes { get; set; } | |
public HashSet<long> Hash { get; private set; } | |
public Board(IEnumerable<int> inputs) | |
{ | |
Nodes = inputs.Select((x, i) => new Node((i + 1) % 16, x)) | |
.ToArray(); | |
Hash = new HashSet<long>(); | |
} | |
public Board() { } | |
// public Board[] Move(int count, int max) | |
// { | |
// var empty = Nodes.First(x => x.Current == 0); | |
// var children = empty.AdjacentNumbers | |
// .Select(_ => Board.Clone(this)) | |
// .ToArray(); | |
// | |
// empty.AdjacentNumbers | |
// .ForEach((adj, i) => | |
// { | |
// var board = children[i]; | |
// var left = board.Nodes.First(x => x.Current == 0); | |
// var right = board.Nodes.First(x => x.CorrectNumber == adj); | |
// | |
// board.SwapCurrent(left, right); | |
// | |
// if (!hash.Add(board.GetHash())) | |
// children[i] = null; | |
// else if (board.Nodes.Where(x => x.Current != 0).Sum(x => GetManhattanDistance(x.Current, x.CorrectNumber)) > max - count) | |
// children[i] = null; | |
// }); | |
// | |
// return children.Where(x => x != null).ToArray(); | |
// } | |
public static bool Move(Board board, int count, int max) | |
{ | |
if (board.Nodes.All(x => x.IsCorrect())) | |
return true; | |
var empty = board.Nodes.First(x => x.Current == 0); | |
var children = empty.AdjacentNumbers | |
.Select(_ => Board.Clone(board)) | |
.ToArray(); | |
empty.AdjacentNumbers | |
.ForEach((adj, i) => | |
{ | |
var child = children[i]; | |
var left = child.Nodes.First(x => x.Current == 0); | |
var right = child.Nodes.First(x => x.CorrectNumber == adj); | |
child.SwapCurrent(left, right); | |
if (!child.Hash.Add(child.GetHash())) | |
children[i] = null; | |
else | |
{ | |
var distance = child.Nodes.Where(x => x.Current != 0).Sum(x => GetManhattanDistance(x.Current, x.CorrectNumber)); | |
if (distance > max - count) | |
children[i] = null; | |
} | |
}); | |
children = children.Where(x => x != null).ToArray(); | |
// if (children.Any(x => x.Nodes.All(node => node.IsCorrect()))) return true; | |
return children.Any(x => Board.Move(x, count + 1, max)); | |
} | |
public void SwapCurrent(Node left, Node right) | |
{ | |
var temp = left.Current; | |
left.Current = right.Current; | |
right.Current = temp; | |
} | |
private static Board Clone(Board board) | |
{ | |
return new Board | |
{ | |
Nodes = board.Nodes.Select(Node.Clone) | |
.ToArray(), | |
Hash = new HashSet<long>(board.Hash) | |
}; | |
} | |
public override string ToString() | |
{ | |
return Nodes.Select(x => x.Current) | |
.Select(x => x.ToString()) | |
.Aggregate((acc, x) => acc + " " + x); | |
} | |
public long GetHash() | |
{ | |
var code = Nodes.Select(x => x.Current).Aggregate((accum, x) => accum * 10 + x); | |
return code; | |
} | |
private static int GetManhattanDistance(int current, int correct) | |
{ | |
var cu = current - 1; | |
var co = correct == 0 ? 15 : correct - 1; | |
var d = Math.Abs(cu / 4 - co / 4) + Math.Abs(cu % 4 - co % 4); | |
return d; | |
} | |
} | |
public class Node | |
{ | |
private static readonly Dictionary<int, int[]> adjacentNumbersDic = | |
new Dictionary<int, int[]> | |
{ | |
{ 1, new [] { 2, 4 } }, | |
{ 2, new [] { 1, 3, 6 } }, | |
{ 3, new [] { 2, 4, 7 } }, | |
{ 4, new [] { 3, 8 } }, | |
{ 5, new [] { 1, 5, 9 } }, | |
{ 6, new [] { 2, 5, 7, 10 } }, | |
{ 7, new [] { 3, 6, 8, 11 } }, | |
{ 8, new [] { 4, 7, 12 } }, | |
{ 9, new [] { 5, 10, 13 } }, | |
{ 10, new [] { 6, 9, 11, 14 } }, | |
{ 11, new [] { 7, 10, 12, 15 } }, | |
{ 12, new [] { 8, 11, 0 } }, | |
{ 13, new [] { 9, 14 } }, | |
{ 14, new [] { 10, 13, 15 } }, | |
{ 15, new [] { 11, 14, 0 } }, | |
{ 0, new [] { 12, 15 } }, | |
}; | |
public int CorrectNumber { get; private set; } | |
public int Current { get; set; } | |
public int[] AdjacentNumbers { get; set; } | |
public Node(int correct, int current) | |
{ | |
CorrectNumber = correct; | |
Current = current; | |
AdjacentNumbers = adjacentNumbersDic[correct]; | |
} | |
public static Node Clone(Node node) | |
{ | |
return new Node(node.CorrectNumber, node.Current); | |
} | |
public bool IsCorrect() { return CorrectNumber == Current; } | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment