Code Space

Blue sky

 

用dart实现一个ASCII交互小动画

周末的时候想教小孩编程,想先引起孩子的兴趣,就想做一个小动画出来给她看看。之前给她玩过scratch的示例小猫,小猫可以通过简单的命令设置在屏幕上移动。就想用dart自己做一个,结果发现桌面端对图形的支持比较差,需要安装一堆额外的东西,或者采用flutter的app/web/desktop方案。简单研究了一下,都比较麻烦(主要也是当时用的电脑也不允许安装这些东西),就暂时放弃了,准备以后作为一个单独的课题进行研究。

于是就想,之前玩BBS时,经常有一些ASCII字符画,要不就在命令行的环境下,做一个简单的ASCII图画移动程序吧。然后在网上找了一幅画,又做了ASCII转码(网址:https://www.degraeve.com/img2txt.php),然后写了如下的程序。本次只做了平移,没有做旋转,后续再研究一下旋转的实现。平移的实现主要靠对数组的操作。

本次环境:

dart vm version: 2.10.4

console:

height = 30;
width = 118;
 
完整代码如下:
  1 import 'dart:io';
  2 import 'dart:math';
  3 
  4 main() async {
  5   var path = r'.\ascii\dog.txt';
  6 
  7   var lines = await File(path).readAsLines();
  8 
  9   display(AsciiImage(
 10       'dog', List.generate(lines.length, (i) => lines[i].split(''))));
 11 }
 12 
 13 void display(AsciiImage image) {
 14   Console.draw(image);
 15   var cmd = _getCmd();
 16   while (cmd != 'exit') {
 17     var steps = _getSteps();
 18     switch (cmd) {
 19       case 'up':
 20         image.moveUp(steps);
 21         Console.draw(image);
 22         break;
 23       case 'down':
 24         image.moveDown(steps);
 25         Console.draw(image);
 26         break;
 27       case 'left':
 28         image.moveLeft(steps);
 29         Console.draw(image);
 30         break;
 31       case 'right':
 32         image.moveRight(steps);
 33         Console.draw(image);
 34         break;
 35       default:
 36         break;
 37     }
 38     if (!image.isValid()) {
 39       stdout.writeln('Aha~~~ the ${image.name} has disappeared! Game Over!');
 40       return;
 41     }
 42     cmd = _getCmd();
 43   }
 44 }
 45 
 46 class Console {
 47   static const height = 30;
 48   static const width = 118;
 49 
 50   static void draw(AsciiImage image) {
 51     var outImage = _needCut(image) ? image.cut(height, width) : image;
 52     stdout.writeln(outImage.content);
 53   }
 54 }
 55 
 56 bool _needCut(AsciiImage image) =>
 57     image.height > Console.height || image.width > Console.width;
 58 
 59 bool _isValidCmd(String cmd) =>
 60     cmd == 'left' ||
 61     cmd == 'right' ||
 62     cmd == 'up' ||
 63     cmd == 'down' ||
 64     cmd == 'exit';
 65 
 66 String _getCmd() {
 67   stdout.write(
 68       'Now try to move the dog! left, right, up or down. exit for quit: ');
 69   var cmd = stdin.readLineSync().toLowerCase();
 70   while (!_isValidCmd(cmd)) {
 71     stdout.write('Invalid Command! left, right, up or down. exit for quit: ');
 72     cmd = stdin.readLineSync().toLowerCase();
 73   }
 74   return cmd;
 75 }
 76 
 77 int _getSteps() {
 78   var steps = -1;
 79   while (steps < 0) {
 80     stdout.write('Please input the steps(an integer >= 0): ');
 81     try {
 82       steps = int.parse(stdin.readLineSync());
 83     } catch (e) {}
 84   }
 85   return steps;
 86 }
 87 
 88 class AsciiImage {
 89   static const placeholder = ' ';
 90 
 91   String name;
 92 
 93   final List<List<String>> asciis;
 94 
 95   AsciiImage(this.name, this.asciis);
 96 
 97   AsciiImage.generateEmptyImage(this.name, int height, int width)
 98       : asciis = List.generate(
 99             height, (_) => List.filled(width, placeholder, growable: true));
100 
101   int get height => asciis.length;
102 
103   int get width => asciis.isEmpty ? 0 : asciis[0].length;
104 
105   void moveLeft(int x) {
106     for (var line in asciis) line.removeRange(0, min(x, width));
107   }
108 
109   void moveRight(int x) {
110     for (var line in asciis) line.insertAll(0, List.filled(x, placeholder));
111   }
112 
113   void moveUp(int y) => asciis.removeRange(0, min(y, height));
114 
115   void moveDown(int y) => asciis.insertAll(0,
116       List.generate(y, (_) => List.filled(width, placeholder, growable: true)));
117 
118   // 裁剪,根据给定的高和宽,当图形移动超出屏幕显示范围时,需要裁剪
119   AsciiImage cut(int h, int w) => AsciiImage(
120       name,
121       List.generate(
122           min(height, h), (i) => asciis[i].sublist(0, min(width, w))));
123 
124   // 字符画的本质是字符串,因此将其转换为字符串以便输出
125   String get content {
126     var buffer = StringBuffer();
127     for (var line in asciis) buffer.write('${line.join()}\n');
128     return buffer.toString();
129   }
130 
131   bool isValid() => height > 0 && width > 0;
132 }

示例用的小狗ASCII文件内容dog.txt:

                                                  
                              L#KKK#G.            
                            .G        EK          
                           .i           t,        
                           W             ;,       
                                          ;f      
                          D  K   G          #     
                          #  ;    f      #   .#t# 
                          L L     f           K . 
                          i #      ;          fDW 
                         :  E      W            , 
                         E  f      i           K  
                         #t D      .          .,  
                        :: t#                ii   
                        #EG E               K.    
                       .;  ED:     ,    ,DWi      
                       #     #     ##fG;          
                      j      ;    L    D          
                     t;       W  #L#;  EL         
   j, #             W.         ##    ;t  W        
  ;.  ,          ;#i                 K  ;j        
  L   i        tW                    f LWD        
 D    #       #                       # Di        
 D   i      ,E                        :           
 ,   #     t;                        .            
.    E    ;i                         D            
 .   t    D                          #            
 f   j   #                          t             
 #   #   :                          L             
 ,   :t G                     #,   D              
  #    ##                    # ,   E              
   #                       .#  i  ,               
    ;#t                   t;E  j  W               
        .K              :#  j  D  #               
          K           ,#:    . #  K               
          K         #f       E D .#               
          #        GDE#.     f .   K              
         t             #      Wtf  .              
         ;L;iG####WWEEEi        ;i E              
                                  .               

 

posted on 2021-01-27 18:14  一抹青阳  阅读(254)  评论(0)    收藏  举报

导航