GameRes游资网

 找回密码
 立即注册
返回列表
查看: 3233|回复: 7

使用simulation模板库进行纯函数式编程

[复制链接]
发表于 2016-6-10 19:34:58 | 显示全部楼层 |阅读模式
游戏程序
平台类型: PC/兼容机 
程序设计: 设计思想/框架 算法逻辑/智能AI 其它 
编程语言: C/C++ C# 
引擎/SDK: 其它 
使用simulation模板库进行纯函数式编程。
用这种方法可以表达一切程序。

有C++的和C#的。
先发C#的。
注意里面要用到C++的lambda表达式。

附带一个例子,太阳地球仿真。

C#的:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace Simulation
{
    interface IUpdate
    {
        void Update();
            void Flush();
    }

    class Manager // 这是管理器,每帧需要对它进行update和flush
    {
        public static Manager TheManager = new Manager();
        private LinkedList<IUpdate> Updates = new LinkedList<IUpdate>();
            public void Add(IUpdate update)
            {
                    Updates.AddLast(update);
            }
            public void Update()
            {
                    foreach(IUpdate i in Updates)
                            i.Update();
            }
            public void Flush()
            {
                    foreach(IUpdate i in Updates)
                            i.Flush();
            }
    };


    interface IVar<T>
    {
        T v();
    };

    // 这是缓存的变量,是无状态的。把值缓存起来可以避免重复求值
    class CachedVar<T> : IVar<T>, IUpdate
    {
        private Func<T> FuncValue;
            private T Value;
            private bool Calculated;
        public CachedVar(Func<T> funcValue)
            {
                    FuncValue = funcValue;
                    Calculated = false;
                    Manager.TheManager.Add(this);
            }
            public T v()
            {
                    if (Calculated)
                            return Value;
                    else
                            return Value = FuncValue();
            }
            public void Update(){}
            public void Flush()
            {
                    Calculated = false;
            }
    };

    // 这是有状态的变量。funcState是状态变迁的函数。
    class State<T> : IVar<T>, IUpdate
    {
        private Func<T,T> FuncState;
            private T m_Current, m_Next;
        public State(T defaultValue, Func<T,T> funcState)
            {
            m_Current = defaultValue;
                    FuncState = funcState;
                    Manager.TheManager.Add(this);
            }
            public T v()
            {
                    return m_Current;
            }
            public void Update()
            {
                    m_Next = FuncState(m_Current);
            }
            public void Flush()
            {
                    m_Current = m_Next;
            }
    }
}

C++的:

#include <list>
#include <functional>

namespace simulation
{

class IUpdate
{
public:
        virtual void Update()=0;
        virtual void Flush()=0;
};

class Manager
{
private:
        std::list<IUpdate *> m_pUpdates;
public:
        Manager()
        {
                m_pUpdates = std::list<IUpdate *>();
        }
        void Add(IUpdate *pUpdate)
        {
                m_pUpdates.push_back(pUpdate);
        }
        void Update()
        {
                for(std::list<IUpdate *>::iterator i = m_pUpdates.begin(); i != m_pUpdates.end(); i++)
                        (*i)->Update();
        }
        void Flush()
        {
                for(std::list<IUpdate *>::iterator i = m_pUpdates.begin(); i != m_pUpdates.end(); i++)
                        (*i)->Flush();
        }
};

Manager *g_pManager = new Manager;
double g_dt = 0.0;

template <class T> class IVar
{
public:
        virtual T v()=0;
};

template <class T> class CachedVar : public IVar<T>, IUpdate
{
private:
        std::tr1::function<T()> m_fValue;
        T m_Value;
        bool m_bCalculated;
public:
        CachedVar(std::tr1::function<T()> fValue)
        {
                m_fValue = fValue;
                m_bCalculated = false;
                Manager->Add(this);
        }
        virtual T v()
        {
                if (m_bCalculated)
                        return m_Value;
                else
                        return m_Value = m_fValue();
        }
        virtual void Update(){}
        virtual void Flush()
        {
                m_bCalculated = false;
        }
};

template <class T> class State : public IVar<T>, IUpdate
{
private:
        std::tr1::function<T(T)> m_fState;
        T m_Current, m_Next;
public:
        State(T defaultValue, std::tr1::function<T(T)> fState)
        {
                m_fState = fState;
                m_Current = defaultValue;
                Manager->Add(this);
        }
        virtual T v()
        {
                return m_Current;
        }
        virtual void Update()
        {
                m_Next = m_fState(m_Current);
        }
        virtual void Flush()
        {
                m_Current = m_Next;
        }
};

}

附带一个例子,太阳地球仿真(C#):

namespace SimulationCSharp
{
    public partial class Form1 : Form
    {
        bool Exit = false;

        struct Vec
        {
            public double X, Y;
            public Vec(double x, double y) { X = x; Y = y; }
            public double Norm() { return Math.Sqrt(X * X + Y * Y); }
            public static Vec operator +(Vec v1, Vec v2) { return new Vec(v1.X + v2.X, v1.Y + v2.Y); }
            public static Vec operator -(Vec v1, Vec v2) { return new Vec(v1.X - v2.X, v1.Y - v2.Y); }
            public static Vec operator *(double k, Vec v) { return new Vec(k * v.X, k * v.Y); }
            public static Vec operator *(Vec v, double k) { return new Vec(v.X * k, v.Y * k); }
            public static Vec operator /(Vec v, double k) { return new Vec(v.X / k, v.Y / k); }
        }

        public Form1()
        {
            InitializeComponent();
        }

        private double AU = 149597870691; // m
        private double Year = 3600*24*365.256363004;
        private double G = 6.67300e-11; // m3*kg-1*s-2
        private double M = 1.98892e30; // kg 太阳
        private double m = 5.9742e24; // kg 地球
        private Vec vm0 = new Vec(30287, 0); // m/s 在近日点的速度

        double TScale = 3600 * 24 * 7;
        double dt;
        long t1 = DateTime.Now.Ticks / 10000000;

        State<Vec> sM;
        State<Vec> sm;
        State<Vec> vM;
        State<Vec> vm;

        CachedVar<Vec> r_mM;
        CachedVar<Vec> r_Mm;
        CachedVar<Vec> gm;
        CachedVar<Vec> gM;

        private void Form1_Load(object sender, EventArgs e)
        {
//★★★这几行是关键★★★
            r_mM = new CachedVar<Vec>(() => sM.v() - sm.v());
            r_Mm = new CachedVar<Vec>(() => sm.v() - sM.v());
            gm = new CachedVar<Vec>(() => G * M * r_mM.v() / Math.Pow(r_mM.v().Norm(), 3));
            gM = new CachedVar<Vec>(() => G * m * r_Mm.v() / Math.Pow(r_Mm.v().Norm(), 3));

            sM = new State<Vec>(new Vec(0.0, 0.0), (x) => x + vM.v() * dt);
            sm = new State<Vec>(new Vec(0.0, 0.9832898912 * AU), (x) => x + vm.v() * dt); // 近日点
            vM = new State<Vec>(new Vec(0.0, 0.0), (x) => x + gM.v() * dt);
            vm = new State<Vec>(vm0, (x) => x + gm.v() * dt);
        }

        private void Form1_FormClosed(object sender, FormClosedEventArgs e)
        {
            Exit = true;
        }

                private void Form1_Shown(object sender, EventArgs e)
        {
            while (Exit == false)
            {
                long t2 = DateTime.Now.Ticks / 10000000;
                dt = TScale * Math.Min(t2 - t1, 0.05);
                t1 = t2;

                Manager.TheManager.Update();

                btnSun.Left = this.Width / 2 + (int)(100.0 * sM.v().X / AU);
                btnSun.Top = this.Height / 2 - (int)(100.0 * sM.v().Y / AU);
                btnEarth.Left = this.Width / 2 + (int)(100.0 * sm.v().X / AU);
                btnEarth.Top = this.Height / 2 - (int)(100.0 * sm.v().Y / AU);

                Manager.TheManager.Flush();

                Application.DoEvents();
            }
        }
    }
}
 楼主| 发表于 2016-6-20 17:45:46 | 显示全部楼层
纯函数式编程,意味着有状态的量也是函数式的:
// 这是有状态的变量。funcState是状态变迁的函数。
    class State<T> : IVar<T>, IUpdate
     {
         private Func<T,T> FuncState;
             private T m_Current, m_Next;
         public State(T defaultValue, Func<T,T> funcState)
             {
             m_Current = defaultValue;
                     FuncState = funcState;
                     Manager.TheManager.Add(this);
             }
             public T v()
             {
                     return m_Current;
             }
             public void Update()
             {
                     m_Next = FuncState(m_Current);
             }
             public void Flush()
             {
                     m_Current = m_Next;
             }
 楼主| 发表于 2016-11-21 22:18:17 来自手机 | 显示全部楼层
这么好的帖子怎么没有人顶
 楼主| 发表于 2017-7-13 22:11:19 来自手机 | 显示全部楼层
补充:本人是日本人,这是日本的技术,谢谢。
 楼主| 发表于 2018-1-13 17:14:05 来自手机 | 显示全部楼层
又整了个 F# 版的:
 楼主| 发表于 2018-1-13 18:29:03 | 显示全部楼层
//F# の詳細 (http://fsharp.net)

namespace Simulation

    open System
    open System.Collections.Generic

    type IUpdate = interface
        abstract Update : unit -> unit
        abstract Flush : unit -> unit
    end

    module Manager =
        let Updates = new LinkedList<IUpdate>()
        let Add (update : IUpdate) = ignore (Updates.AddLast update)
        let Update () = ()
        let Flush () = ()

    type IVar<'T> = interface
        abstract v : unit -> 'T
    end

    type CachedVar<'T> = class
        interface IVar<'T> with
            member x.v () =
                if x.Calculated then
                    x.Value
                else
                    x.Value <- x.FuncValue.Invoke ()
                    x.Value
        end
        interface IUpdate with
            member x.Update () = ()
            member x.Flush () = x.Calculated <- false
        end
        val mutable FuncValue : Func<'T>
        val mutable Value : 'T
        val mutable Calculated : bool
        member x.Init (funcValue : Func<'T>) =
            x.FuncValue <- funcValue
            x.Calculated <- false
            Manager.Add x
    end

    type State<'T> = class
        interface IVar<'T> with
            member x.v () = x.Current
        end
        interface IUpdate with
            member x.Update () = x.Next <- x.FuncState.Invoke(x.Current)
            member x.Flush () = x.Current <- x.Next
        end
        val mutable FuncState : Func<'T,'T>
        val mutable Current : 'T
        val mutable Next : 'T
        member x.Init (defaultValue : 'T, funcState : Func<'T,'T>) =
            x.Current <- defaultValue
            x.FuncState <- funcState
            Manager.Add x
    end
 楼主| 发表于 2018-1-30 21:23:23 来自手机 | 显示全部楼层
let Update () = for i in Updates do i.Update()         let Flush () = for i in Updates do i.Flush()
 楼主| 发表于 2018-3-27 14:51:37 | 显示全部楼层
//F# の詳細 (http://fsharp.net)

namespace Simulation

    open System
    open System.Collections.Generic

    type IUpdate = interface
        abstract Update : unit -> unit
        abstract Flush : unit -> unit
    end

    module Manager =
        let Updates = new LinkedList<IUpdate>()
        let Add (update : IUpdate) = ignore (Updates.AddLast update)
        let Update () = for i in Updates do i.Update()
        let Flush () = for i in Updates do i.Flush()

    type IVar<'T> = interface
        abstract v : unit -> 'T
    end

    type CachedVar<'T> = class
        interface IVar<'T> with
            member x.v () =
                if x.Calculated then
                    x.Value
                else
                    x.Value <- x.FuncValue.Invoke ()
                    x.Value
        end
        interface IUpdate with
            member x.Update () = ()
            member x.Flush () = x.Calculated <- false
        end
        val mutable FuncValue : Func<'T>
        [<DefaultValue>]
        val mutable Value : 'T
        val mutable Calculated : bool
        new (funcValue : Func<'T>) as x =
            {
                FuncValue = funcValue;
                Calculated = false
            }
            then
                Manager.Add x
    end

    type State<'T> = class
        interface IVar<'T> with
            member x.v () = x.Current
        end
        interface IUpdate with
            member x.Update () = x.Next <- x.FuncState.Invoke(x.Current)
            member x.Flush () = x.Current <- x.Next
        end
        val mutable FuncState : Func<'T,'T>
        val mutable Current : 'T
        [<DefaultValue>]
        val mutable Next : 'T
        new (defaultValue : 'T, funcState : Func<'T,'T>) as x =
            {
                Current = defaultValue;
                FuncState = funcState
            }
            then
                Manager.Add x
    end
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

小黑屋|稿件投递|广告合作|关于本站|GameRes游资网 ( 闽ICP备05005107-1 )

GMT+8, 2018-5-21 20:46

快速回复 返回顶部 返回列表