我对我想要编写的程序有所了解,但哪种语言最好是我的问题.
如果我有一个赛车游戏,我想让用户提交新的交互式3D赛道(想想Speed Racer电影中的曲目),车辆和自动驾驶汽车的代码,那么,他们会创建AI他们的汽车将使汽车能够确定如何处理危险.
所以,我需要一种能够快速运行的语言,并且作为服务器具有所有可用种族的世界地图的一部分,以及它们的各种状态.
我很好奇,例如,这是否是在Scala中创建DSL的一个很好的理由?
我不想重新启动一个应用程序来加载新的dll或jar文件这么多编译语言会有问题.
我对Linux或Windows开放,对于语言,大多数脚本语言,F#,Scala,Erlang或大多数OOP我可以编程.
用户将能够监控他们的车辆如何运行,并且如果他们为该车辆上载了多个AI,当遇到某些障碍时,他们应该能够根据需要将一个AI程序换成另一个AI程序.
更新:到目前为止,解决方案是javascript,使用V8和Lua.
我很好奇这是否适用于DSL,实际上是3个独立的DSL.1用于创建赛道,另一个用于控制赛车,第三个用于创建新车.
如果是这样,那么Haskell,F#或Scala会是一个很好的选择吗?
更新:让不同的部分以不同的语言结束是否有意义?例如,如果Erlang用于控制汽车,Lua用于汽车本身,还用于动画赛道?
Mar*_*off 32
你的情况听起来像是Lua的一个很好的候选人.
os.execute命令来初始化用户的环境,用户就无法再访问该功能.另外,正如@elviejo在评论中指出的那样,Lua已经在许多游戏中被用作脚本语言.如果不出意外,以你所描述的方式使用Lua肯定有一些先例.并且,正如@gmonc所提到的,您的用户可能已经在另一个游戏中使用过Lua.
TurnLeft,TurnRight,Go,和Stop.然后,用户将上传类似的脚本
Actions = {} -- empty table, but you might want to provide default functions
function Actions.Cone()
TurnLeft()
end
function Actions.Wall()
Stop()
TurnRight()
TurnRight()
Go()
end
Run Code Online (Sandbox Code Playgroud)
然后服务器端,你可能会用a启动它们Go().然后,当他们的汽车到达一个圆锥体时,你会调用它们的Actions.Cone()功能; 墙壁通向Actions.Wall()功能等.此时,您(希望)已经沙箱化了Lua环境,因此您可以简单地执行其脚本而不必过多考虑错误检查 - 如果它们的脚本导致错误,则不您无法直接将错误传递给用户的原因.如果没有任何错误,lua_State服务器代码中的代码应包含其汽车的最终状态.
这是一个独立的C文件,它从stdin获取Lua脚本并像我上面解释的那样运行它.游戏是你会遇到地面,栅栏或树枝,你必须分别跑,跳或鸭子通过.您通过stdin输入Lua脚本来决定如何做出反应.源代码有点长,但希望它很容易理解(除了需要一段时间才能习惯的Lua API).这是我过去30分钟的原创作品,希望它有所帮助:
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include "lua.h"
#include "lauxlib.h"
#include "lualib.h"
#define FAIL 0
#define SUCCESS 1
/* Possible states for the player */
enum STATE {
RUNNING,
JUMPING,
DUCKING
};
/* Possible obstacles */
enum OBSTACLE {
GROUND,
FENCE,
BRANCH
};
/* Using global vars here for brevity */
enum STATE playerstate = RUNNING;
enum OBSTACLE currentobstacle = GROUND;
/* Functions to be bound to Lua */
int Duck(lua_State *L)
{
playerstate = DUCKING;
return 0; /* no return values to Lua */
}
int Run(lua_State *L)
{
playerstate = RUNNING;
return 0;
}
int Jump(lua_State *L)
{
playerstate = JUMPING;
return 0;
}
/* Check if player can pass obstacle, offer feedback */
int CanPassObstacle()
{
if ( (playerstate == RUNNING && currentobstacle == GROUND) )
{
printf("Successful run!\n");
return SUCCESS;
}
if (playerstate == JUMPING && currentobstacle == FENCE)
{
printf("Successful jump!\n");
return SUCCESS;
}
if (playerstate == DUCKING && currentobstacle == BRANCH)
{
printf("Successful duck!\n");
return SUCCESS;
}
printf("Wrong move!\n");
return FAIL;
}
/* Pick a random obstacle */
enum OBSTACLE GetNewObstacle()
{
int i = rand() % 3;
if (i == 0) { return GROUND; }
if (i == 1) { return FENCE; }
else { return BRANCH; }
}
/* Execute appropriate function defined in Lua for the next obstacle */
int HandleObstacle(lua_State *L)
{
/* Get the table named Actions */
lua_getglobal(L, "Actions");
if (!lua_istable(L, -1)) {return FAIL;}
currentobstacle = GetNewObstacle();
/* Decide which user function to call */
if (currentobstacle == GROUND)
{
lua_getfield(L, -1, "Ground");
}
else if (currentobstacle == FENCE)
{
lua_getfield(L, -1, "Fence");
}
else if (currentobstacle == BRANCH)
{
lua_getfield(L, -1, "Branch");
}
if (lua_isfunction(L, -1))
{
lua_call(L, 0, 0); /* 0 args, 0 results */
return CanPassObstacle();
}
return FAIL;
}
int main()
{
int i, res;
srand(time(NULL));
lua_State *L = lua_open();
/* Bind the C functions to Lua functions */
lua_pushcfunction(L, &Duck);
lua_setglobal(L, "Duck");
lua_pushcfunction(L, &Run);
lua_setglobal(L, "Run");
lua_pushcfunction(L, &Jump);
lua_setglobal(L, "Jump");
/* execute script from stdin */
res = luaL_dofile(L, NULL);
if (res)
{
printf("Lua script error: %s\n", lua_tostring(L, -1));
return 1;
}
for (i = 0 ; i < 5 ; i++)
{
if (HandleObstacle(L) == FAIL)
{
printf("You failed!\n");
return 0;
}
}
printf("You passed!\n");
return 0;
}
Run Code Online (Sandbox Code Playgroud)
用GCC构建上面的GCC gcc runner.c -o runner -llua5.1 -I/usr/include/lua5.1.
几乎每次成功通过的唯一Lua脚本是:
Actions = {}
function Actions.Ground() Run() end
function Actions.Fence() Jump() end
function Actions.Branch() Duck() end
Run Code Online (Sandbox Code Playgroud)
也可以写成
Actions = {}
Actions.Ground = Run
Actions.Fence = Jump
Actions.Branch = Duck
Run Code Online (Sandbox Code Playgroud)
使用好的脚本,您将看到如下输出:
Successful duck! Successful run! Successful jump! Successful jump! Successful duck! You passed!
如果用户尝试恶意攻击,程序将只提供错误:
$ echo "Actions = {} function Actions.Ground() os.execute('rm -rf /') end" | ./runner
PANIC: unprotected error in call to Lua API (stdin:1: attempt to index global 'os' (a nil value))
使用不正确的移动脚本,用户将看到他执行了错误的移动:
$ echo "Actions = {} Actions.Ground = Jump; Actions.Fence = Duck; Actions.Branch = Run" | ./runner
Wrong move!
You failed!