alac 发表于 2014-2-6 15:22:39

贪吃蛇源代码

求一个用c语言写的能在vc++正常编译的贪吃蛇源代码。想拿来看一下,学习一下。大神别藏起来了哈。

牡丹花下死做鬼 发表于 2014-2-6 15:22:40

Linux下代码#include <stdio.h>
#include <stdlib.h>
#include <curses.h>
#include <signal.h>
#include <sys/time.h>
#define NUM 60

struct direct                //用来表示方向的
{
    int cx;
    int cy;
};
typedef struct node            //链表的结点
{
    int cx;
    int cy;
    struct node *back;
    struct node *next;
}node;

void initGame();            //初始化游戏
int setTicker(int);            //设置计时器
void show();                //显示整个画面
void showInformation();      //显示游戏信息(前两行)
void showSnake();            //显示蛇的身体
void getOrder();            //从键盘中获取命令
void over(int i);            //完成游戏结束后的提示信息

void creatLink();                //(带头尾结点)双向链表以及它的操作
void insertNode(int x, int y);   
void deleteNode();
void deleteLink();

int ch;                              //输入的命令
int hour, minute, second;            //时分秒
int length, tTime, level;            //(蛇的)长度,计时器,(游戏)等级
struct direct dir, food;            //蛇的前进方向,食物的位置
node *head, *tail;                  //链表的头尾结点

int main()
{
    initscr();
    initGame();
    signal(SIGALRM, show);
    getOrder();
    endwin();
    return 0;
}

void initGame()
{
    cbreak();                  //把终端的CBREAK模式打开
    noecho();                  //关闭回显
    curs_set(0);                //把光标置为不可见
    keypad(stdscr, true);      //使用用户终端的键盘上的小键盘
    srand(time(0));                //设置随机数种子
    //初始化各项数据
    hour = minute = second = tTime = 0;
    length = 1;
    dir.cx = 1;
    dir.cy = 0;
    ch = 'A';
    food.cx = rand() % COLS;
    food.cy = rand() % (LINES-2) + 2;
    creatLink();
    setTicker(20);
}

//设置计时器(这个函数是书本上的例子,有改动)
int setTicker(int n_msecs)
{
    struct itimerval new_timeset;
    long    n_sec, n_usecs;

    n_sec = n_msecs / 1000 ;
    n_usecs = ( n_msecs % 1000 ) * 1000L ;
    new_timeset.it_interval.tv_sec= n_sec;      
    new_timeset.it_interval.tv_usec = n_usecs;      
    n_msecs = 1;
    n_sec = n_msecs / 1000 ;
    n_usecs = ( n_msecs % 1000 ) * 1000L ;
    new_timeset.it_value.tv_sec   = n_sec;      
    new_timeset.it_value.tv_usec    = n_usecs ;   
    return setitimer(ITIMER_REAL, &new_timeset, NULL);
}

void showInformation()
{
    tTime++;
    if(tTime >= 1000000)                //
      tTime = 0;
    if(1 != tTime % 50)
      return;
    move(0, 3);   
    //显示时间
    printw("time: %d:%d:%d %c", hour, minute, second);
    second++;
    if(second > NUM)
    {
      second = 0;
      minute++;
    }
    if(minute > NUM)
    {
      minute = 0;
      hour++;
    }
    //显示长度,等级
    move(1, 0);
    int i;
    for(i=0;i<COLS;i++)
      addstr("-");
    move(0, COLS/2-5);
    printw("length: %d", length);
    move(0, COLS-10);
    level = length / 3 + 1;
    printw("level: %d", level);
}

//蛇的表示是用一个带头尾结点的双向链表来表示的,
//蛇的每一次前进,都是在链表的头部增加一个节点,在尾部删除一个节点
//如果蛇吃了一个食物,那就不用删除节点了
void showSnake()
{
    if(1 != tTime % (30-level))
      return;
    //判断蛇的长度有没有改变
    bool lenChange = false;
    //显示食物
    move(food.cy, food.cx);
    printw("@");
    //如果蛇碰到墙,则游戏结束
    if((COLS-1==head->next->cx && 1==dir.cx)
      || (0==head->next->cx && -1==dir.cx)
      || (LINES-1==head->next->cy && 1==dir.cy)
      || (2==head->next->cy && -1==dir.cy))
    {
      over(1);
      return;
    }
    //如果蛇头砬到自己的身体,则游戏结束
    if('*' == mvinch(head->next->cy+dir.cy, head->next->cx+dir.cx) )
    {
      over(2);
      return;
    }
    insertNode(head->next->cx+dir.cx, head->next->cy+dir.cy);
    //蛇吃了一个“食物”
    if(head->next->cx==food.cx && head->next->cy==food.cy)
    {
      lenChange = true;
      length++;
      //恭喜你,通关了
      if(length >= 50)
      {
            over(3);
            return;
      }
      //重新设置食物的位置
      food.cx = rand() % COLS;
      food.cy = rand() % (LINES-2) + 2;
    }
    if(!lenChange)
    {
      move(tail->back->cy, tail->back->cx);
      printw(" ");
      deleteNode();
    }
    move(head->next->cy, head->next->cx);
    printw("*");
}

void show()
{
    signal(SIGALRM, show);      //设置中断信号
    showInformation();
    showSnake();
    refresh();                  //刷新真实屏幕
}

void getOrder()
{
    //建立一个死循环,来读取来自键盘的命令
    while(1)
    {
      ch = getch();
      if(KEY_LEFT == ch)
      {
            dir.cx = -1;
            dir.cy = 0;
      }
      else if(KEY_UP == ch)
      {
            dir.cx = 0;
            dir.cy = -1;
      }
      else if(KEY_RIGHT == ch)
      {
            dir.cx = 1;
            dir.cy = 0;
      }
      else if(KEY_DOWN == ch)
      {
            dir.cx = 0;
            dir.cy = 1;
      }
      setTicker(20);
    }
}

void over(int i)
{
    //显示结束原因
    move(0, 0);
    int j;
    for(j=0;j<COLS;j++)
      addstr(" ");
    move(0, 2);
    if(1 == i)
      addstr("Crash the wall. Game over");
    else if(2 == i)
      addstr("Crash itself. Game over");
    else if(3 == i)
      addstr("Mission Complete");
    setTicker(0);                //关闭计时器
    deleteLink();                //释放链表的空间
}

//创建一个双向链表
void creatLink()
{
    node *temp = (node *)malloc( sizeof(node) );
    head = (node *)malloc( sizeof(node) );
    tail = (node *)malloc( sizeof(node) );
    temp->cx = 5;
    temp->cy = 10;
    head->back = tail->next = NULL;
    head->next = temp;
    temp->next = tail;
    tail->back = temp;
    temp->back = head;
}

//在链表的头部(非头结点)插入一个结点
void insertNode(int x, int y)
{
    node *temp = (node *)malloc( sizeof(node) );
    temp->cx = x;
    temp->cy = y;
    temp->next = head->next;
    head->next = temp;
    temp->back = head;
    temp->next->back = temp;
}

//删除链表的(非尾结点的)最后一个结点
void deleteNode()
{
    node *temp = tail->back;
    node *bTemp = temp->back;
    bTemp->next = tail;
    tail->back = bTemp;
    temp->next = temp->back = NULL;
    free(temp);
    temp = NULL;
}

//删除整个链表
void deleteLink()
{
    while(head->next != tail)
      deleteNode();
    head->next = tail->back = NULL;
    free(head);
    free(tail);
}windows下(最好用trubo c VC行也行麻烦点貌似要装easyx 应为有graphics.h)#define N 200
#include <graphics.h>
#include <stdlib.h>
#include <dos.h>
#define LEFT 0x4b00
#define RIGHT 0x4d00
#define DOWN 0x5000
#define UP 0x4800
#define ESC 0x011b
int i,key;
int score=0;/*得分*/
int gamespeed=50000;/*游戏速度自己调整*/
struct Food
{
   int x;/*食物的横坐标*/
   int y;/*食物的纵坐标*/
   int yes;/*判断是否要出现食物的变量*/
}food;/*食物的结构体*/
struct Snake
{
   int x;
   int y;
   int node;/*蛇的节数*/
   int direction;/*蛇移动方向*/
   int life;/* 蛇的生命,0活着,1死亡*/
}snake;
void Init(void);/*图形驱动*/
void Close(void);/*图形结束*/
void DrawK(void);/*开始画面*/
void GameOver(void);/*结束游戏*/
void GamePlay(void);/*玩游戏具体过程*/
void PrScore(void);/*输出成绩*/
/*主函数*/
void main(void)
{
   Init();/*图形驱动*/
   DrawK();/*开始画面*/
   GamePlay();/*玩游戏具体过程*/
   Close();/*图形结束*/
}
/*图形驱动*/
void Init(void)
{
   int gd=DETECT,gm;
   initgraph(&gd,&gm,"c:\\tc");
   cleardevice();
}
/*开始画面,左上角坐标为(50,40),右下角坐标为(610,460)的围墙*/
void DrawK(void)
{
/*setbkcolor(LIGHTGREEN);*/
   setcolor(11);
   setlinestyle(SOLID_LINE,0,THICK_WIDTH);/*设置线型*/
   for(i=50;i<=600;i+=10)/*画围墙*/
   {
      rectangle(i,40,i+10,49); /*上边*/
      rectangle(i,451,i+10,460);/*下边*/
   }
for(i=40;i<=450;i+=10)
{
   rectangle(50,i,59,i+10); /*左边*/
   rectangle(601,i,610,i+10);/*右边*/
}
}
/*玩游戏具体过程*/
void GamePlay(void)
{
   randomize();/*随机数发生器*/
   food.yes=1;/*1表示需要出现新食物,0表示已经存在食物*/
   snake.life=0;/*活着*/
   snake.direction=1;/*方向往右*/
   snake.x=100;snake.y=100;/*蛇头*/
   snake.x=110;snake.y=100;
   snake.node=2;/*节数*/
   PrScore();/*输出得分*/
   while(1)/*可以重复玩游戏,压ESC键结束*/
   {
      while(!kbhit())/*在没有按键的情况下,蛇自己移动身体*/
      {
if(food.yes==1)/*需要出现新食物*/
{
      food.x=rand()()%400+60;
      food.y=rand()()%350+60;
      while(food.x%10!=0)/*食物随机出现后必须让食物能够在整格内,这样才可以让蛇吃到*/
food.x++;
      while(food.y%10!=0)
food.y++;
food.yes=0;/*画面上有食物了*/
}
if(food.yes==0)/*画面上有食物了就要显示*/
{
            setcolor(GREEN);
            rectangle(food.x,food.y,food.x+10,food.y-10);
}
         for(i=snake.node-1;i>0;i--)/*蛇的每个环节往前移动,也就是贪吃蛇的关键算法*/
         {
            snake.x=snake.x;
   snake.y=snake.y;
}
       /*1,2,3,4表示右,左,上,下四个方向,通过这个判断来移动蛇头*/
switch(snake.direction)
{
   case 1:snake.x+=10;break;
   case 2: snake.x-=10;break;
   case 3: snake.y-=10;break;
   case 4: snake.y+=10;break;
}
for(i=3;i<snake.node;i++)/*从蛇的第四节开始判断是否撞到自己了,因为蛇头为两节,第三节不可能拐过来*/
{
   if(snake.x==snake.x&&snake.y==snake.y)
   {
               GameOver();/*显示失败*/
               snake.life=1;
               break;
   }
      }
if(snake.x<55||snake.x>595||snake.y<55||
    snake.y>455)/*蛇是否撞到墙壁*/
{
   GameOver();/*本次游戏结束*/
   snake.life=1; /*蛇死*/
}
if(snake.life==1)/*以上两种判断以后,如果蛇死就跳出内循环,重新开始*/
         break;
if(snake.x==food.x&&snake.y==food.y)/*吃到食物以后*/
{
         setcolor(0);/*把画面上的食物东西去掉*/
         rectangle(food.x,food.y,food.x+10,food.y-10);
    snake.x=-20;snake.y=-20;
          /*新的一节先放在看不见的位置,下次循环就取前一节的位置*/
    snake.node++;/*蛇的身体长一节*/
    food.yes=1;/*画面上需要出现新的食物*/
    score+=10;
    PrScore();/*输出新得分*/
}
setcolor(4);/*画出蛇*/
for(i=0;i<snake.node;i++)
    rectangle(snake.x,snake.y,snake.x+10,
               snake.y-10);
delay(gamespeed);
setcolor(0);/*用黑色去除蛇的的最后一节*/
rectangle(snake.x,snake.y,
snake.x+10,snake.y-10);
   }/*endwhile(!kbhit)*/
    if(snake.life==1)/*如果蛇死就跳出循环*/
      break;
    key=bioskey(0);/*接收按键*/
    if(key==ESC)/*按ESC键退出*/
       break;
    else
       if(key==UP&&snake.direction!=4)
/*判断是否往相反的方向移动*/
   snake.direction=3;
       else
   if(key==RIGHT&&snake.direction!=2)
      snake.direction=1;
   else
      if(key==LEFT&&snake.direction!=1)
snake.direction=2;
      else
if(key==DOWN&&snake.direction!=3)
   snake.direction=4;
   }/*endwhile(1)*/
}
/*游戏结束*/
void GameOver(void)
{
    cleardevice();
    PrScore();
   setcolor(RED);
   settextstyle(0,0,4);
   outtextxy(200,200,"GAME OVER");
   getch()();
}
/*输出成绩*/
void PrScore(void)
{   
   char str;
   setfillstyle(SOLID_FILL,YELLOW);
   bar(50,15,220,35);
   setcolor(6);
   settextstyle(0,0,2);
   sprintf(str,"score:%d",score);
   outtextxy(55,20,str);
}
/*图形结束*/
void Close(void)
{   
    getch()();
    closegraph();
}

牡丹花下死做鬼 发表于 2014-2-6 18:28:46

还有 我是windows 而且没装trubo c 这到底能不能正常运行 我心里却是没底啊

andalousie 发表于 2014-2-6 18:42:11

本帖最后由 andalousie 于 2014-2-6 18:48 编辑

/***********************************************
* File: snake.cpp
* Author: Keith Schwarz (htiek@cs.stanford.edu)
*
* An implementation of the game "Snake" with a
* rudimentary computer AI player.The computer
* controls a snake that tries to eat as much food
* as possible.Every time it eats a food pellet,
* its length increases by one.The snake loses if
* it hits a wall or crashes into itself.
*
* The AI in this program is extremely simple.The
* snake moves forward, turning with probability 1/5
* at each step.If the snake's next step will
* certainly hit a wall, it tries to turn.
*
* In order to run this program, you will need to use
* a level file.A set of sample files are included
* in this directory.
*/

#include <iostream>
#include <string>
#include <deque>
#include <vector>
#include <fstream>
#include <cstdlib>
#include <ctime>
using namespace std;

/* Probability of turning at each step. */
const double kTurnRate = 0.2;

/* Time to wait, in seconds, between frames. */
const double kWaitTime = 0.1;

/* Number of food pellets that must be eaten to win. */
const size_t kMaxFood = 20;

/* Constants for the different tile types.Each level file is
* encoded using these characters.
*/
const char kEmptyTile = ' '; // Empty space
const char kWallTile= '#'; // Wall
const char kFoodTile= '
; // Food
const char kSnakeTile = '*'; // Snake start location/current position

/* The string used to clear the display before printing the game board.
* Windows systems should use CLS, Mac OS X or Linux users should use
* clear.
*/

const string kClearCommand = "CLS";

/* A struct encoding a point in a two-dimensional grid. */
struct pointT {
size_t row, col;

/* Utility constructor. */
pointT(size_t row, size_t col) {
    this->row = row;
    this->col = col;
}

/* Default constructor sets everything to 0. */
pointT() {
    row = col = 0;
}
};

/* A struct containing relevant game information. */
struct gameT {
vector<string> world; // The playing field.Each string is
                        // composed of the characters encoding
                        // tiles and represents one row of the
                        // playing field.

size_t numRows, numCols; // Size of the playing field

deque<pointT> snake;// The snake body.The head is in the front
                        // of the deque and the tail in the back, so
                        // we can easily advance the snake a step
                        // forward

int dx, dy;         // The snake direction

size_t numEaten;      // How much food we've eaten.
};

/* Reads a line of text from the user. */
string GetLine() {
string result;
getline(cin, result);
return result;
}

/* Returns true with probability probability.This works by scaling
* down rand() by RAND_MAX so that we have a value in [0, 1) and returning
* whether the value is less than the set probability.
*/
bool RandomChance(double probability) {
return static_cast<double>(rand()) / RAND_MAX < probability;
}

/* Places a piece of food randomly on the board.This assumes that there
* is some free space remaining.
*/
void PlaceFood(gameT& game) {
while(true) {
    size_t row = rand() % game.numRows;
    size_t col = rand() % game.numCols;
   
    /* If there isn't anything at the specified position, place the food there. */
    if(game.world == kEmptyTile) {
      game.world = kFoodTile;
      return;
    }
}
}

/* Clears the display and prints the game board. */
void PrintWorld(gameT& game) {
/* Use a system call to clear the display. */
system(kClearCommand.c_str());

/* Print each row. */
for(size_t i = 0; i < game.world.size(); ++i)
    cout << game.world << endl;

cout << "Food eaten: " << game.numEaten << endl;
}

/* Given an ifstream to a file containing CORRECTLY-FORMATTED world data,
* loads in the world.
*
* The format used is as follows:
* Line 1: numRows numCols
* Line 2: dx dy
* Rest:   World data
*
* We assume that the world is correctly-sized and that there is a single
* '*' character in the world that's the starting point for the snake.
*/
void LoadWorld(gameT& game, ifstream& input) {
/* Read in the number of rows and columns. */
input >> game.numRows >> game.numCols;
game.world.resize(game.numRows);

/* Read in the starting location. */
input >> game.dx >> game.dy;

/* Because we're going to be using getline() to read in the world
   * data, we need to make sure that we consume the newline character
   * at the end of the line containing the input data.We'll use
   * getline() to handle this.This scans characters until it finds
   * a newline, then consumes it.
   */
string dummy;
getline(input, dummy);

/* Read in the rows. */
for(size_t row = 0; row < game.numRows; ++row) {
    getline(input, game.world);
   
    /* Check to see if the * character (snake start position)
   * is in this line.If so, make the snake.
   */
    size_t col = game.world.find('*');
    if(col != string::npos)
      game.snake.push_back(pointT(row, col));
}

/* Set numEaten to zero - this needs to get done somewhere! */
game.numEaten = 0;
}

/* Helper function which returns whether a point is contained in the game
* grid.
*/
bool InWorld(pointT& pt, gameT& game) {
return pt.col < game.numCols &&
         pt.row < game.numRows;
}

/* Returns whether, if the snake head is at position head, the snake
* has crashed.
*/
bool Crashed(pointT head, gameT& game) {
/* We crashed if the head is out of bounds, on a wall, or on another
   * snake piece.
   */
return !InWorld(head, game) ||
         game.world == kSnakeTile ||
         game.world == kWallTile;
}

/* Returns the next position occupied by the head if the snake is moving
* in the direction dx, dy.
*/
pointT GetNextPosition(gameT& game, int dx, int dy) {
/* Get the head. */
pointT nextSpot = game.snake.front();

/* Update it. */
nextSpot.col += dx;
nextSpot.row += dy;

return nextSpot;
}

/* Performs AI logic to control the snake.The behavior is as follows:
* 1. If we aren't going to crash and we don't roll a 1 on a fair die,
*    keep going straight.
* 2. Otherwise, check to see if we can turn left or right.Then randomly
*    pick one safe choice.
*/
void PerformAI(gameT& game) {
/* Look where we're going to be next step. */
pointT nextSpot = GetNextPosition(game, game.dx, game.dy);

/* If this crashes us or we just feel like turning, turn. */
if(Crashed(nextSpot, game) || RandomChance(kTurnRate)) {
    /* Compute what direction we'd be facing if we turned left or
   * right.From linear algebra we have the following:
   *
   * For a left turn:
   * |x'|   |0 -1||x| --> x' = -y
   * |y'| = |10||y| --> y' =x
   *
   * For a right turn:
   * |x'|   |01||x| --> x' =y
   * |y'| = |-1 0||y| --> y' = -x
   */
    int leftDx = -game.dy;
    int leftDy =game.dx;
   
    int rightDx =game.dy;
    int rightDy = -game.dx;
   
    /* Check if turning left or right will cause us to crash. */
    bool canLeft = !Crashed(GetNextPosition(game, leftDx, leftDy), game);
    bool canRight = !Crashed(GetNextPosition(game, rightDx, rightDy), game);
   
    /* Now determine which direction to turn based on what direction
   * we're facing.If we can choose either direction, pick one
   * randomly.If we can't turn, don't.
   */
    bool willTurnLeft;
    if(!canLeft && !canRight)
      return;
    else if(canLeft && !canRight)
      willTurnLeft = true;
    else if(!canLeft && canRight)
      willTurnLeft = false;
    else
      willTurnLeft = RandomChance(0.5);
   
    /* Otherwise, based on the direction, turn appropriately. */
    game.dx = willTurnLeft? leftDx : rightDx;
    game.dy = willTurnLeft? leftDy : rightDy;
}
}

/* Moves the snake one step in its current direction and handles collisions
* and eating food.Returns true if we didn't crash, false if we did.
*/
bool MoveSnake(gameT& game) {
/* Compute new head. */
pointT nextHead = GetNextPosition(game, game.dx, game.dy);

/* Check for dead. */
if(Crashed(nextHead, game))
    return false;

/* Remember whether we just ate food. */
bool isFood = (game.world == kFoodTile);

/* Update the display. */
game.world = kSnakeTile;

/* Push new head to the front of the deque. */
game.snake.push_front(nextHead);

/* If we got food, pick a new spot and don't remove the tail.This
   * causes us to extend by one spot. */
if(isFood) {
    PlaceFood(game);
    ++game.numEaten;
}
else {
    /* Clear the tail and remove it from the snake. */
    game.world = kEmptyTile;
    game.snake.pop_back();
}

return true;
}

/* Pauses for a few milliseconds so we can see what's happening.This is
* implemented using a busy loop, which is less-than-optimal but doesn't
* require platform-specific features.
*/
void Pause() {
clock_t start = clock();

while(static_cast<double>(clock() - start) / CLOCKS_PER_SEC < kWaitTime);
}

/* Prompts the user for a filename, then loads the specified file. */
void InitializeGame(gameT& game) {
/* Seed the randomizer. */
srand(static_cast<int>(time(NULL)));

ifstream input;
while(true) {
    cout << "Enter level file: ";
    input.open(GetLine().c_str());
   
    if(!input.fail()) break;
   
    cout << "Sorry, I can't open that file." << endl;
    input.clear();
}

LoadWorld(game, input);
}

/* Displays the result of the game. */
void DisplayResult(gameT& game) {
PrintWorld(game);
if(game.numEaten == kMaxFood)
    cout << "Yay!The snake won!" << endl;
else
    cout << "Oh no!The snake crashed!" << endl;
}

/* Runs the simulation and displays the result. */
void RunSimulation(gameT& game) {
/* Keep looping while we haven't eaten too much. */
while(game.numEaten < kMaxFood) {
    PrintWorld(game);
    PerformAI(game);
   
    /* Move the snake and abort if we crashed. */
    if(!MoveSnake(game))
      break;
    Pause();
}
DisplayResult(game);
}

/* The main program.Initializes the world, then runs the simulation. */
int main() {
gameT game;
InitializeGame(game);
RunSimulation(game);
return 0;
}

andalousie 发表于 2014-2-6 19:10:13

地图格式是15 15
1 0
###############
#             #
# # # # # # # #
#$$    $#
# # # # # # # #
#$          #
# # # # # # # #
#      *      #
# # # # # # # #
#          $#
# # # # # # # #
#$   $ $#
# # # # # # # #
#             #
###############

GINut 发表于 2014-2-6 22:15:45

看看而已,初学者

未闻丶花名 发表于 2014-2-8 20:54:28

路过看看 = =

谓我心忧 发表于 2014-2-10 15:14:55

不明觉厉啊~~~
页: [1]
查看完整版本: 贪吃蛇源代码