问题描述
我有一个程序我想写的想法,但语言将是最好的是我的问题。
I had an idea of a program I want to write, but which language would be best is my problem.
如果我有一个赛车游戏,我想允许用户提交code新的交互式3D赛道(想想轨道例如在高速赛车电影中发现的),车辆和他们的自主车,所以,他们将创造人工智能为自己的爱车,使汽车以确定如何处理危害。
If I have a car racing game and I want to allow users to submit code for new interactive 3D race tracks (think of tracks such as found in the Speed Racer movie), vehicles and for their autonomous vehicles, so, they would create the AI for their car that will enable the car to determine how to handle hazards.
所以,我需要将运行快速的语言,作为一个世界地图服务器具有所有可能的种族可供选择,它们的各种状态的一部分。
So, I need a language that will run fast, and as part of a world map that the server has of all the possible races available, and their various states.
我很好奇,如果这将是一个很好的理由来看看在创造一个斯卡拉DSL,例如?
I am curious if this would be a good reason to look at creating a DSL in Scala, for example?
我不希望有重新启动应用程序加载的DLL新或jar文件那么多的编译语言将是一个问题。
I don't want to have to restart an application to load new dlls or jar files so many compiled languages would be a problem.
我打开Linux或Windows,并为语言,最脚本语言,F#,斯卡拉,二郎或大部分OOP我可以编程。
I am open to Linux or Windows, and for the languages, most scripting languages, F#, Scala, Erlang or most OOP I can program in.
用户将能够监控他们的车辆是如何做的,如果他们有上传那辆车多个AI,当它到达一定的障碍,他们应该能够交换输入(AI)计划为另一个需求。
The user will be able to monitor how their vehicle is doing, and if they have more than one AI uploaded for that car, when it gets to certain obstacles they should be able to swap one AI program for another on demand.
更新:到目前为止,解决方案的javascript,使用V8,和Lua。
Update: So far the solutions are javascript, using V8, and Lua.
我很好奇,如果这可能是一个DSL很好用的,实际上是3个独立的。 1,用于创建一个赛马场,另一个用于控制赛车和第三创建新汽车。
I am curious if this may be a good use for a DSL, actually 3 separate ones. 1 for creating a racetrack, another for controlling a racecar and the third for creating new cars.
如果是的话,Haskell中,F#或斯卡拉是这个很好的选择?
If so, would Haskell, F# or Scala be good choices for this?
更新:难道意义有不同的地方用不同的语言结束了?例如,如果二郎被用于汽车和Lua为汽车本身的控制,并且还为动画赛道?
Update: Would it make sense to have different parts end up in different languages? For example, if Erlang was used for the controlling of the car and Lua for the car itself, and also for the animated racetrack?
推荐答案
您的情况听起来像一个很好的候选人的Lua。
Your situation sounds like a good candidate for Lua.
- 您需要的沙盒:这是做。您只需通过重写或删除
os.execute
命令,比如初始化用户的环境,有没有办法让用户再访问该功能。 - 您想快速:检查出一些对的。
- Assumably需要用另一种语言进行互操作。 Lua是很容易的(IMO)在C或C ++中嵌入,至少。我没有用的,但是这是C#绑定。
- lua有一阶的功能,所以它应该是容易掉在即时功能。
- 支持OOP与元表一定程度上。
- Lua的主要数据结构是非常适合稀疏的(关联数组)数据结构就像一个世界地图整合。
- lua有一个很正规的语法。还有用分号或压痕不搞笑招数,所以这是少了一个东西为你的用户去学习,当他们拿起你的语言 - 更不用提,采用了证据充分的语言带走一些你所要做的工作,自己记录它条款。
- You need sandboxing: This is easy to do in Lua. You simply initialize the users' environment by overwriting or deleting the
os.execute
command, for instance, and there is no way for the user to access that function anymore. - You want fast: Check out some of the Lua benchmarks against other languages.
- Assumably you need to interoperate with another language. Lua is very easy (IMO) to embed in C or C++, at least. I haven't used LuaInterface, but that's the C# binding.
- Lua has first-order functions, so it should be easy to swap functions on-the-fly.
- Lua supports OOP to some extent with metatables.
- Lua's primary data structure is the table (associative array) which is well-suited to sparse data structures like integrating with a world map.
- Lua has a very regular syntax. There are no funny tricks with semicolons or indentation, so that's one less thing for your users to learn when they are picking up your language -- not to mention, using a well-documented language takes away some of the work you have to do in terms of documenting it yourself.
此外,如在@elviejo评论指出,Lua是已经用作许多游戏的脚本语言。如果不出意外,肯定是在你所描述的方式使用Lua的一些precedent。而且,@gmonc提到,有一个机会,你的用户已经使用的Lua在另一场比赛。
Also, as @elviejo points out in a comment, Lua is already used as a scripting language in many games. If nothing else, there's certainly some precedent for using Lua in the way you've described. And, as @gmonc mentions, there is a chance that your users have already used Lua in another game.
至于的如何的用Lua的整合:一般来说,你的用户应该只需要上传的Lua脚本文件。要粗暴简单化,可以为用户提供可用的功能,如
TurnLeft
,右拐
,转到
和停止
。然后,用户会上传像As far as how to integrate with Lua: generally, your users should simply need to upload a Lua script file. To grossly oversimplify, you might provide the users with available functions such as
TurnLeft
, TurnRight
, Go
, and Stop
. Then, the users would upload a script likeActions = {} -- empty table, but you might want to provide default functions
function Actions.Cone()
TurnLeft()
end
function Actions.Wall()
Stop()
TurnRight()
TurnRight()
Go()
end
然后服务器端,你就可以使用围棋()
开始他们。然后,当他们的车到达一个锥形,你叫他们的 Actions.Cone()
功能;墙上导致 Actions.Wall()
功能等。在这一点上,你(希望)已沙箱Lua环境,所以你可以简单地执行自己的脚本没有错误检查,甚至很多方面 - 如果他们的脚本导致一个错误,没有任何原因,你不能直接传递错误上给用户。如果存在的不的任何错误, lua_State
在你的服务器的code应该包含他们的汽车的最终状态。
Then server-side, you would might start them off with a Go()
. Then, when their car reaches a cone, you call their Actions.Cone()
function; a wall leads to the Actions.Wall()
function, etc. At this point, you've (hopefully) already sandboxed the Lua environment, so you can simply execute their script without even much regard for error checking -- if their script results in an error, no reason you can't pass the error on directly to the user. And if there aren't any errors, the lua_State
in your server's code should contain the final state of their car.
下面是一个独立的C文件,从标准输入需要一个Lua脚本并运行它就像我上面的解释。本场比赛是你会遇到地面,栅栏,或一个分支,你必须分别跑,跳,或鸭通过。您输入通过标准输入Lua中决定如何反应。来源是有点长,但希望它很容易理解(除Lua的API,这需要习惯一段时间)。这是我的独创,在过去30分钟,希望它可以帮助:
Here's a standalone C file that takes a Lua script from stdin and runs it like I explained above. The game is that you'll encounter Ground, a Fence, or a Branch, and you have to respectively Run, Jump, or Duck to pass. You input a Lua script via stdin to decide how to react. The source is a little long, but hopefully it's easy to understand (besides the Lua API which takes a while to get used to). This is my original creation over the past 30 minutes, hope it helps:
#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;
}
在构建GCC上述与的gcc -o runner.c亚军-llua5.1 -I / usr / include目录/ lua5.1
。
和pretty多少唯一的Lua脚本,将顺利每次传球的是:
And pretty much the only Lua script that will pass successfully every time is:
Actions = {}
function Actions.Ground() Run() end
function Actions.Fence() Jump() end
function Actions.Branch() Duck() end
这也可写为
Actions = {}
Actions.Ground = Run
Actions.Fence = Jump
Actions.Branch = Duck
随着好剧本,你会看到这样的输出:
With the good script, you'll see output like:
Successful duck!
Successful run!
Successful jump!
Successful jump!
Successful duck!
You passed!
如果用户尝试一些恶意程序会简单地提供一个错误:
If the user tries something malicious, the program will simply provide an error:
$ 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))
使用了不正确的举动脚本,用户将看到他执行了错误的举动:
With an incorrect move script, the user will see that he performed the wrong move:
$ echo "Actions = {} Actions.Ground = Jump; Actions.Fence = Duck; Actions.Branch = Run" | ./runner
Wrong move!
You failed!
这篇关于寻找优秀的服务器端语言,将允许玩家上传code可以执行的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!