void Main()
{
// Test1(12345, true);
// Test2(1024*8+1);
// Test3(12345, new Func<int, int>[]{ x => 2*x, x => 2*x + 4, x => 2*x + 5, x => (int)Math.Round(1.98*x), x => (int)Math.Round(2.02*x) }, false);
}
// проверяем для всех n от 1 до nmax включительно
private void Test1(int nmax, bool optimize = true, bool print = false)
{
var train = new CycleTrain(nmax, optimize);
decimal maxratio = 0, avgratio = 0;
for(int n = 1; n <= nmax; n++)
{
var res = train.CountLength(n);
if(res != n) throw new ApplicationException(string.Format("n = {0}, res = {1}, count = {2}", n, res, train.Count));
var ratio = (decimal)train.Count/n;
avgratio += ratio;
if(ratio > maxratio)
{
if(print) Console.WriteLine("n = {0}, res = {1}, count = {2}, ratio = {3:0.00}", n, res, train.Count, ratio);
maxratio = ratio;
}
}
avgratio /= nmax;
Console.WriteLine("maxratio = {0:0.00000}, avgratio = {1:0.00000}", maxratio, avgratio);
}
// проверяем cnt раз для заданного n
private void Test2(int n, int cnt = 10000)
{
var train = new CycleTrain(n);
decimal maxratio = 0, minratio = 8*n, avgratio = 0;
for(int i = 1; i <= cnt; i++)
{
var res = train.CountLength(n);
if(res != n) throw new ApplicationException(string.Format("n = {0}, res = {1}, count = {2}", n, res, train.Count));
var ratio = (decimal)train.Count/n;
avgratio += ratio;
if(ratio > maxratio) maxratio = ratio;
if(ratio < minratio) minratio = ratio;
}
avgratio /= cnt;
Console.WriteLine("minratio = {0:0.00000}, maxratio = {1:0.00000}, avgratio = {2:0.00000}", minratio, maxratio, avgratio);
}
// проверяем с различными прогрессиями для длины шага
private void Test3(int nmax, IEnumerable<Func<int, int>> funcs, bool print = false)
{
var train = new CycleTrain(nmax, false);
foreach(var func in funcs)
{
decimal maxratio = 0, avgratio = 0;
for(int n = 1; n <= nmax; n++)
{
var res = train.CountLength(n, func);
if(res != n) throw new ApplicationException(string.Format("n = {0}, res = {1}, count = {2}", n, res, train.Count));
var ratio = (decimal)train.Count/n;
avgratio += ratio;
if(ratio > maxratio)
{
if(print) Console.WriteLine("n = {0}, res = {1}, count = {2}, ratio = {3:0.00}", n, res, train.Count, ratio);
maxratio = ratio;
}
}
avgratio /= nmax;
Console.WriteLine("maxratio = {0:0.00000}, avgratio = {1:0.00000}", maxratio, avgratio);
}
}
public class CycleTrain
{
private const int defaultCapacity = 10000;
private readonly Random rnd = new Random();
private bool[] tt; // train lights
private int tn; // train length
private int ti; // current position
private bool optimize;
public int Count { get; private set; }
public CycleTrain(int capacity = defaultCapacity, bool opt = true)
{
tt = new bool[capacity];
optimize = opt;
}
public int CountLength(int n)
{
return CountLength(n, NextStepLength);
}
public int CountLength(int n, Func<int, int> nextLen)
{
Init(n);
bool state = true, left = false;
for(int m = 1, mlast = 0;; state = !state, left = !left, mlast = m, m = nextLen(m))
{
var res = Step(mlast, ref m, state, left);
if(res > 0) return res;
}
}
private static int NextStepLength(int m) { return 2*m; }
private int Step(int mlast, ref int mcur, bool state, bool left)
{
for(int i = 1; i <= mlast; i++)
{
tt[ti] = state;
Move(left);
if(tt[ti] == state) return i;
}
for(int i = mlast+1; i <= mcur; i++)
{
tt[ti] = state;
Move(left);
if(optimize && tt[ti] != state) mcur = i + mlast;
}
return 0;
}
private void Init(int size)
{
if(tt.Length < size) tt = new bool[tt.Length*2];
tn = size;
ti = 0;
Count = 0;
for(int i = 0; i < tn; i++) tt[i] = rnd.Next(2) == 1;
}
private void Left()
{
if(ti == 0) ti = tn;
ti--;
Count++;
}
private void Right()
{
ti++;
if(ti == tn) ti = 0;
Count++;
}
private void Move(bool left)
{
if(left) Left(); else Right();
}
}