cmd代码玩贪吃蛇_关于N行贪吃蛇回答的补充

最近堆叠的事情比较多,返回到这一层时知乎问题已经不能修改了,只好开一篇文章说。

用C语言,能在100行之内实现贪吃蛇吗? - duangsuse的回答 - 知乎 https://www.zhihu.com/question/360814879/answer/1601486959

不说无关技术的语文错误(如把使用写成适用),那个压行代码的部分应该也有部分逻辑缺失的问题(比如 cursEnableputWall 的逻辑,对程序正确性影响大)

我在此给一个完整的压行版(10行,但行数已无意义):

//gcc rm.c -DW=24 -DH=18 -lncurses -include curses.h #-include stdlib.h -include unistd.h
// gobals
int w;int h;int nM;int nBlk;typedef int*map2D;map2D m;map2D que;int p;int iHead=0;useconds_t delayUsec;void init(int m_w,int m_h,int dt){w=m_w;h=m_h;nM=w*h;delayUsec=dt*1000;map2D*maps[]={&m,&que};for(int i=0;i<2;i++)*maps[i]=malloc(sizeof(int)*nM);}
// data model
static inline int pYX(int y,int x){return y*w+x;}static inline void yxP(int p,int*y,int*x){*y=p/w,*x=p%w;}static inline int cycledInc(int*p){*p=(*p+1)%nM;return*p;}int isZeroOr(int n,int x){return(x%n)==0;}int curUse(int(op)(WINDOW*,bool)){return op(stdscr,1);}
//putXX
void putWall(){int y,x;for(int i=0;i<nM;i++){yxP(i,&y,&x);if (isZeroOr(w-1, x)||isZeroOr(h-1, y)) m[i]=1;}}void putCell(){que[cycledInc(&iHead)]=p;m[p]=1;}void putFruit(){int pA;do{pA=rand()%nM;}while(m[pA]!=0);m[pA]=2;}
//game
void game(char*style[]){noecho();curUse(nodelay);curUse(keypad);int ch,y,x,d=1,iTail=0;putWall();putFruit();p=pYX(h/2,w/2);putCell();while((ch=wgetch(stdscr))!='q'){if(ch==(-1)){}else if(ch==259&&d!=w)d=-w;else if(ch==258&&d!=-w)d=w;else if(ch==260&&d!=1)d=-1;else if(ch==261&&d!=-1)d=1;p+=d;if(m[p]==1){break;}if(m[p]==2){putFruit();}else{m[que[cycledInc(&iTail)]]=0;}putCell();for(int i=0;i<nM;i++){yxP(i,&y,&x);mvprintw(y,x*nBlk,style[m[i]]);}wrefresh(stdscr);usleep(delayUsec);}}
//call init,game
int main(){char*deftStyle[]={"  ","[]","()"};nBlk=2;initscr();curs_set(0);init(W,H,100);game(deftStyle);wgetch(stdscr);return endwin();}

第一行编译命令 # 号后的头文件是选择性包含(.h 里只用了函数的 extern),可以 -Wno-everything 替换。

ed08ad256973bd51655c7dcf2daadcfd.png

关于这个程序以代码行数评优劣,的确十分不妥(不过不当人面我说句心里话,我重写的那个大佬也该试着多重写几次看看,总会有进步;还有,许多其它都只实现了命令行前端的答主,你们大几百行已经够我用 clean C + asprintf 写一个 multiplayer 的贪吃蛇了,要加油啊)

至于B站那个18行的,不得不承认是“很有创新性”(我也不知道该不该这么说),反正我复刻了一遍(修改了IO方式消除“闪烁”,为此也对后端数据解释做了点改动,毕竟不要闪烁是不可能区别mpApple各自渲染的)

// Windows.h, conio.h, limits.h, stdlib/stdio/time
// 当然你要和他一样短,C预处理器 gcc -E 过一遍内联所有常量就行
define w 50
#define h 40
#define speed 100
const char *sNone="  ", *sBody="[]", *sFruit="()";
const int nM=w*h, nBlk=2; int *m;

HANDLE hStdout = GetStdHandle(STD_OUTPUT_HANDLE);
void printp(int p, const char* s) {
  COORD cd = {p%w*nBlk, p/w};
  SetConsoleCursorPosition(hStdout, cd);
  printf("%s", s);
}
int randP() { int pt; do { pt = rand()%nM; } while (m[pt]!=0); return pt; }
#define isZeroOr(n, x) ((x%n) == 0)

int main(void) {
  srand(time(NULL));
  m = malloc(nM);
  char* cmd; asprintf(&cmd, "mode con cols=%d lines=%d", w*nBlk, 1+h); system(cmd);
  for (int i=0; i<nM; i++) m[i] = (isZeroOr(h-1, i/w) || isZeroOr(w-1, i%w))? 1 : 0;
  int p=(h/2)*w + w/2, d=1, nLen=1, pA=randP();
  unsigned t0 = time(NULL);
  char ch; while (!kbhit() || (ch=getch()) != 'q') {
    d =
      (ch=='a')? -1 :
      (ch=='d')?+1 :
      (ch=='w')? -w :
      (ch=='s')? +w : d;
    p+=d; if (m[p]==1) break;
    m[p] = nLen+1/*decred later*/;
    if (p==pA) { nLen++; pA = randP(); continue; }
    int oldMpA = m[pA]; m[pA] = INT_MAX-1;
    for (int i=0; i<nM; i++) { m[i]--; printp(i, (m[i]<=0)? sNone : (m[p]!=INT_MAX-1-1)? sBody : sFruit); }
    m[pA] = oldMpA;
    unsigned t1 = time(NULL);
    Sleep((t1-t0)/speed); t0 = t1;
  }
}

注意,我这个版本没有“闪烁”而且没注意压行,长几倍。当然性能一样很垃圾(每次渲染都要递减整个 map 数组,思量是不是要 SIMD <xmmintrin> 优化,啧啧)

至于其它两个超短(C/JavaScript,惯常一维的存储模式)蛇,虽然还好(也不至于按一键更一帧,之前听说有人只会这么写),但行为上要么直接朝运动反向击键会挂(我也写了这种版本),要么完全不会挂(没有墙、撞自己也不会),所以说,最小化设计也不是说一定有多短。

就好像算法的时间复杂度一样,好的代码功能越多越好维护、实现行数开销越少,烂代码,即便刚开始看起来很短,如果要加一个功能,要么然你痛苦要么然电脑痛苦。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
以下是一个使用turtlesim实现贪吃蛇的Python代码: ```python import rospy from geometry_msgs.msg import Twist from turtlesim.msg import Pose from math import pow, atan2, sqrt class TurtleBot: def __init__(self): rospy.init_node('turtlebot_controller', anonymous=True) self.velocity_publisher = rospy.Publisher('/turtle1/cmd_vel', Twist, queue_size=10) self.pose_subscriber = rospy.Subscriber('/turtle1/pose', Pose, self.update_pose) self.pose = Pose() self.rate = rospy.Rate(10) def update_pose(self, data): self.pose = data self.pose.theta = round(self.pose.theta, 4) def euclidean_distance(self, goal_pose): return sqrt(pow((goal_pose.x - self.pose.x), 2) + pow((goal_pose.y - self.pose.y), 2)) def linear_vel(self, goal_pose, constant=1.5): return constant * self.euclidean_distance(goal_pose) def steering_angle(self, goal_pose): return atan2(goal_pose.y - self.pose.y, goal_pose.x - self.pose.x) def angular_vel(self, goal_pose, constant=6): return constant * (self.steering_angle(goal_pose) - self.pose.theta) def move2goal(self): goal_pose = Pose() goal_pose.x = input("Set your x goal: ") goal_pose.y = input("Set your y goal: ") distance_tolerance = input("Set your tolerance: ") vel_msg = Twist() while self.euclidean_distance(goal_pose) >= distance_tolerance: vel_msg.linear.x = self.linear_vel(goal_pose) vel_msg.linear.y = 0 vel_msg.linear.z = 0 vel_msg.angular.x = 0 vel_msg.angular.y = 0 vel_msg.angular.z = self.angular_vel(goal_pose) self.velocity_publisher.publish(vel_msg) self.rate.sleep() vel_msg.linear.x = 0 vel_msg.angular.z = 0 self.velocity_publisher.publish(vel_msg) if __name__ == '__main__': try: x = TurtleBot() x.move2goal() except rospy.ROSInterruptException: pass ``` 希望能对你有所帮助!
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值