Simple implementation of Decision Tree with C++
=================================
#include <iostream>
using namespace std;
bool val_visible = false;
bool val_evidence = true;
bool val_hungry = false;
float val_distance = 50;
class GameWorldEnv
{
public:
float GetPlayerDistance()
{
return rand() % 100;
}
};
class DecisionNode
{
public:
virtual DecisionNode* Decision() { return nullptr; };
virtual void Action() {};
};
class Decision : public DecisionNode
{
public:
};
class Boolean : public Decision
{
public:
Boolean(bool* val, DecisionNode* yes, DecisionNode* no)
: mTestValue(val)
, mYesNode(yes)
, mNoNode(no)
{
}
DecisionNode* Decision()
{
if (*mTestValue)
{
return mYesNode;
}
return mNoNode;
}
DecisionNode* mYesNode;
DecisionNode* mNoNode;
bool* mTestValue;
};
class Close : public Decision
{
public:
Close(float* distance, GameWorldEnv* env, DecisionNode* yes, DecisionNode* no)
: mTestDistance(distance)
, mEnv(env)
, mYesNode(yes)
, mNoNode(no)
{
}
DecisionNode* Decision()
{
if (mEnv->GetPlayerDistance() < *mTestDistance)
{
return mYesNode;
}
return mNoNode;
}
DecisionNode* mYesNode;
DecisionNode* mNoNode;
GameWorldEnv* mEnv;
float* mTestDistance;
};
class Action : public DecisionNode
{
public:
};
class Eat : public Action
{
public:
void Action()
{
cout << "Action Executed : Eat" << endl;
}
};
class Wander : public Action
{
public:
void Action()
{
cout << "Action Executed : Wander" << endl;
}
};
class Attack : public Action
{
public:
void Action()
{
cout << "Action Executed : Attack" << endl;
}
};
class Trace : public Action
{
public:
void Action()
{
cout << "Action Executed : Trace" << endl;
}
};
// Action은 Wander, Eat, Trace, Attack
// 총 4개가 있다.
void Process(DecisionNode* node)
{
DecisionNode* newNode = node->Decision();
if (newNode != nullptr)
{
Process(newNode);
}
else
{
// action
node->Action();
}
}
int main()
{
Eat eatNode;
Wander wanderNode;
Attack attackNode;
Trace traceNode;
GameWorldEnv env;
Close closeNode(&val_distance, &env, &attackNode, &traceNode);
Boolean hungryNode(&val_hungry, &eatNode, &wanderNode);
Boolean evidenceNode(&val_evidence, &closeNode, &hungryNode);
Boolean visibleNode(&val_visible, &closeNode, &evidenceNode);
DecisionNode* root = &visibleNode;
// Make a decision tree
for (int i = 0; i < 3; ++i)
{
Process(root);
Process(root);
}
}
Showing posts with label programming. Show all posts
Showing posts with label programming. Show all posts
Sunday, April 5, 2020
Wednesday, February 26, 2020
Wrapping angle
Because nature of rotation angle, when we interpolate angles we could have some problems. For instance we have angle A0 and A1.
A0 is -170 degree
A1 is 170 degree
If we interpolate A0 to A1 then it will take 340 degree turn to reach the A1.(which is clockwise)
instead we can take 20 degree which is counter-clockwise, it is much faster way to reach A1. To solve this kind of problem we can use wrap angle technique.
// angle in degree
float wrapPI(float angle)
{
float secondTerm = floor((angle + 180.0f) / 360.0f);
return angle - 360.0f * secondTerm;
}
floor is the function which will take same as given input x or highest integer value less than.
As you can see the below video, blue line is the A0(which is base angle) and red line(longer one) is the target angle which is A1. shorter red line is the result of interpolation.
// angle in degree
float wrapPI(float angle)
{
float secondTerm = floor((angle + 180.0f) / 360.0f);
return angle - 360.0f * secondTerm;
}
float baseAngle = 0;
float targetAngle = 90;
float angleRatio = 0.0f;
void Render(HDC hdc)
{
XFORM xForm;
xForm.eM11 = (FLOAT) 1.0;
xForm.eM12 = (FLOAT) 0.0;
xForm.eM21 = (FLOAT) 0.0;
xForm.eM22 = (FLOAT) -1.0;
xForm.eDx = (FLOAT) 300.0;
xForm.eDy = (FLOAT) 300.0;
SetGraphicsMode(hdc, GM_ADVANCED);
SetWorldTransform(hdc, &xForm);
float baseLength = 100;
float targetLength = 80;
float diffAngle = wrapPI(targetAngle - baseAngle);
float angle = baseAngle + (diffAngle * angleRatio);
// draw baseAngle
HPEN bluePen = CreatePen(PS_SOLID, 1, RGB(0, 0, 255));
HPEN redPen = CreatePen(PS_SOLID, 1, RGB(255, 0, 0));
HGDIOBJ oldPen = nullptr;
oldPen = SelectObject(hdc, bluePen);
MoveToEx(hdc, 0, 0, nullptr);
// convert degree to radian
float baseRadian = baseAngle * 3.14 / 180.0f;
LineTo(hdc, cosf(baseRadian) * baseLength, sinf(baseRadian) * baseLength);
SelectObject(hdc, oldPen);
DeleteObject(bluePen);
oldPen = SelectObject(hdc, redPen);
MoveToEx(hdc, 0, 0, nullptr);
float angleRadian = angle * 3.14 / 180.0f;
float targetRadian = targetAngle * 3.14 / 180.0f;
LineTo(hdc, cosf(targetRadian) * baseLength, sinf(targetRadian) * baseLength);
MoveToEx(hdc, 0, 0, nullptr);
LineTo(hdc, cosf(angleRadian) * targetLength, sinf(angleRadian) * targetLength);
SelectObject(hdc, oldPen);
DeleteObject(redPen);
angleRatio += 0.01f;
if (angleRatio >= 1.0f)
{
// choose another
baseAngle = rand() % 360;
targetAngle = rand() % 360;
angleRatio = 0.0f;
}
}
Saturday, February 1, 2020
DOS style directory viewer
I've just made a DOS style directory viewer for fun. Implement all the UI features by hand is really fun to do. you should try too!
Friday, November 1, 2019
Time Calculator
I don't know why there is no program, which is able to set source time and based on the time difference calculate destination's time.
LA is -16 hours slower than South Korea. To make comfortable time for each others, I had to calculate -16 hours but as you know I'm a programmer and lazy.
So I created a program to calculate for me.
Source is really simple.
===================================
public partial class frmTimeCalculator : Form
{
public frmTimeCalculator()
{
InitializeComponent();
}
private void frmTimeCalculator_Load(object sender, EventArgs e)
{
sourceTime.CustomFormat = "MM/dd/yyyy hh:mm:ss tt";
sourceTime.Format = DateTimePickerFormat.Custom;
destTime.CustomFormat = "MM/dd/yyyy hh:mm:ss tt";
destTime.Format = DateTimePickerFormat.Custom;
}
private void dateTimePicker1_ValueChanged(object sender, EventArgs e)
{
DateTime laTime = sourceTime.Value.AddHours(-16);
destTime.Value = laTime;
}
}
LA is -16 hours slower than South Korea. To make comfortable time for each others, I had to calculate -16 hours but as you know I'm a programmer and lazy.
So I created a program to calculate for me.
Source is really simple.
===================================
public partial class frmTimeCalculator : Form
{
public frmTimeCalculator()
{
InitializeComponent();
}
private void frmTimeCalculator_Load(object sender, EventArgs e)
{
sourceTime.CustomFormat = "MM/dd/yyyy hh:mm:ss tt";
sourceTime.Format = DateTimePickerFormat.Custom;
destTime.CustomFormat = "MM/dd/yyyy hh:mm:ss tt";
destTime.Format = DateTimePickerFormat.Custom;
}
private void dateTimePicker1_ValueChanged(object sender, EventArgs e)
{
DateTime laTime = sourceTime.Value.AddHours(-16);
destTime.Value = laTime;
}
}
Tuesday, October 29, 2019
One pattern that I use on multi-threaded environment.
As many Unity developer already knows, Unity's logic runs in main thread. When you need network feature in your project you probably use socket or other network library. Of course when you send/receive some packets over the network, you will use non-blocking or asynchronize mechanism.
Normally we use callback or event function and those are called by OS. Ok then you can do whatever you want. Something like this.
void MyReceiveFunction(data)
{
// ok, I received a data!
if ( data == 0 )
{
foo(0);
}
else if ( data == 1001 )
{
foo(1001);
}
else
{
...
}
}
The problem is that the function is called on different thread. (which is not mianthread)
so If you do anything that it is related with main thread or GUI, logic won't run correctly. The pattern I'm going to talk about is saving this situation! (very simple)
void MyReceiveFunction(data)
{
// ok, I received a data!
if ( data == 0 )
{
reserveFoo(0);
}
else if ( data == 1001 )
{
reserveFoo(1001);
}
else
{
...
}
}
in the reserveFoo function we can reserve the command like below.
void reserveFoo(int cmd)
{
lock
{
reserveFooList.add(cmd);
}
}
reserveFooList is a container. It store a cmd. and it is used in consumer logic in mainthread.
// Update function is called in main thread.
void Update()
{
if ( reserveFooList.size > 0 )
{
foreach(element : reserveFooList)
{
Foo(element);
}
reserveFooList.clear;
}
}
Now Update function is called in main thread and checks whether size of reserveFooList is greater than 0 which means it has some element to do.
if the list is not empty then iterate all the elements and process those in main thread. That's is the main idea.
Of course you can use invoke method for solve this issue but personally I prefer to do this.
Normally we use callback or event function and those are called by OS. Ok then you can do whatever you want. Something like this.
void MyReceiveFunction(data)
{
// ok, I received a data!
if ( data == 0 )
{
foo(0);
}
else if ( data == 1001 )
{
foo(1001);
}
else
{
...
}
}
The problem is that the function is called on different thread. (which is not mianthread)
so If you do anything that it is related with main thread or GUI, logic won't run correctly. The pattern I'm going to talk about is saving this situation! (very simple)
void MyReceiveFunction(data)
{
// ok, I received a data!
if ( data == 0 )
{
reserveFoo(0);
}
else if ( data == 1001 )
{
reserveFoo(1001);
}
else
{
...
}
}
in the reserveFoo function we can reserve the command like below.
void reserveFoo(int cmd)
{
lock
{
reserveFooList.add(cmd);
}
}
reserveFooList is a container. It store a cmd. and it is used in consumer logic in mainthread.
// Update function is called in main thread.
void Update()
{
if ( reserveFooList.size > 0 )
{
foreach(element : reserveFooList)
{
Foo(element);
}
reserveFooList.clear;
}
}
Now Update function is called in main thread and checks whether size of reserveFooList is greater than 0 which means it has some element to do.
if the list is not empty then iterate all the elements and process those in main thread. That's is the main idea.
Of course you can use invoke method for solve this issue but personally I prefer to do this.
Saturday, October 26, 2019
Every programming language has its own idioms.
Every programming language has its own idioms and idioms are not the same as Design Pattern. If you already know computer language such as C, C++, Java but you feel you are not good at it, then I suggest you to know/use/apply the idioms of the languages.
I'm sure you get the idea.
I'm sure you get the idea.
Wednesday, January 9, 2013
Subscribe to:
Posts (Atom)
Task in UnrealEngine
https://www.youtube.com/watch?v=1lBadANnJaw
-
Unity released very good FPS example for people and I decided to analysis how they make this. Personally I wanted to show you how I analys...
-
Because nature of rotation angle, when we interpolate angles we could have some problems. For instance we have angle A0 and A1. A0 is -...
-
http://rogerdudler.github.com/git-guide/index.ko.html

