Tuesday, January 11, 2022

教小朋友用Python编Minecraft server插件

前面在教小朋友编程之坦克大战 1提到David Whale, Martin O'Hanlon写的《Adventures in Minecraft》,我觉得有必要提供一些细节,特别是对喜欢玩Minecraft的小朋友,根据作者的讲述,他们在学校的实验很成功,有的学生开发出不错的程序。

这本书的官网是https://www.wiley.com/en-us/Adventures+in+Minecraft-p-9781118946916,


Amazon等也都有卖。

网上可以很容易找到这本书的电子版,我不确定是否有版权问题,所以不会在这里列出link招惹不必要的麻烦。开发的Python程序是要运行在Minecraft server端。为此,需要到https://adventuresinminecraft.github.io 下载Minecraft Starter Kits。这个github repo提供了Windows、MacOS和Raspberry Pi的Start Kit, for Minecraft 1.12, 虽然不是最新版Minecraft,不过不影响趣味性。这个网站还提供如何自己创建定制的Start Kits,当然也提供了书中全部程序的下载。

网上可以找到很多的学习Python的资料,如Python Crash Course。https://www.pdfdrive.com/python-crash-course-a-hands-on-project-based-introduction-to-programming-e190067998.html提供很多ebook下载。

https://github.com/everestwitman/Pygame-Checkers/blob/master/checkers.py是一个checker board game程序,只有一个500行的Python code(算上注释空行)外加一个board的bmp file,简单易懂。

Sunday, January 2, 2022

奇妙code

 十几年前一guru同事在离职email里分享了一个99瓶啤酒的perl程序,target是打印:

99 bottles of beer on the wall, 99 bottles of beer.
Take one down and pass it around, 98 bottles of beer on the wall.

98 bottles of beer on the wall, 98 bottles of beer.
Take one down and pass it around, 97 bottles of beer on the wall.

....

2 bottles of beer on the wall, 2 bottles of beer.
Take one down and pass it around, 1 bottle of beer on the wall.

1 bottle of beer on the wall, 1 bottle of beer.
Go to the store and buy some more, 99 bottles of beer on the wall.

那时我还没听说过Google。最近一查,发现有专门的网站:http://99-bottles-of-beer.net

比如Perl code: http://99-bottles-of-beer.net/download/658

$a=
        "cpuu
       \bmft p
       \bg cff
       \bs";$b
       ="po ui
       \bf xbm
      \bm";$c="
      Ypv ublf p
     \bof epxo qb
   \btt ju bspvoe";
  $a =~ s/\n//;$a =~
  s/\s+/ /g; $b   =~
  s/\n// ;  $b    =~
  s/\s+/ /g;$c    =~
  s/\n// ;  $c    =~
  s/\s+/ /g;$a    =~
  y/b-z/a-z/;$b   =~
  tr/b-z/a-z/;$c  =~
  tr/b-z/a-z/ ; for(
  $d=100;$d>0;$d--){
  print"$d $a $b $d"
  ;print" $a,\n$c, "
  ;print($d-1);print
  " $a $b.\n";} $x =
  "cjc"; $y="dobbz";
  $z="com";print"\n"
  ;print "- $x\@$y."
   ;print"$z \n\n";

 http://99-bottles-of-beer.net/download/737 (可能需要旧Perl比如5.19之前的,不然会得到错误:Eval-group not allowed at runtime, use re 'eval' in regex):

    ''=~(        '(?{'        .('`'        |'%')        .('['        ^'-')
    .('`'        |'!')        .('`'        |',')        .'"'.        '\\$'
    .'=='        .('['        ^'+')        .('`'        |'/')        .('['
    ^'+')        .'||'        .(';'        &'=')        .(';'        &'=')
    .';-'        .'-'.        '\\$'        .'=;'        .('['        ^'(')
    .('['        ^'.')        .('`'        |'"')        .('!'        ^'+')
   .'_\\{'      .'(\\$'      .';=('.      '\\$=|'      ."\|".(      '`'^'.'
  ).(('`')|    '/').').'    .'\\"'.+(    '{'^'[').    ('`'|'"')    .('`'|'/'
 ).('['^'/')  .('['^'/').  ('`'|',').(  '`'|('%')).  '\\".\\"'.(  '['^('(')).
 '\\"'.('['^  '#').'!!--'  .'\\$=.\\"'  .('{'^'[').  ('`'|'/').(  '`'|"\&").(
 '{'^"\[").(  '`'|"\"").(  '`'|"\%").(  '`'|"\%").(  '['^(')')).  '\\").\\"'.
 ('{'^'[').(  '`'|"\/").(  '`'|"\.").(  '{'^"\[").(  '['^"\/").(  '`'|"\(").(
 '`'|"\%").(  '{'^"\[").(  '['^"\,").(  '`'|"\!").(  '`'|"\,").(  '`'|(',')).
 '\\"\\}'.+(  '['^"\+").(  '['^"\)").(  '`'|"\)").(  '`'|"\.").(  '['^('/')).
 '+_,\\",'.(  '{'^('[')).  ('\\$;!').(  '!'^"\+").(  '{'^"\/").(  '`'|"\!").(
 '`'|"\+").(  '`'|"\%").(  '{'^"\[").(  '`'|"\/").(  '`'|"\.").(  '`'|"\%").(
 '{'^"\[").(  '`'|"\$").(  '`'|"\/").(  '['^"\,").(  '`'|('.')).  ','.(('{')^
 '[').("\["^  '+').("\`"|  '!').("\["^  '(').("\["^  '(').("\{"^  '[').("\`"|
 ')').("\["^  '/').("\{"^  '[').("\`"|  '!').("\["^  ')').("\`"|  '/').("\["^
 '.').("\`"|  '.').("\`"|  '$')."\,".(  '!'^('+')).  '\\",_,\\"'  .'!'.("\!"^
 '+').("\!"^  '+').'\\"'.  ('['^',').(  '`'|"\(").(  '`'|"\)").(  '`'|"\,").(
 '`'|('%')).  '++\\$="})'  );$:=('.')^  '~';$~='@'|  '(';$^=')'^  '[';$/='`';

有意思的是这个程序可能是用Acme::EyeDrops从一个简单的Perl程序转换来的:

use Acme::EyeDrops qw(sightly get_eye_string hjoin_shapes);
my $ninety_nine = <<'BURP';
$==pop||99;--$=;sub
_{($;=($=||No)." bottle"."s"x!!--$=." of beer")." on the wall"}
print+_,", $;!
Take one down, pass it around,
",_,"!

"while++$=
BURP
chop($ninety_nine); $ninety_nine =~ s/\nprint/print/;
print sightly( { Regex         => 1,
                 Compact       => 1,
                 ShapeString   => hjoin_shapes(2,
                                  (get_eye_string('bottle2'))x6),
                  SourceString  => $ninety_nine } );

 关于99个啤酒瓶编程的相关网站很多,如:

https://codegolf.stackexchange.com/questions/2/99-bottles-of-beer

https://titanwolf.org/Network/Articles/Article?AID=01592803-8636-4fcd-ac1a-3cc92050a741

之所以想起旧事,是因为最近看了Dylan Beattie的<<The Art of Code>>

里面提到Oscar Toledo G. 2010年用1kB Javascript实现的mini chess:

<html>
<head>
<title>1K Javascript Tiny Chess by &Oacute;scar Toledo G. &copy;2010</title>
</head>
<body>
<script>
for(B=i=y=u=b=i=5-5,x=10,I=[],l=[];B++<304;I[B-1]=B%x?B/x%x<2|B%x<2?7:B/x&4?0:l[i++]="ECDFBDCEAAAAAAAAIIIIIIIIMKLNJLKM@G@TSb~?A6J57IKJT576,+-48HLSUmgukgg OJNMLK  IDHGFE".charCodeAt(y++)-64:7);function X(c,h,e,s){c^=8;for(var o,S,C,A,R,T,G,d=e&&X(c,0)>1e4,n,N=-1e8,O=20,K=78-h<<9;++O<99;)if((o=I[T=O])&&(G=o^c)<7){A=G--&2?8:4;C=o-9?l[61+G]:49;do if(!(R=I[T+=l[C]])&&!!G|A<3||(R+1^c)>9&&G|A>2){if(!(R-2&7))return K;n=G|(c?T>29:T<91)?o:6^c;S=(R&&l[R&7|32]*2-h-G)+(n-o?110:!G&&(A<2)+1);if(e>h||1<e&e==h&&S>2|d){I[T]=n;I[O]=0;S-=X(c,h+1,e,S-N);if(!(h||e-1|B-O|T-b|S<-1e4))return W(),c&&setTimeout("X(8,0,2),X(8,0,1)",75);I[O]=o;I[T]=R}if(S>N||!h&S==N&&Math.random()<.5)if(N=S,e>1)if(h?s-S<0:(B=O,b=T,0))break}while(!R&G>2||(T=O,(G||A>2|(c?O>78:O<41)&!R)&&++C*--A))}return-K+768<N|d&&N}function W(){i="<table>";for(u=18;u<99;document.body.innerHTML=i+=++u%x-9?"<th width=60 height=60 onclick='I[b="+u+"]>8?W():X(0,0,1)'style='font-size:50px'bgcolor=#"+(u-B?u*.9&1||9:"d")+"0f0e0>&#"+(I[u]?9808+l[67+I[u]]:160):u++&&"<tr>")B=b}W()
</script>
</body>
</html>
用任何网页浏览器打开它就会发现它是一个完全可运行的国际象棋游戏。Oscar Toledo G还做了好几个不同版本的c/java类似程序,参见:https://nanochess.org/chess.html
Dylan Beattie在<<The Art of Code>>中提到另一个Flappy Bird code:

                  #define P(a,b,c) a##b##c
                #include/*++**++*/<curses.h>
              int         c,h,            v,x,y,s,                i,b; int
            main            () {            initscr(              ); P(cb,
          rea,                k)()                ;///
        P(n,                  oec,                ho)(
       )/*     */             ;for            (curs_set(0); s=        x=COLS/2
      ; P(    flu,            shi,          np)()){ timeout(y=c=      v=0);///
      P(c,    lea,            r)()          ;for              (P (
      mva,     d,             dstr        )(2,                3+x,
      G) ;                  ; P(        usl,                  eep,    )(U)){//
       P(m,               vad,         dstr                   )( y    >>8,x,//
    "    "); for(i=LINES; /*           */ i                   -->0
  ; mvinsch(i,0,0>(~c|i-h-H             &h-i                  )?' '
:(i-                      h|h-            i+H)            <0?'|'      :'=' ));
if((                       i=( y            +=v=        getch(        )>0?I:v+
  A)>>8)>=LINES||mvinch(i*=   0<i,            x)!=' '||' '
  !=mvinch(i,3+x))break/*&%   &*/;              mvaddstr(y
    >>8,                   x,0>v                      ?F:B        ); i=--s
    /-W;                  P(m,                        vpr,        intw)(0,
     COLS-9," %u/%u ",(0<i)*                  i,b=b<i?i:
      b); refresh(); if(++                    c==D){ c
                        -=W; h=rand()%(LINES-H-6
                          )+2; } } flash(); }}

是个完全可编译可运行的Flappy bird程序(depends on libcurses-devel, 需要下载makefile, 里边定义了游戏参数)。实际上,上面的程序是The International Obfuscated C Code Contest比赛2015年的优胜者之一。从1984年到2020年已经举办27届,优胜程序列在这里:https://www.ioccc.org/years-spoiler.html,其中的每一个程序都一定会让每个C程序员惊叹不已。上面提到的Oscar Toledo G.也有5个程序获奖。

下面的是Youtube video关于Andy Sloane的Donut-shaped C code生成3D spinning donuts

  

Andy的C code source:

             k;double sin()
         ,cos();main(){float A=
       0,B=0,i,j,z[1760];char b[
     1760];printf("\x1b[2J");for(;;
  ){memset(b,32,1760);memset(z,0,7040)
  ;for(j=0;6.28>j;j+=0.07)for(i=0;6.28
 >i;i+=0.02){float c=sin(i),d=cos(j),e=
 sin(A),f=sin(j),g=cos(A),h=d+2,D=1/(c*
 h*e+f*g+5),l=cos      (i),m=cos(B),n=s\
in(B),t=c*h*g-f*        e;int x=40+30*D*
(l*h*m-t*n),y=            12+15*D*(l*h*n
+t*m),o=x+80*y,          N=8*((f*e-c*d*g
 )*m-c*d*e-f*g-l        *d*n);if(22>y&&
 y>0&&x>0&&80>x&&D>z[o]){z[o]=D;;;b[o]=
 ".,-~:;=!*#$@"[N>0?N:0];}}/*#****!!-*/
  printf("\x1b[H");for(k=0;1761>k;k++)
   putchar(k%80?b[k]:10);A+=0.04;B+=
     0.02;}}/*****####*******!!=;:~
       ~::==!!!**********!!!==::-
         .,~~;;;========;;;:~-.
             ..,--------,*/

 编译:

gcc -o donut donut.c -lm

Updated on Oct 11, 2023: Just saw a Wolfenstein implementation with 600 line Gawk code, a 3D game in Text mode, though will feel dizzy when playing. Reference: https://hackaday.com/2016/01/15/wolfenstein-in-600-lines-of-code/:

sudo apt-get install gawk
git clone https://github.com/TheMozg/awk-raycaster.git
cd awk-raycaster/
gawk -f awkaster.awk

Friday, December 31, 2021

用开源GIMP编辑GIF动图

 新年到,微信同学群大家发了一堆video和GIF动图,我不甘落后,可一时也没这么可show的,于是网上现抓,可稍好看点的都有水印,怎么办?祭出开源的PhotoShop编辑器:GIMP。网上的图可能有版权(copyright),如下例用到的,我找不到license信息(Had tried to check the site showed in the bottom of the image, but not able to access that URL. Please let me know if anybody seeing concern about this. Thanks in advance)。这里只是简单介绍怎样用GIMP快速编辑图,应该不是问题。

好久没用了,现学教程。工具板都找不到,不过GIMP倒是列出所有的layer了。

工具版不是在menu->Tools下,而是menu->Windows下,或者Recently Closed Docks,或者New Toolbox(ctrl+b)和Dockable Dialog->Tool options。所有layer都visiable时,看不清修改的效果,所以要把除Background的layer都改成invisible(click layer左边的眼睛),然后每改完当前层,就把下一层变成visible。当所有层都改完并可见后,选menu File->Export->存成GIF文件,特别注意要选GIF Option->As Animation,然后按export。



Wednesday, December 29, 2021

两个关于基因和病毒的中文科普Youtube video

 知识就是力量。科学技术是第一生产力。最近在Youtube上看到的尹烨和李治中的两个访谈和演讲,涨知识。

 

中国需要让大众崇尚科学,少些纸醉金迷、物欲横流、唯利是图的颓废。我最看不惯的就是国内的电影电视剧大都是宫廷和抗日神剧,缺少科幻和现代的影视。中国人不是写不出好作品,除了最近的刘云慈的三体,和郑渊洁的舒克贝塔,以前叶永烈写了很多金明戈亮的作品,拿到今天也未必过时。 叶永烈写的小灵通漫游未来更是给了我们一代人对未来的憧憬。我们需要更多的像果壳和知吧的网站,让下一代的孩子有开阔的眼界。

Monday, December 27, 2021

教小朋友编程之坦克大战 2

加声音并不难,最简单的办法是直接调用SDL的mixer API(需要package libSDL2_mixer-devel),参见forked的Tanks,已经加入开始,开火和击中的声音,各自用独立的channel,好处是同一声音不会overlap。

So far有点跑偏了,原因是我打算先完成Windows下的c++ code,然后port到Python的Pygame上。

前面讲到,在cygwin下编译出来的可执行文件,需要依赖X server来render graphics,不是很方便。所以我想直接编译成Windows的图形界面,那么就需要用Visual Studio了,同时要设置Windows下的SDL环境。关于Windows下的SDL,可参见David的how-to-install-sdl2-in-visual-studio,主要是要下载SDL的Windows开发库,包括SDL2 core, ttf(字体), mixer(声音)和image(图像)支持,我只下载了x64 binary,目前最新的是:

我不想安装庞大的VC,也不需要VC的IDE,所以准备只安装VC的Build Tools,甚至不需要Windows SDK,因为根据SDL的文档,它没有其余的dependency。VC Build Tools选择如下:

如果像上图中所有的Optional都清空,只需要2.66GB的空间,可以运行msbuild命令,但是不能运行nmake。运行环境setup通常会看到:'C:\Program' is not recognized as an internal or external command, operable program or batch file. 一方面是空格引起的错误,另一方面环境设置文件如vcvars64.bat并未安装。参见微软文档,需要安装至少一个build环境,如上图的最新MSVC v143 - VS2022 C++ x64/x86 build t..,会额外增加1.6GB的空间。这样环境设置批处理文件都会被安装,不过运行时还会看到The system cannot find the file specified,应该可以忽略。现在可以运行nmake了,需要修改Makefile加入nmake setting,另一个选项是用CMake生成新Makefile。

CMake是Open-Source Cross-Platform Make, 支持Linux,Windows和MacOS。在VS Code中可安装CMake(用来编辑CMakeLists.txt)和CMake Tools(微软为VS Code定制的CMake extension)。如果不用微软的CMake Tools, 也可以直接创建CMake task(参见https://www.40tude.fr/compile-cpp-code-with-vscode-cmake-nmake,需要保证环境变量Path里有CMake的路径)。在用微软的CMake Tools时,我遇到了:

[proc] Executing command: "C:\Program Files\CMake\bin\cmake.EXE" --no-warn-unused-cli -DCMAKE_EXPORT_COMPILE_COMMANDS:BOOL=TRUE -Hc:/w/Tanks -Bc:/w/Tanks/build -G "Visual Studio 17 2022" -T host=x64 -A win32
[cmake] Not searching for unused variables given on the command line.
[cmake] -- Selecting Windows SDK version  to target Windows 10.0.19044.
[cmake] -- The C compiler identification is unknown
[cmake] -- The CXX compiler identification is unknown
[cmake] CMake Error at CMakeLists.txt:3 (project):
[cmake]   No CMAKE_C_COMPILER could be found.

可是MSVC v143已经安装了!CMakeOutput.log显示:

cannot open input file 'kernel32.lib'

这个kernel32.lib应该是从Windows SDK来的,难道必须安装这个庞大的SDK?这个missing lib看起来和上面的No CMAKE_C_COMPILER好像没关联?还是先试试法国人的CMake task吧(我加了 "group": "build",这样就不用"alt-t"=>选task,直接"ctrl-shift-b"=>选build。同样有错:

CMake Error: Could not create named generator 

可是task里已经设了:-G 'NMake Makefiles'。Debug了半天,原来是双引号惹的祸,而且args应该是给list,所以args line应该像这样:

            "args": ["-G \"NMake Makefiles\"", "-DCMAKE_BUILD_TYPE=Debug", ".."],

另外NMake Makefiles不支持toolset设置,如: -T host=x64 -A win32

如果看到错误:

CMake Error at CMakeLists.txt:3 (project):
  Running
   'nmake' '-?'
  failed with:
   The system cannot find the file specified

这是因为没有运行Visual Studio的环境变量设置,VS code找不到nmake可执行文件。

为了绕开诸多麻烦,我直接改了Makefile用cl直接build,然后就遇到问题:

 fatal error C1083: Cannot open include file: 'stddef.h': No such file or directory

 网上一查,Introducing the Universal CRT http://blogs.msdn.com/b/vcblog/archive/2015/03/03/introducing-the-universal-crt.aspx:
"The headers, sources, and libraries are now distributed as part of a separate
Universal CRT SDK. This SDK is included with Visual Studio; it is installed by
default to C:\Program Files (x86)\Windows Kits\10."。看来还是必须安装Windows SDK,最新的Windows 11 SDK, another 2.27GB。装了Windows Kits(SDK)后,至少微软的CMake Tools可以成功生产build file。

@Update on Dec 29, 2021: 一番折腾后终于搞定CMake, 虽然不够完美。CMakeLists.txt文件已经push到forked的Tanks。上面提到的下载的SDL库和头文件要重新安排目录结构,排成和Linux的一样,就不需要改动任何源程序了,然后把所有的SDL文件放在根目录下SDL子目录,这样Makefile就可以用相对目录了。用CMake/NMake build:

  1. cd build
  2. cmake -G "NMake Makefiles" ..
  3. nmake
  4. manually copy all SDL dll file to build/out
  5. All done. Just run: build/out/tanks.exe