using System;
namespace Factorial
{
class Program
{
static void Main(string[] args)
{
Factorial<intFact> f = new Factorial<intFact>(new intFact(5));
Console.WriteLine(f.Value);
}
}
struct intFact : IFactoriable<intFact>
{
public int n;
public intFact(int num)
{
n = num;
}
public bool isZero()
{
return n == 0;
}
public bool isBelowZero()
{
return n < 0;
}
public intFact Step()
{
return new intFact(n - 1);
}
public intFact Multiply(intFact iF)
{
return new intFact(n * iF.n);
}
public intFact getNeutralElement()
{
return new intFact(1);
}
public override string ToString()
{
return n.ToString();
}
}
[Serializable]
class Factorial<T> where T : IFactoriable<T>
{
T p;
public T Value
{
get;
private set;
}
public T Param
{
get
{
return p;
}
set
{
if (value.isBelowZero()) throw new ArgumentOutOfRangeException("n or Param");
Value = fact(value);
p = value;
}
}
public Factorial(T n)
{
Param = n;
}
T fact(T n)
{
if (n.isZero()) return n.getNeutralElement();
return n.Multiply(fact(n.Step()));
}
}
interface IFactoriable<T>
{
bool isZero();
bool isBelowZero();
T Step();
T getNeutralElement();
T Multiply(T t);
}
}
dXNpbmcgU3lzdGVtOwoKbmFtZXNwYWNlIEZhY3RvcmlhbAp7CiAgICBjbGFzcyBQcm9ncmFtCiAgICB7CiAgICAgICAgc3RhdGljIHZvaWQgTWFpbihzdHJpbmdbXSBhcmdzKQogICAgICAgIHsKICAgICAgICAgICAgRmFjdG9yaWFsPGludEZhY3Q+IGYgPSBuZXcgRmFjdG9yaWFsPGludEZhY3Q+KG5ldyBpbnRGYWN0KDUpKTsKICAgICAgICAgICAgQ29uc29sZS5Xcml0ZUxpbmUoZi5WYWx1ZSk7CiAgICAgICAgfQoKICAgIH0KICAgIAogICAgc3RydWN0IGludEZhY3QgOiBJRmFjdG9yaWFibGU8aW50RmFjdD4KICAgIHsKICAgICAgICBwdWJsaWMgaW50IG47CiAgICAgICAgcHVibGljIGludEZhY3QoaW50IG51bSkKICAgICAgICB7CiAgICAgICAgICAgIG4gPSBudW07CiAgICAgICAgfQogICAgICAgIHB1YmxpYyBib29sIGlzWmVybygpCiAgICAgICAgewogICAgICAgICAgICByZXR1cm4gbiA9PSAwOwogICAgICAgIH0KICAgICAgICBwdWJsaWMgYm9vbCBpc0JlbG93WmVybygpCiAgICAgICAgewogICAgICAgICAgICByZXR1cm4gbiA8IDA7CiAgICAgICAgfQogICAgICAgIHB1YmxpYyBpbnRGYWN0IFN0ZXAoKQogICAgICAgIHsKICAgICAgICAgICAgcmV0dXJuIG5ldyBpbnRGYWN0KG4gLSAxKTsKICAgICAgICB9CiAgICAgICAgcHVibGljIGludEZhY3QgTXVsdGlwbHkoaW50RmFjdCBpRikKICAgICAgICB7CiAgICAgICAgICAgIHJldHVybiBuZXcgaW50RmFjdChuICogaUYubik7CiAgICAgICAgfQogICAgICAgIHB1YmxpYyBpbnRGYWN0IGdldE5ldXRyYWxFbGVtZW50KCkKICAgICAgICB7CiAgICAgICAgICAgIHJldHVybiBuZXcgaW50RmFjdCgxKTsKICAgICAgICB9CiAgICAgICAgcHVibGljIG92ZXJyaWRlIHN0cmluZyBUb1N0cmluZygpCiAgICAgICAgewogICAgICAgICAgICByZXR1cm4gbi5Ub1N0cmluZygpOwogICAgICAgIH0KICAgIH0KCiAgICBbU2VyaWFsaXphYmxlXQogICAgY2xhc3MgRmFjdG9yaWFsPFQ+IHdoZXJlIFQgOiBJRmFjdG9yaWFibGU8VD4KICAgIHsKICAgICAgICBUIHA7CgogICAgICAgIHB1YmxpYyBUIFZhbHVlCiAgICAgICAgewogICAgICAgICAgICBnZXQ7CiAgICAgICAgICAgIHByaXZhdGUgc2V0OwogICAgICAgIH0KICAgICAgICBwdWJsaWMgVCBQYXJhbQogICAgICAgIHsKICAgICAgICAgICAgZ2V0IAogICAgICAgICAgICB7IAogICAgICAgICAgICAgICAgcmV0dXJuIHA7IAogICAgICAgICAgICB9CiAgICAgICAgICAgIHNldCAKICAgICAgICAgICAgewogICAgICAgICAgICAgICAgaWYgKHZhbHVlLmlzQmVsb3daZXJvKCkpIHRocm93IG5ldyBBcmd1bWVudE91dE9mUmFuZ2VFeGNlcHRpb24oIm4gb3IgUGFyYW0iKTsKICAgICAgICAgICAgICAgIFZhbHVlID0gZmFjdCh2YWx1ZSk7IAogICAgICAgICAgICAgICAgcCA9IHZhbHVlOyAKICAgICAgICAgICAgfQogICAgICAgIH0KCiAgICAgICAgcHVibGljIEZhY3RvcmlhbChUIG4pCiAgICAgICAgewogICAgICAgICAgICBQYXJhbSA9IG47CiAgICAgICAgfQoKICAgICAgICBUIGZhY3QoVCBuKQogICAgICAgIHsKICAgICAgICAgICAgaWYgKG4uaXNaZXJvKCkpIHJldHVybiBuLmdldE5ldXRyYWxFbGVtZW50KCk7CiAgICAgICAgICAgIHJldHVybiBuLk11bHRpcGx5KGZhY3Qobi5TdGVwKCkpKTsKICAgICAgICB9CiAgICB9CgogICAgaW50ZXJmYWNlIElGYWN0b3JpYWJsZTxUPgogICAgewogICAgICAgIGJvb2wgaXNaZXJvKCk7CiAgICAgICAgYm9vbCBpc0JlbG93WmVybygpOwogICAgICAgIFQgU3RlcCgpOwogICAgICAgIFQgZ2V0TmV1dHJhbEVsZW1lbnQoKTsKICAgICAgICBUIE11bHRpcGx5KFQgdCk7CiAgICB9Cn0=