Skip to content

Instantly share code, notes, and snippets.

@kb10uy
Last active December 10, 2015 16:19
Show Gist options
  • Save kb10uy/4460519 to your computer and use it in GitHub Desktop.
Save kb10uy/4460519 to your computer and use it in GitHub Desktop.
保安装置の動作を再現するクラス立ち。 XNA4.0 + IronPython 2.7.3で作成。 ※Trainクラス内のマスコン動作のラムダは実際の動作と全然違います
#coding: shift-jis
#保安装置のスクリプトのサンプル
#Automatic Nanimo Shinai system
#必須インポート
import clr
from TrainSystemSimulator.Simulate import *
from Microsoft.Xna.Framework import *
from Microsoft.Xna.Framework.Content import *
from Microsoft.Xna.Framework.Graphics import *
from Microsoft.Xna.Framework.Media import *
#保安装置を表すクラスです。
#名前はProtectiveDeviceにし、IProtectiveDeviceを実装してください。
class ProtectiveDevice(IProtectiveDevice):
#以下はプロパティのためのメソッド。インターフェースには含まれません
def setdfnp(self,val):
self.notch=val
def getdfnp(self):
return self.notch
def setdfn(self,val):
self.fook=val
def getdfn(self):
return self.fook
###########################ここからインターフェース用の実装################
#保安装置インスタンス作成時に呼ばれます
def Install(self,tool):
self.fook=0
self.notch=MasterControl.N
return
#保安装置の電源が入った時に呼ばれます
def Initialize(self):
return
#描画時に呼ばれます。
#sb引数はXNAにおけるSpriteBatchです。Begin,Endの必要はありません。
def Draw(self,sb):
return
#更新時に呼ばれます。
def Update(self):
return
#保安装置側でノッチを制御している時に、そのノッチを返します。
FookedNotchPosition = property(getdfnp,setdfnp)
#保安装置でノッチを制御していれば1,そうでなければ0を返してください。
NotchFooked = property(getdfn,setdfn)
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Reflection;
using Microsoft.Scripting.Hosting;
using IronPython.Hosting;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Audio;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.GamerServices;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
using Microsoft.Xna.Framework.Media;
using TrainSystemSimulator.Simulate;
namespace TrainSystemSimulator
{
/// <summary>
/// IronPythonを扱いやすくするためのラッパ
/// </summary>
public class PythonScript
{
ScriptEngine engine = Python.CreateEngine();
ScriptSource src;
public ScriptScope Scope { get; set; }
public PythonScript()
{
engine.Runtime.LoadAssembly(typeof(Game1).Assembly);
///XNAのて機能なクラスを使って読み込ませる
engine.Runtime.LoadAssembly(typeof(Vector2).Assembly);
engine.Runtime.LoadAssembly(typeof(Texture2D).Assembly);
Scope = engine.CreateScope();
}
public void LoadFromFile(string path)
{
src = engine.CreateScriptSourceFromFile(path);
src.Execute(Scope);
}
public void loadFromString(string exp)
{
src = engine.CreateScriptSourceFromString(exp);
src.Execute(Scope);
}
/// <summary>
/// 現在のスコープ内で式を実行して、
/// その結果を返します。
/// </summary>
/// <typeparam name="InsType">返して欲しい型</typeparam>
/// <param name="defexp">式</param>
/// <returns>実行した式の返り値</returns>
public InsType GetInstance<InsType>(string defexp)
{
return engine.Execute<InsType>(defexp, Scope);
}
}
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Audio;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.GamerServices;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
using Microsoft.Xna.Framework.Media;
using TrainSystemSimulator;
namespace TrainSystemSimulator.Simulate
{
/// <summary>
/// 列車が地上子を通過した時に発生するイベントのデリゲート型。
/// </summary>
public delegate void BeaconEventHandler();
public delegate void RailwayLoadImageEventHandler(string name);
/// <summary>
/// マスコンの状態。
/// </summary>
public enum MasterControl
{
EB = 0,
B8,
B7,
B6,
B5,
B4,
B3,
B2,
B1,
BF,
N,
P1,
P2,
P3,
P4,
P5,
}
/// <summary>
/// 保安装置スクリプトで実装する必要のあるインターフェース。
/// </summary>
public interface IProtectiveDevice
{
/// <summary>
/// 保安装置に関する情報をウンタラカンタラ
/// </summary>
void Install(PDTool tool);
/// <summary>
/// 保安装置の電源が入った時。
/// </summary>
void Initialize();
/// <summary>
/// 描画時。
/// </summary>
/// <param name="sb">SpriteBatch</param>
void Draw(SpriteBatch sb);
/// <summary>
/// 更新。
/// </summary>
void Update(); //Trainクラスの何かを送る
//BeaconEventHandle
/// <summary>
/// 地上子通り過ぎちまった時
/// </summary>
/// <param name="e">e</param>
void BeaconPassed(BeaconEventArgs e);
/// <summary>
/// 保安装置側でノッチを制御している時のノッチ
/// </summary>
MasterControl FookedNotchPosition { get; }
/// <summary>
/// 保安装置側でノッチをフックしているか。
/// </summary>
int NotchFooked { get; }
}
/// <summary>
/// 保安装置が準備に必要なものを集めます。
/// </summary>
public class PDTool
{
public GraphicsDevice Device { get; private set; }
public Railway RunningRailway { get; private set; }
public PDTool(GraphicsDevice d,Railway r)
{
Device = d;
RunningRailway = r;
}
public Texture2D LoadImage(string file)
{
using (Stream i = File.OpenRead(file))
{
return Texture2D.FromStream(Device, i);
}
}
public void RegistSignalLinkBeacon(int pos, string type)
{
RunningRailway.RegistSignalLinkBeacon(type, pos);
}
}
/// <summary>
/// そのまま
/// </summary>
public class BeaconEventArgs : EventArgs
{
/// <summary>
/// 空っぽで初期化
/// </summary>
public BeaconEventArgs()
: base()
{
PassedBeacon = new Beacon();
}
/// <summary>
/// 地上子指定で初期化
/// </summary>
/// <param name="b">地上子</param>
public BeaconEventArgs(Beacon b)
{
PassedBeacon = b;
}
/// <summary>
/// 通り過ぎちまった地上子。
/// </summary>
public Beacon PassedBeacon { get; private set; }
}
/// <summary>
/// 地上子
/// </summary>
public class Beacon
{
/// <summary>
/// 位置
/// </summary>
public int Position { get; set; }
/// <summary>
/// 種類
/// </summary>
public string Type { get; set; }
/// <summary>
/// 連動している信号
/// </summary>
public ExternalSignal LinkedSingal { get; set; }
/// <summary>
/// 地上子としてのプライドをたもちます。
/// </summary>
/// <param name="tp">現在の列車位置</param>
/// <param name="ptp">前回の列車位置</param>
/// <param name="train">列車</param>
public void Update(List<double> tp, List<double> ptp, List<Train> train)
{
for (int i = 0; i < tp.Count; i++)
{
if (ptp[i] <= Position && tp[i] > Position)
{
train[i].ProtectiveDevice.BeaconPassed(new BeaconEventArgs(this));
}
}
}
}
/// <summary>
/// 列車を模した
/// </summary>
public class Train
{
///<summary>速度</summary>
public double Speed { get; protected set; }
///<summary>マスコン位置</summary>
public MasterControl Control { get; protected set; }
///<summary>保安装置</summary>
public IProtectiveDevice ProtectiveDevice { get; protected set; }
///<summary>保安装置とかのスクリプト</summary>
public PythonScript Script { get; protected set; }
/// <summary>
/// 加速度の対応表
/// </summary>
public Dictionary<MasterControl, Func<double, double>> MasterControlLink { get; protected set; }
public double FrameRate { get; protected set; }
/// <summary>
/// 制御に使うスクリプトを指定して初期化。
/// </summary>
/// <param name="script">スクリプト</param>
public Train(PythonScript script,PDTool tool)
{
Speed = 0.0;
FrameRate = 60;
Control = MasterControl.N;
Script = script;
MasterControlLink = new Dictionary<MasterControl, Func<double, double>>();
//マスコン対応表
MasterControlLink[MasterControl.EB] = (s) => s - (4.0 / FrameRate);
MasterControlLink[MasterControl.B8] = (s) => s - (3.0 / FrameRate);
MasterControlLink[MasterControl.B7] = (s) => s - (2.8 / FrameRate);
MasterControlLink[MasterControl.B6] = (s) => s - (2.4 / FrameRate);
MasterControlLink[MasterControl.B5] = (s) => s - (2.0 / FrameRate);
MasterControlLink[MasterControl.B4] = (s) => s - (1.8 / FrameRate);
MasterControlLink[MasterControl.B3] = (s) => s - (1.2 / FrameRate);
MasterControlLink[MasterControl.B2] = (s) => s - (0.8 / FrameRate);
MasterControlLink[MasterControl.B1] = (s) => s - (0.4 / FrameRate);
MasterControlLink[MasterControl.BF] = (s) => s;
MasterControlLink[MasterControl.N] = (s) => s - (s * 0.001 / FrameRate);
MasterControlLink[MasterControl.P1] = (s) => s + (0.7 / FrameRate);
MasterControlLink[MasterControl.P2] = (s) => s + (1.5 / FrameRate);
MasterControlLink[MasterControl.P3] = (s) => s + (2.0 / FrameRate);
MasterControlLink[MasterControl.P4] = (s) => s + (2.6 / FrameRate);
MasterControlLink[MasterControl.P5] = (s) => s + (3.3 / FrameRate);
ProtectiveDevice = Script.GetInstance<IProtectiveDevice>("ProtectiveDevice()");
ProtectiveDevice.Install(tool);
ProtectiveDevice.Initialize();
}
/// <summary>
/// 描画します。別にUpdateだけでもおk
/// </summary>
/// <param name="sb">SpriteBatch</param>
public void Draw(SpriteBatch sb)
{
ProtectiveDevice.Draw(sb);
}
/// <summary>
/// 更新します。毎フレーム必ず呼び出してね。
/// </summary>
public void Update()
{
ProtectiveDevice.Update();
//速度更新
if (ProtectiveDevice.NotchFooked==1)
{
Speed = Math.Max(MasterControlLink[ProtectiveDevice.FookedNotchPosition](Speed),0);
}
else
{
Speed = Math.Max(MasterControlLink[Control](Speed),0);
}
}
/// <summary>
/// マスコン状態を設定します。
/// </summary>
/// <param name="mc"></param>
public void SetNotch(MasterControl mc)
{
Control = mc;
}
}
/// <summary>
/// 信号の現示
/// </summary>
public enum SignalKind
{
/// <summary>
/// 0km/h
/// </summary>
R,
/// <summary>
/// 25km/h
/// </summary>
YY,
/// <summary>
/// 45km/h
/// </summary>
Y,
/// <summary>
/// 70km/h
/// </summary>
YG,
/// <summary>
/// 105km/h
/// </summary>
YGF,
/// <summary>
/// 130km/h
/// </summary>
G,
/// <summary>
/// 160km/h
/// </summary>
GG
}
/// <summary>
/// 信号(まあ正確には車外なのでExternal)
/// </summary>
public class ExternalSignal
{
public SignalKind Kind { get; set; }
public ExternalSignal()
{
Kind = SignalKind.R;
}
}
public class Railway
{
/// <summary>
/// 列車位置。
/// </summary>
public List<double> TrainPosition { get; private set; }
/// <summary>
/// 前フレーム列車位置。
/// </summary>
public List<double> PreviousTrainPosition { get; set; }
/// <summary>
/// 列車。
/// </summary>
public List<Train> Trains { get; private set; }
/// <summary>
/// 地上子。
/// </summary>
public Dictionary<int, List<Beacon>> Beacons { get; private set; }
/// <summary>
/// 信号。
/// </summary>
public Dictionary<int, ExternalSignal> Signals { get; private set; }
/// <summary>
/// 信号に連動した地上子。
/// </summary>
public Dictionary<int, string> SignalLinkBeacons { get; private set; }
/// <summary>
/// フレームレート
/// </summary>
public double FrameRate { get; set; }
public event RailwayLoadImageEventHandler LoadImage;
/// <summary>
/// とりあえず初期化。
/// </summary>
public Railway()
{
TrainPosition = new List<double>();
PreviousTrainPosition = new List<double>();
Trains = new List<Train>();
Beacons = new Dictionary<int, List<Beacon>>();
Signals = new Dictionary<int, ExternalSignal>();
SignalLinkBeacons = new Dictionary<int, string>();
FrameRate = 60.0;
}
/// <summary>
/// 列車を設置します。
/// </summary>
/// <param name="train">列車</param>
/// <param name="pos">位置</param>
public int PutTrain(Train train, double pos = 0)
{
Trains.Add(train);
TrainPosition.Add(pos);
PreviousTrainPosition.Add(0);
return Trains.Count - 1;
}
/// <summary>
/// 信号を(ry
/// </summary>
/// <param name="sig"></param>
/// <param name="pos"></param>
public void RegistSignal(ExternalSignal sig, int pos)
{
Signals[pos] = sig;
foreach (var bs in SignalLinkBeacons)
{
RegistBeacon(bs.Value, bs.Key);
}
}
/// <summary>
/// 信号連動地上子、登録。
/// </summary>
/// <param name="type"></param>
/// <param name="pos"></param>
public void RegistSignalLinkBeacon(string type, int pos)
{
SignalLinkBeacons[pos] = type;
}
/// <summary>
/// 地上子、設置。
/// </summary>
/// <param name="type"></param>
/// <param name="pos"></param>
public void RegistBeacon(string type, int pos)
{
if (Beacons[pos] != null)
{
//モウすでにそこに1個以上あった場合
Beacons[pos].Add(new Beacon { Type = type, LinkedSingal = null, Position = pos });
}
else
{
//まだそこに何もなかった
Beacons[pos] = new List<Beacon>();
Beacons[pos].Add(new Beacon { Type = type, LinkedSingal = null, Position = pos });
}
}
/// <summary>
/// 指定位置が属する閉塞の信号を取得します。
/// </summary>
/// <param name="pos">位置(m)</param>
/// <returns>信号の現示</returns>
public SignalKind GetThereSectionSignal(int pos)
{
return Signals
.Where(p => p.Key < pos)
.OrderBy(p => p.Key)
.Last()
.Value.Kind;
}
/// <summary>
/// 指定位置が属する閉塞の次の閉塞の信号を取得します。
/// </summary>
/// <param name="pos">位置(m)</param>
/// <returns>信号の現示</returns>
public SignalKind GetNextSectionSignal(int pos)
{
return Signals
.Where(p => p.Key >= pos)
.OrderBy(p => p.Key)
.First()
.Value.Kind;
}
/// <summary>
/// 更新。
/// </summary>
public void Update()
{
//地上子更新
foreach (var bs in Beacons)
{
foreach (Beacon b in bs.Value)
{
b.Update(TrainPosition, PreviousTrainPosition, Trains);
}
}
//あとは
/*
* 列車をすすめることとか色々
*/
for (int i = 0; i < Trains.Count; i++)
{
Trains[i].Update();
TrainPosition[i] += Trains[i].Speed / 3.6 / FrameRate;
}
//信号状況更新
var sig = Signals.OrderBy((p) => p.Key).ToArray();
for (int i = 0; i < sig.Count(); i++)
{
foreach (double p in TrainPosition)
{
if (p >= sig[i].Key && i + 1 <= sig.Count() - 1 && p <= sig[i + 1].Key)
{
//その信号が指す閉塞内に列車が存在したら
Signals[sig[i].Key].Kind = SignalKind.R;
if (i - 1 >= 0) Signals[sig[i - 1].Key].Kind = SignalKind.YY;
if (i - 2 >= 0) Signals[sig[i - 2].Key].Kind = SignalKind.Y;
if (i - 3 >= 0) Signals[sig[i - 3].Key].Kind = SignalKind.YG;
if (i - 4 >= 0) Signals[sig[i - 4].Key].Kind = SignalKind.YGF;
if (i - 5 >= 0) Signals[sig[i - 5].Key].Kind = SignalKind.G;
if (i - 6 >= 0) Signals[sig[i - 6].Key].Kind = SignalKind.GG;
}
}
}
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment