介绍两个比较好玩的编程语言

  BF语言介绍

  Brainfuck,是一种极小化的计算机语言,这种 语言,是一种按照"Turing complete(完整图灵机)"思想设计的语言,它的主要设计思路是:用最小的概念实现一种"简单"的语言,BrainFuck 语言只有八种符号,所有的操作都由这八种符号的组合来完成。BF基于一个简单的机器模型,除了八个指令,这个机器还包括:一个以字节为单位、被初始化为零的数组、一个指向该数组的指针(初始时指向数组的第一个字节)、以及用于输入输出的两个字节流。

  下面是这八种指令的描述,其中每个指令由一个字符标识:

字符 含义 用C语言表示
> 指针加一 ++ptr;
< 指针减一 --ptr;
+ 指针指向的字节的值加一 ++*ptr;
- 指针指向的字节的值减一 --*ptr;
. 输出指针指向的单元内容(ASCII码) putchar(*ptr);
, 输入内容到指针指向的单元(ASCII码) *ptr =getchar();
[ 如果指针指向的单元值为零,向后跳转到对应的]指令的次一指令处 while (*ptr) {
] 如果指针指向的单元值不为零,向前跳转到对应的[指令的次一指令处 }

  提供一个简单的HelloWord程序

1 ++++++++++[>+++++++>++++++++++>+++>+<<<<-]
2 >++.>+.+++++++..+++.>++.<<+++++++++++++++.
3 >.+++.------.--------.>+.>.

  下面提供一个BF的解析器,用C语言模拟的。

 1 #include <stdio.h>
 2 #include <string.h>
 3 #include <stdlib.h>
 4
 5 int main(int argc,char *argv[])
 6 {
 7     FILE * rfp;
 8     FILE * wfp;
 9     char filename[64];
10     char exec[128];
11     char ch;
12     if(argc!=2)
13     {
14         printf("请输入brainfuck源文件:");
15         scanf("%s",filename);
16     }
17     else
18     {
19         strcpy(filename,argv[1]);
20     }
21     rfp=fopen(filename,"r");
22     strcat(filename,".c");
23     wfp=fopen(filename,"w");
24     if(rfp==NULL || wfp==NULL)
25     {
26         printf("Can‘t open the file!\n");
27         return -1;
28     }
29     fputs("#include <stdio.h>\n#include <string.h>\n int main(int argc,char *argv[])\n{",wfp);
30     fputs("char *ptr; \n char memory_tmp[0xffff];\n",wfp);
31     fputs("memset(memory_tmp,0,sizeof(memory_tmp));\nptr=memory_tmp;\n ",wfp);
32
33     while((ch=fgetc(rfp))!=EOF)
34     {
35         //printf("%c",ch);
36         switch(ch)
37         {
38             case ‘>‘:
39                 fputs("++ptr;\n",wfp);
40                 break;
41             case ‘<‘:
42                 fputs("--ptr;\n",wfp);
43                 break;
44             case ‘+‘:
45                 fputs("++*ptr;\n",wfp);
46                 break;
47             case ‘-‘:
48                 fputs("--*ptr;\n",wfp);
49                 break;
50             case ‘.‘:
51                 fputs("putchar(*ptr);\n",wfp);
52                 break;
53             case ‘,‘:
54                 fputs("*ptr=getchar();\n",wfp);
55                 break;
56             case ‘[‘:
57                 fputs("while(*ptr)\n{\n",wfp);
58                 break;
59             case ‘]‘:
60                 fputs("}\n",wfp);
61                 break;
62             default:
63                 break;
64         }
65     }
66     fputs("\n return 0; \n }",wfp);
67     fclose(rfp);
68     fclose(wfp);
69     memset(exec,0,sizeof(exec));
70     strcpy(exec,"gcc ");
71     strcat(exec,filename);
72     strcat(exec," -o tmp.tmp; rm ");
73     strcat(exec,filename);
74     strcat(exec,"; chmod 777 tmp.tmp;./tmp.tmp ; rm tmp.tmp;");
75     //printf("运行的命令是:%s\n",exec);
76     printf("===============brainfuck运行结果=================\n");
77     system(exec);
78     printf("=================================================\n");
79     return 0;
80 }

  下面对那个Hello World进行解释

 1 +++ +++ +++ +           initialize counter (cell #0) to 10
 2 [                       use loop to set the next four cells to 70/100/30/10
 3     > +++ +++ +             add  7 to cell #1
 4     > +++ +++ +++ +         add 10 to cell #2
 5     > +++                   add  3 to cell #3
 6     > +                     add  1 to cell #4
 7     <<< < -                 decrement counter (cell #0)
 8 ]
 9 >++ .                   print ‘H‘
10 >+.                     print ‘e‘
11 +++ +++ +.              print ‘l‘
12 .                       print ‘l‘
13 +++ .                   print ‘o‘
14 >++ .                   print ‘ ‘
15 <<+ +++ +++ +++ +++ ++. print ‘W‘
16 >.                      print ‘o‘
17 +++ .                   print ‘r‘
18 --- --- .               print ‘l‘
19 --- --- --.             print ‘d‘
20 >+.                     print ‘!‘
21 >.                      print ‘\n‘

  下面提供一个小程序用于把玩

++++++++++[>+>++>+++>++++>+++++>++++++>+++++++>++++++++>+++++++++>++++++++++>+++++++++++>++++++++++++>+++++++++++++<<<<<<<<<<<<<-]>>>>>>>>>>++++.---->>----..++++<++.--<<<<<--.++<---.+++>>>>>>>-...+<<<<<<<----.++++>>>>>-.+>.<--.++>--.+++.-<+++.--->+++++.-----<<<<<<----.++++>>>>>-.+>+.--.+<<<<<<---.+++>>>>>>>-.+---.+++<.<---.+++>+.->++.--<<---.++++++++.-----<<<<<<<<<.+++.---

  Piet语言

  Piet 是一种非常深奥的编程语言,使用颜色编写代码。由David Morgan-Mar,其方案是位图,看起来像抽象艺术设计。编译指导图像周围移动,从一个连续颜色的区域下的一个“指针”。通过一个地区的指针退出时的程序进行。

  由于原本的Piet语法比较复杂,我对其修改如下,使其比较简单和容易实现。

编号 指令 含义 颜色Red 颜色Green 颜色Blue
1 start 表示一个代码段的开始 0 0 0
2 end 表示一个代码段的结束 2 2 2
3 ++(plusplus) 将寄存器中的数加1 0 0 1
4 --(minusminus) 将寄存器中的数减1 0 0 2
5 push 将寄存器中的数写入栈中 0 1 1
6 pop 将栈中的数读弹出并不存入寄存器中 0 1 2
7 in 控制台输入一个字符到寄存器 0 2 1
8 out 将寄存器的字符打印到控制台 0 2 2
9 turn
栈顶元素与寄存器比较,如果相等则代码方向指针向前

如果大于则代码方向指针向左,如果小于则代码方向指针向右

1 0 1
10 zero 将寄存器中的数置零 1 0 0
11 call 跳转指令,以寄存器为x,以栈顶数为y,跳到图像的(x,y)位置开始执行 1 1 1
12 add 栈顶元素与寄存器相加,并保存在寄存器中 2 0 0
13 sub 栈顶元素减去寄存器,差保存在寄存器中 2 0 1
14 mul 栈顶元素与寄存器相乘,并保存在寄存器中 2 1 0
15 div 栈顶元素除以寄存器,商保存在寄存器中 2 1 1

  这个语言包含一个栈,还有一个寄存器,包含IO操作。十五个颜色的对应如下

  我给出的程序是使用PPM格式的图片,彩色255颜色,以左上角为(0,0)右下角(sx,xy).

  下面这个是用于编译的代码

  1 #include <stdio.h>
  2 #include <stdlib.h>
  3 #include <string.h>
  4
  5 #define START       1
  6 #define END         2
  7 #define PLUSPLUS    3
  8 #define MINUSMINUS  4
  9 #define PUSH        5
 10 #define POP         6
 11 #define IN          7
 12 #define OUT         8
 13 #define TURN        9
 14 #define ZERO        10
 15 #define CALL        11
 16 #define ADD         12
 17 #define SUB         13
 18 #define MUL         14
 19 #define DIV         15
 20
 21 struct IMG
 22 {
 23     int channel;
 24     int sx,sy;
 25     int maxv;
 26     unsigned char * img;
 27 };
 28
 29 int ReadPPM(char * fname,struct IMG * img)
 30 {
 31     FILE * fp=NULL;
 32     char ch;
 33     fp=fopen(fname,"rb");
 34     if(fp==NULL)
 35     {
 36         perror("Can‘t open the file");
 37         exit(-1);
 38     }
 39     fscanf(fp,"%c%d%d%d%d%*c",&ch,&img->channel,&img->sx,&img->sy,&img->maxv);
 40     if(img->channel==6)
 41     {
 42         img->img=(unsigned char *)malloc(img->sx*img->sy*3);
 43         if(img->img==NULL)
 44         {
 45             perror("Can‘t malloc memory");
 46             exit(-1);
 47         }
 48         fread(img->img,img->sx*img->sy*3,1,fp);
 49     }
 50     fclose(fp);
 51     return 0;
 52 }
 53
 54 struct Dir
 55 {
 56     int x;
 57     int y;
 58 };
 59
 60 int to3(int a)
 61 {
 62     if(a<=50)
 63         return 0;
 64     if(a>50&&a<150)
 65         return 1;
 66     if(a>=200)
 67         return 2;
 68     perror("图片格式模糊不便执行");
 69 }
 70
 71 int toinc(int r,int g,int b)
 72 {
 73     int i;
 74     if(to3(r)==0 && to3(g)==0 &&to3(b)==0)
 75         return START;
 76     if(to3(r)==2 && to3(g)==2 &&to3(b)==2)
 77         return END;
 78
 79     if(to3(r)==0 && to3(g)==0 &&to3(b)==1)
 80         return PLUSPLUS;
 81     if(to3(r)==0 && to3(g)==0 &&to3(b)==2)
 82         return MINUSMINUS;
 83
 84     if(to3(r)==0 && to3(g)==1 &&to3(b)==1)
 85         return PUSH;
 86     if(to3(r)==0 && to3(g)==1 &&to3(b)==2)
 87         return POP;
 88
 89     if(to3(r)==0 && to3(g)==2 &&to3(b)==1)
 90         return IN;
 91     if(to3(r)==0 && to3(g)==2 &&to3(b)==2)
 92         return OUT;
 93
 94     if(to3(r)==1 && to3(g)==0 &&to3(b)==1)
 95         return TURN;
 96     if(to3(r)==1 && to3(g)==0 &&to3(b)==0)
 97         return ZERO;
 98     if(to3(r)==1 && to3(g)==1 &&to3(b)==1)
 99         return CALL;
100
101     if(to3(r)==2 && to3(g)==0 &&to3(b)==0)
102         return ADD;
103     if(to3(r)==2 && to3(g)==0 &&to3(b)==1)
104         return SUB;
105     if(to3(r)==2 && to3(g)==1 &&to3(b)==0)
106         return MUL;
107     if(to3(r)==2 && to3(g)==1 &&to3(b)==1)
108         return DIV;
109 }
110
111 int decode(struct IMG * img)
112 {
113     struct Dir dir;//代码方向向量
114     struct Dir now;//表示当前代码指针
115     int stack[1024];
116     char ch;
117     int inc;//保存指令
118     int ptr;//栈指针
119     int reg;//这个是寄存器
120     int tmp;
121     memset(stack,0,sizeof(stack));
122     ptr=0;reg=0;
123     dir.x=1;
124     dir.y=0;//表示向前
125     now.x=0;
126     now.y=0;
127     inc=toinc(img->img[0],img->img[1],img->img[2]);
128     while(1)
129     {
130         tmp=now.y*img->sx*3+now.x*3;
131         inc=toinc(img->img[tmp],img->img[tmp+1],img->img[tmp+2]);
132         //printf("%d x=%d y=%d\n",inc,now.x,now.y);
133         //printf("此时reg=%d stack=%d\n",reg,stack[ptr-1]);
134         //getchar();
135         switch(inc)
136         {
137             case START:
138                 {
139                     break;
140                 }
141             case END:
142                 {
143                     return 0;
144                 }
145             case PLUSPLUS:
146                 {
147                     reg++;
148                     break;
149                 }
150             case MINUSMINUS:
151                 {
152                     reg--;
153                     break;
154                 }
155             case PUSH:
156                 {
157                     stack[ptr]=reg;
158                     ptr++;
159                     break;
160                 }
161             case POP:
162                 {
163                     ptr--;
164                     break;
165                 }
166             case IN:
167                 {
168                     fflush(stdin);
169                     ch=getchar();
170                     reg=ch;
171                     break;
172                 }
173             case OUT:
174                 {
175                     printf("%c",reg);
176                     break;
177                 }
178             case TURN:
179                 {
180                     if(stack[ptr-1]>reg)//左转
181                     {
182                         //printf("左转\n");
183                         if(dir.x==1&&dir.y==0)//东
184                         {
185                             dir.x=0;dir.y=-1;
186                         }
187                         else if(dir.x==-1&&dir.y==0)//西
188                         {
189                             dir.x=0;dir.y=1;
190                         }
191                         else if(dir.x==0&&dir.y==1)//南
192                         {
193                             dir.x=1;dir.y=0;
194                         }
195                         else if(dir.x==0&&dir.y==-1)//北
196                         {
197                             dir.x=-1;dir.y=0;
198                         }
199                     }
200                     else if(stack[ptr-1]<reg)//右转
201                     {
202                         //printf("右转\n");
203                         if(dir.x==1&&dir.y==0)//东
204                         {
205                             dir.x=0;dir.y=1;
206                         }
207                         else if(dir.x==-1&&dir.y==0)//西
208                         {
209                             dir.x=0;dir.y=-1;
210                         }
211                         else if(dir.x==0&&dir.y==1)//南
212                         {
213                             dir.x=-1;dir.y=0;
214                         }
215                         else if(dir.x==0&&dir.y==-1)//北
216                         {
217                             dir.x=1;dir.y=0;
218                         }
219                     }
220                     else
221                     {
222                         ;//不变
223                     }
224                     break;
225                 }
226             case ZERO:
227                 {
228                     reg=0;
229                     break;
230                 }
231             case CALL:
232                 {
233                     now.x=reg;
234                     now.y=stack[ptr-1];
235                     continue;
236                     break;
237                 }
238             case ADD:
239                 {
240                     reg=reg+stack[ptr-1];
241                     break;
242                 }
243             case SUB:
244                 {
245                     reg=stack[ptr-1]-reg;
246                     break;
247                 }
248             case MUL:
249                 {
250                     reg=reg*stack[ptr-1];
251                     break;
252                 }
253             case DIV:
254                 {
255                     reg=stack[ptr-1]/reg;
256                     break;
257                 }
258         }
259         now.x=now.x+dir.x;
260         now.y=now.y+dir.y;
261     }
262
263     return 0;
264 }
265
266 int main(int argc,char *argv[])
267 {
268     int i,j;
269     struct IMG image;
270     struct IMG *pimg=&image;
271     char filename[64];
272     if(argc!=2)
273     {
274         printf("请输入要编译的文件:");
275         scanf("%s",filename);
276     }
277     else
278     {
279         strcpy(filename,argv[1]);
280     }
281     ReadPPM(filename,pimg);
282     decode(pimg);
283     return 0;
284 }

  运行这个程序: ./ppm file.ppm

  例如下面这个图片将会输出"He"这两个字符,本来是要输出Helloworld的,但是发现画起来有点麻烦,所以就没有画了。

  

  上面的指令表示如下:

  start;++;++;push;mul;mul;mul;mul;mul;
  push;zero;++;++;push;++turn;--;
  mul;mul;pop;add;out;++;turn;--;
  push;zero;++;++;push;mul;mul;
  mul;mul;pop;add;--;--;--;out;end;

  看起来很神奇的样子呢!画了几个图,下面有点小经验,(如果有人真的去画的话。)关于转弯的问题,转弯是紫色,要让当前是左转还是右转,就取决于前一个颜色块是++块还是--块,然后为了恢复,后面就接着用--块或++块,这就实现转弯了。如果有强迫症的想每一行都用上像个已字一样那么就只需同时使用两个转弯就可以了。注意两次右转就实现向后了,而且还是只隔一行。好方便的说。

  如果有兴趣还可以根据指令生成一张ppm的图片呢,然后再用程序去执行它。

  参考资料: http://coolshell.cn/articles/1142.html

        http://www.dangermouse.net/esoteric/piet/samples.html

  本文地址: http://www.cnblogs.com/wunaozai/p/3888481.html

  用到的程序和图片: http://files.cnblogs.com/wunaozai/BF%26Piet.zip

介绍两个比较好玩的编程语言,布布扣,bubuko.com

时间: 2024-10-29 00:10:14

介绍两个比较好玩的编程语言的相关文章

介绍两个JQuery插件 — 滚动和轮播

1.滚动组件. 有时候需要在网页中的各个部分跳转,类似于回到首页的功能,给点动画当然是极好的.JQuery插件AnimateScroll就是解决这个问题的. 使用方法类似这样: $('#use').animatescroll({scrollSpeed:1500, easing:'easeOutCubic'}); //跳转到#use处 更多方法请访问项目主页. 2.轮播组件 这款轮播组件同样基于JQuery,可以用来做个牛逼哄哄的3D相册神马的. demo地址:http://tympanus.ne

介绍两个Eclipse插件: Implementors &amp; Call Hierarchy

介绍两个Eclipse插件: Implementors & Call Hierarchy 本文介绍两个在Eclipse调试与跟踪过程中的两个实用插件 他们都可以在 http://eclipse-tools.sourceforge.net/ ?下载 该网址还包含了另外两个项目,以及一份Eclipse的 reference card. ------------------------------------------------------------------ 一: Implementors

【推荐】介绍两款Windows资源管理器,Q-Dir 与 FreeCommander XE(比TotalCommander更易用的免费资源管理器)

你是否也像我一样,随着硬盘.文件数量的增加,而感到对于文件的管理越来越乏力. 于是我试用了传说中的各种软件,包括各种Explorer外壳,或者第三方资源管理器. 最后我确定下来经常使用,并推荐给您的是这两款软件:FreeCommander XE.Q-Dir. ============================= 我为什么推荐FreeCommander 和 Q-Dir? 因为 TotalCommander 太难学,Clover 太低端. Q-Dir 是一款简单的四格窗体的资源管理器,可以同时

给大家介绍两款超级牛逼的算法!SVM &#183; SMO算法!和牛逼也很难 !

KKT 条件 先来看如何选取参数.在 SMO 算法中,我们是依次选取参数的: 选出违反 KKT 条件最严重的样本点.以其对应的参数作为第一个参数第二个参数的选取有一种比较繁复且高效的方法,但对于一个朴素的实现而言.第二个参数即使随机选取也无不可 可以以一张图来直观理解这里提到的诸多概念: (画得有点乱,见谅--) 图中外面有个黑圆圈的其实就是传说中的"支持向量",其定义会在文末给出 那么我们到底应该如何刻画"违反 KKT 条件"这么个东西呢?从直观上来说,我们可以有

简单介绍两个JSP中隐含对象

一.config 对象 config 对象里存放着一些Servlet 初始的数据结构. config 对象实现于javax.servlet.ServletConfig 接口,它共有下列四种方法: public String getInitParameter(name) public java.util.Enumeration getInitParameterNames( ) public ServletContext getServletContext( ) public Sring getSe

介绍两个Ubuntu上的桌面小工具

经常使用Windows10,Sticky Notes和壁纸自动切换功能挺好用的.我经常会使用Sticky Notes来记录一些信息,内容是实时保存的,而且启动的时候会自动显示在桌面上.其实Ubuntu上也有类似的一些小工具. 1. Variety Variety可以在Ubuntu上实现桌面壁纸的自动轮播,壁纸定期更换,以及一些特效等.官方站点:http://peterlevi.com/variety/.通过以下命令进行安装: sudo add-apt-repository ppa:peterle

介绍两款让人忍不住一口气通关的平板or手机游戏

limbo <地狱边境> 代入感极强的游戏,画面超棒,设计很合理. <纪念碑谷> 视觉享受,配音也很好

Git简单介绍两种拉取代码的方式

first: 1.通过git clone 命令克隆git库中的项目 具体操作命令: //克隆git库中的代码,后面的https地址换成自己的git库地址就好,注意:不要使用ssh git clone https://gitee.com/yulongcode/TestGit.git //查看本地git库的文件修改状态 git status //将本地修改的代码提交到暂存区 ./ 也可以换成具体的文件名 git add ./ //给将要提交的代码写注释 git commit -m '代码提交注释'

亲密数编程语言旋风式的介绍

为什么要学编程 你好世界 算数运算 操作和查看栈 获取帮助 数据类型 控制语句 重复 分支 循环 定义关键字 画图 坐标系 基本的画图命令 鳖图 结束语 为什么要学编程 这里我要引用一段文字. "人类学语言时,学的不仅是听还有说:学字时,学的不仅是读还有写:而现在随着我们向一个越来越数字化的世界迈进,我们也不仅应该学会如何使用程序,还要学会如何开发程序.在未来,面对着一个高度程序化的世界,如果你不能开发软件,那么你将变成软件.就是这么简单:要么编程,要么被编程(Program or Be Pro