सी#
लगभग पूरी तरह से यादृच्छिक और कच्चे विधानसभा समाधान। जहाँ तक C # और बहुत ज्यादा किसी अन्य प्लेटफॉर्म पर जाता है, यह यथासंभव निम्न स्तर है। सौभाग्य से, C # आपको IL में रनटाइम के दौरान तरीकों को परिभाषित करने की अनुमति देता है (IL मध्यवर्ती भाषा है, .NET का बाइट-कोड, असेंबली के समान)। इस कोड की एकमात्र सीमा यह है कि मैंने मनमाने ढंग से वितरण के साथ कुछ ऑपकोड (सैकड़ों में से) चुने जो सही समाधान के लिए आवश्यक होगा। यदि हम सभी ऑपकोड की अनुमति देते हैं, तो एक कार्यशील कार्यक्रम की संभावना किसी के लिए भी पतली नहीं है, इसलिए यह आवश्यक है (जैसा कि आप कल्पना कर सकते हैं, कई ऐसे तरीके हैं जो यादृच्छिक असेंबली निर्देश क्रैश कर सकते हैं, लेकिन सौभाग्य से, वे पूरे कार्यक्रम को नीचे नहीं लाते हैं कुल मिलाकर)। संभव opcodes की सीमा के अलावा, यह पूरी तरह से यादृच्छिक टुकड़ा करने की क्रिया और किसी भी तरह के संकेत के बिना IL opcodes dicing है।
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;
using System.Reflection.Emit;
using System.Diagnostics;
using System.Threading;
namespace codegolf
{
class Program
{
// decompile this into IL to find out the opcodes needed for the perfect algo
static int digitsumbest(int i)
{
var ret = 0;
while (i > 0)
{
ret += i % 10;
i /= 10;
}
return ret;
}
delegate int digitsumdelegate(int num);
static Thread bgthread;
// actually runs the generated code for one index
// it is invoked in a background thread, which we save so that it can be aborted in case of an infinite loop
static int run(digitsumdelegate del, int num)
{
bgthread = Thread.CurrentThread;
try
{
return del(num);
}
catch (ThreadAbortException)
{
bgthread = null;
throw;
}
}
// evaluates a generated code for some inputs and calculates an error level
// also supports a full run with logging
static long evaluate(digitsumdelegate del, TextWriter sw)
{
var error = 0L;
List<int> numbers;
if (sw == null) // quick evaluation
numbers = Enumerable.Range(1, 30).Concat(Enumerable.Range(1, 70).Select(x => 5000 + x * 31)).ToList();
else // full run
numbers = Enumerable.Range(1, 9999).ToList();
foreach (var num in numbers)
{
try
{
Func<digitsumdelegate, int, int> f = run;
bgthread = null;
var iar = f.BeginInvoke(del, num, null, null);
if (!iar.AsyncWaitHandle.WaitOne(10))
{
bgthread.Abort();
while (bgthread != null) ;
throw new Exception("timeout");
}
var result = f.EndInvoke(iar);
if (sw != null)
sw.WriteLine("{0};{1};{2};", num, digitsumbest(num), result);
var diff = result == 0 ? 15 : (result - digitsumbest(num));
if (diff > 50 || diff < -50)
diff = 50;
error += diff * diff;
}
catch (InvalidProgramException)
{
// invalid IL code, happens a lot, so let's make a shortcut
if (sw != null)
sw.WriteLine("invalid program");
return numbers.Count * (50 * 50) + 1;
}
catch (Exception ex)
{
if (sw != null)
sw.WriteLine("{0};{1};;{2}", num, digitsumbest(num), ex.Message);
error += 50 * 50;
}
}
return error;
}
// generates code from the given byte array
static digitsumdelegate emit(byte[] ops)
{
var dm = new DynamicMethod("w", typeof(int), new[] { typeof(int) });
var ilg = dm.GetILGenerator();
var loc = ilg.DeclareLocal(typeof(int));
// to support jumping anywhere, we will assign a label to every single opcode
var labels = Enumerable.Range(0, ops.Length).Select(x => ilg.DefineLabel()).ToArray();
for (var i = 0; i < ops.Length; i++)
{
ilg.MarkLabel(labels[i]);
// 3 types of jumps with 23 distribution each, 11 types of other opcodes with 17 distribution each = all 256 possibilities
// the opcodes were chosen based on the hand-coded working solution
var c = ops[i];
if (c < 23)
ilg.Emit(OpCodes.Br_S, labels[(i + 1 + c) % labels.Length]);
else if (c < 46)
ilg.Emit(OpCodes.Bgt_S, labels[(i + 1 + c - 23) % labels.Length]);
else if (c < 69)
ilg.Emit(OpCodes.Bge_S, labels[(i + 1 + c - 46) % labels.Length]);
else if (c < 86)
ilg.Emit(OpCodes.Ldc_I4, c - 70); // stack: +1
else if (c < 103)
ilg.Emit(OpCodes.Dup); // stack: +1
else if (c < 120)
ilg.Emit(OpCodes.Ldarg_0); // stack: +1
else if (c < 137)
ilg.Emit(OpCodes.Starg_S, 0); // stack: -1
else if (c < 154)
ilg.Emit(OpCodes.Ldloc, loc); // stack: +1
else if (c < 171)
ilg.Emit(OpCodes.Stloc, loc); // stack: -1
else if (c < 188)
ilg.Emit(OpCodes.Mul); // stack: -1
else if (c < 205)
ilg.Emit(OpCodes.Div); // stack: -1
else if (c < 222)
ilg.Emit(OpCodes.Rem); // stack: -1
else if (c < 239)
ilg.Emit(OpCodes.Add); // stack: -1
else
ilg.Emit(OpCodes.Sub); // stack: -1
}
ilg.Emit(OpCodes.Ret);
return (digitsumdelegate)dm.CreateDelegate(typeof(digitsumdelegate));
}
static void Main(string[] args)
{
System.Diagnostics.Process.GetCurrentProcess().PriorityClass = ProcessPriorityClass.Idle;
var rnd = new Random();
// the first list is just 10 small random ones
var best = new List<byte[]>();
for (var i = 0; i < 10; i++)
{
var initial = new byte[5];
for (var j = 0; j < initial.Length; j++)
initial[j] = (byte)rnd.Next(256);
best.Add(initial);
}
// load the best result from the previous run, if it exists
if (File.Exists("best.txt"))
best[0] = File.ReadAllLines("best.txt").Select(x => byte.Parse(x)).ToArray();
var stop = false;
// handle nice stopping with ctrl-c
Console.CancelKeyPress += (s, e) =>
{
stop = true;
e.Cancel = true;
};
while (!stop)
{
var candidates = new List<byte[]>();
// leave the 10 best arrays, plus generate 9 consecutive mutations for each of them = 100 candidates
for (var i = 0; i < 10; i++)
{
var s = best[i];
candidates.Add(s);
for (var j = 0; j < 9; j++)
{
// the optimal solution is about 20 opcodes, we keep the program length between 15 and 40
switch (rnd.Next(s.Length >= 40 ? 2 : 0, s.Length <= 15 ? 3 : 5))
{
case 0: // insert
case 1:
var c = new byte[s.Length + 1];
var idx = rnd.Next(0, s.Length);
Array.Copy(s, 0, c, 0, idx);
c[idx] = (byte)rnd.Next(256);
Array.Copy(s, idx, c, idx + 1, s.Length - idx);
candidates.Add(c);
s = c;
break;
case 2: // change
c = (byte[])s.Clone();
idx = rnd.Next(0, s.Length);
c[idx] = (byte)rnd.Next(256);
candidates.Add(c);
s = c;
break;
case 3: // remove
case 4: // remove
c = new byte[s.Length - 1];
idx = rnd.Next(0, s.Length);
Array.Copy(s, 0, c, 0, idx);
Array.Copy(s, idx + 1, c, idx, s.Length - idx - 1);
candidates.Add(c);
s = c;
break;
}
}
}
// score the candidates and select the best 10
var scores = Enumerable.Range(0, 100).ToDictionary(i => i, i => evaluate(emit(candidates[i]), null));
var bestidxes = scores.OrderBy(x => x.Value).Take(10).Select(x => x.Key).ToList();
Console.WriteLine("best score so far: {0}", scores[bestidxes[0]]);
best = bestidxes.Select(i => candidates[i]).ToList();
}
// output the code of the best solution
using (var sw = new StreamWriter("best.txt"))
{
foreach (var b in best[0])
sw.WriteLine(b);
}
// create a CSV file with the best solution
using (var sw = new StreamWriter("best.csv"))
{
sw.WriteLine("index;actual;generated;error");
evaluate(emit(best[0]), sw);
}
}
}
}
क्षमा करें, मेरे पास अब तक कोई परिणाम नहीं है क्योंकि 1..99 (1..9999 के बजाय) के परीक्षण के साथ भी बहुत धीमा है और मैं बहुत थक गया हूं। कल आपको वापस मिल जाएगा।
संपादित करें: मैंने इस कार्यक्रम को पूरा किया और इसे बहुत ट्विस्ट किया। अब, यदि आप CTRL-C दबाते हैं, तो यह वर्तमान रन को खत्म कर देगा और परिणाम को फाइलों में आउटपुट करेगा। वर्तमान में, इसका एकमात्र व्यवहार्य समाधान है जो ऐसे प्रोग्राम हैं जो हमेशा एक स्थिर संख्या लौटाते हैं। मैं यह सोचना शुरू कर रहा हूं कि अधिक उन्नत कार्य कार्यक्रम की संभावनाएं खगोलीय रूप से छोटी हैं। वैसे भी मैं इसे कुछ समय के लिए चालू रखूंगा।
संपादित करें: मैं एल्गोरिथ्म को घुमाता रहता हूं, यह मेरे जैसे गीक के लिए एक सही खिलौना है। मैंने एक बार एक उत्पन्न कार्यक्रम देखा, जो वास्तव में कुछ यादृच्छिक गणित करता था और हमेशा एक निरंतर संख्या नहीं लौटाता था। इसे कुछ मिलियन सीपीयू पर एक बार चलाने के लिए बहुत बढ़िया होगा :)। इसे चलाते रहेंगे।
संपादित करें: यहाँ कुछ पूरी तरह से यादृच्छिक गणित का परिणाम है। यह चारों ओर उछलता है और बाकी सूचकांकों के लिए 17 पर रहता है। यह जल्द ही कभी भी सचेत नहीं होगा।
संपादित करें: यह अधिक जटिल हो रहा है। बेशक, जैसा कि आप उम्मीद करेंगे, यह उचित अंकगणित एल्गोरिथम जैसा कुछ भी नहीं दिखता है, लेकिन यह कठिन प्रयास कर रहा है। देखो, एक कंप्यूटर विधानसभा कार्यक्रम उत्पन्न!
no libraries
अनुमति का कोई मतलब नहीं है?