Skip to content

Instantly share code, notes, and snippets.

@k3kaimu
Created November 11, 2017 15:37
Show Gist options
  • Save k3kaimu/03606280f7805a351f45f9e9cdae5dd2 to your computer and use it in GitHub Desktop.
Save k3kaimu/03606280f7805a351f45f9e9cdae5dd2 to your computer and use it in GitHub Desktop.
/+ dub.json:
{ "dependencies": {"mir-random": "~>0.2.8"} }
+/
import std.container : RedBlackTree;
import std.algorithm : max;
interface Event(Time)
{
Time time() const @property;
Event dupImpl() const @property;
final This dup(this This)() const @property
{
return cast(This) dupImpl();
}
}
interface DurationEvent(Time) : Event!Time
{
alias beginTime = time;
Time endTime() const @property;
}
auto duration(Time)(const DurationEvent!Time event)
{
return event.endTime - event.beginTime;
}
interface World(Time)
{
Time nowTime();
void appendEvent(immutable Event!Time event) in{ assert(this.nowTime < event.time); };
bool hasEvent();
size_t processEvents(Time limit, bool withEQ = true);
size_t processNextEvents();
}
class SimpleWorld(Time) : World!Time
{
this(Time initTime)
{
_nowTime = initTime;
_eventList = new typeof(_eventList)();
}
void callbackOnEvent(void delegate(immutable(Event!Time)[]) onEvent) @property
{
_onEvent = onEvent;
}
void appendEvent(immutable Event!Time event)
{
_eventList.insert(event);
}
Time nowTime() { return _nowTime; }
bool hasEvent() { return _eventList.length != 0; }
size_t processEvents(Time limit, bool withEQ = true)
{
size_t cnt;
while(_eventList.length != 0 && (withEQ ? (_eventList.front.time <= limit) : (_eventList.front.time < limit)))
{
immutable(Event!Time)[] list;
_nowTime = _eventList.front.time;
while(_eventList.length != 0 && _nowTime == _eventList.front.time){
list ~= _eventList.front;
_eventList.removeFront();
}
cnt += list.length;
if(_onEvent) _onEvent(list);
}
return cnt;
}
size_t processNextEvents()
{
if(_eventList.length != 0)
return processEvents(_eventList.front.time, true);
else
return 0;
}
private:
RedBlackTree!(immutable(Event!Time), "a.time < b.time", true) _eventList;
Time _nowTime;
void delegate(immutable(Event!Time)[]) _onEvent;
}
class PrimitiveEvent(Time) : Event!Time
{
this(Time time) { _time = time; }
Time time() const @property { return _time; }
Event dupImpl() const @property
{
return new typeof(this)(_time);
}
private:
Time _time;
}
interface Thing(Time)
{
void onEvent(const Event!Time[]);
}
class CollisionDetector(Time)
{
this() {}
void callbackOnEvent(void delegate(immutable(DurationEvent!Time)[]) onEvent)
{
_onEventDg = onEvent;
}
void callbackOnFailure(void delegate(immutable(DurationEvent!Time)[]) onFailure)
{
_onFailureDg = onFailure;
}
void onEvent(immutable(DurationEvent!Time)[] event)
{
this.flush(event[0].beginTime);
foreach(e; event)
_mixedPacket.mix(e);
}
void flush(Time flushTime = Time.max)
{
_mixedPacket.flush(flushTime, _onEventDg, _onFailureDg);
}
private:
MixedPacket _mixedPacket;
void delegate(immutable(DurationEvent!Time)[]) _onEventDg;
void delegate(immutable(DurationEvent!Time)[]) _onFailureDg;
static struct MixedPacket
{
immutable(DurationEvent!Time)[] events;
Time beginTime;
Time endTime;
void flush(Time flushTime,
void delegate(immutable(DurationEvent!Time)[]) onSuccess,
void delegate(immutable(DurationEvent!Time)[]) onFailure)
{
// パケットが一つも到来してない
if(events.length == 0) return;
if(endTime <= flushTime){
// パケットが1つ == 衝突していない
if(events.length == 1){
if(onSuccess !is null) onSuccess(events);
}
else{
if(onFailure !is null) onFailure(events);
}
events.length = 0;
}
}
void mix(immutable DurationEvent!Time event)
{
if(events.length == 0){
events ~= event;
beginTime = event.beginTime;
endTime = event.endTime;
}else{
events ~= event;
endTime = max(endTime, event.endTime);
}
}
}
}
void main()
{
import std.stdio;
import std.algorithm;
import std.range;
import mir.random;
import mir.random.variable;
enum float packetLength = 1;
enum float totalPackets = 1E6;
foreach(g; iota(1, 31).map!"a*0.1")
{
immutable float totalTime = totalPackets * packetLength / g;
auto rnd = Random(unpredictableSeed);
auto erv = ExponentialVariable!double(packetLength / g);
static
class TestEvent : DurationEvent!float
{
this(float beginTime, float endTime) pure
{
_beginTime = beginTime;
_endTime = endTime;
}
float time() const @property { return _beginTime; }
float endTime() const @property { return _endTime; }
Event!float dupImpl() const @property { return new TestEvent(_beginTime, _endTime); }
private:
float _beginTime, _endTime;
}
auto detector = new CollisionDetector!float();
auto world = new SimpleWorld!float(-1);
world.callbackOnEvent = delegate(immutable(Event!float)[] events)
{
detector.onEvent(cast(immutable(DurationEvent!float)[])events);
};
size_t cnt;
detector.callbackOnEvent = delegate(immutable(DurationEvent!float)[] events)
{
cnt += events.length;
};
float nowTime = 0;
while(nowTime < totalTime){
auto v = nowTime + erv(rnd);
nowTime = v;
//writeln(v);
world.appendEvent(new immutable TestEvent(v, v+1));
world.processNextEvents();
}
writefln("%s : %s", g, cnt / (totalTime / packetLength));
}
}
//void main()
//{
// import std.stdio;
// import std.algorithm;
// alias Time = float;
// auto detector = new CollisionDetector!Time();
// detector.callbackOnEvent = delegate(immutable(DurationEvent!Time)[] events){
// writeln("Success: ", events.map!"[a.beginTime, a.endTime]");
// };
// detector.callbackOnFailure = delegate(immutable(DurationEvent!Time)[] events){
// writeln("Failure: ", events.map!"[a.beginTime, a.endTime]");
// };
// static
// class TestEvent : DurationEvent!Time
// {
// this(Time beginTime, Time endTime) pure
// {
// _beginTime = beginTime;
// _endTime = endTime;
// }
// Time time() const @property { return _beginTime; }
// Time endTime() const @property { return _endTime; }
// Event!Time dupImpl() const @property { return new TestEvent(_beginTime, _endTime); }
// private:
// Time _beginTime, _endTime;
// }
// receiver.onEvent([new immutable(TestEvent)(0, 1)]);
// receiver.onEvent([new immutable(TestEvent)(2, 3)]);
// receiver.onEvent([new immutable(TestEvent)(3, 4)]);
// receiver.onEvent([new immutable(TestEvent)(3.1, 4.2)]);
// receiver.onEvent([new immutable(TestEvent)(3.2, 4.8)]);
// receiver.onEvent([new immutable(TestEvent)(4.8, 5.0)]);
// receiver.onEvent([new immutable(TestEvent)(5, 5)]);
// receiver.flush();
//}
//void main()
//{
// import core.time;
// import std.stdio;
// auto world = new SimpleWorld!(Duration)(0.seconds, (Event!Duration[] e){
// writefln("%s : %s", e[0].time, e);
// });
// assert(world.hasEvent == false);
// world.appendEvent(new PrimitiveEvent!Duration(1.seconds));
// world.appendEvent(new PrimitiveEvent!Duration(1.seconds));
// writeln(world.nowTime);
// world.processNextEvents().writeln();
// writeln(world.nowTime);
//}
//import std.stdio;
//import mir.random;
//import mir.random.variable;
//void main()
//{
// auto rnd = Random(unpredictableSeed);
// auto erv = ExponentialVariable!double(3.0);
// uint[100] hist;
// foreach(i; 0 .. 1000){
// auto v = prv(rnd);
// if(v < 100) hist[v] += 1;
// }
// foreach(i, e; hist[0 .. 10])
// writefln("%2d : %3d", i, e);
//}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment