生命游戏的简单实现(c++代码)

今天上数模课,本来一如既往准备自习,但是,生命游戏——从前就在“人工智能”的书上看到过,今天一讲,发现如此简单。课上30min实现了一份简单的生命游戏代码/


前言

系统演变仿真——生命游戏(与细胞自动机but没实现)

这是数模课的一节内容,讲计算机仿真,其中的一个小点,生命游戏。


一、生命游戏

  • 生命游戏(Game of Life, 简称 生命)是 John Conway 于 1970 年发明的
  • 生命游戏不是通常意义上的游戏,没有游戏者,也无所谓胜负
  • 生命游戏是一类特殊的 细胞自动机(Cellular Automata)
  • 一旦给定初始状态,之后的发展完全由规则确定
  • 生命充满了悬念!绝大多数情况下,不可能只根据初始状态(或称模式)判断未来的发展,只能按照游戏的规则运行下去

生命游戏的基本设置

  • 游戏在一个方形网格中进行,网格在各个方向上都是无限延伸的
  • 每个网格中有一个细胞,细胞可以是  的或者  的
  • 如果细胞是活的就在它所在的方格做一个标记,死的细胞则留空
  • 每个细胞的 邻居 是指它最邻近的 8 个方格

生命游戏的规则

  • 游戏的每一步中,计算每个细胞的 活邻居数目,由此数字决定下一步发展
  • 如果一个死细胞正好有 3 个活邻居,则下一步变成一个活细胞(诞生
  • 如果一个活细胞有 2 个或 3 个活邻居,则可以继续活下去(生存
  • 其他情况下,细胞将死去或保持死的状态(拥挤孤独

生命游戏的应用与发展

  • 生命游戏的演变规则近似的描述了生物群体的生存规律,经过扩展能够模拟生命活动中的生存、灭绝、竞争等等复杂现象
  • Conway 证明,生命游戏具有通用图灵机的计算能力,能力上与图灵机等价
  • 生命游戏的主要扩展方式包括修改或扩展规则改变生存空间设置

二、代码实现过程

  • 游戏的每一步中,计算每个细胞的 活邻居数目,由此数字决定下一步发展

这一步遍历整个表并且记录信息即可。

  • 如果一个死细胞正好有 3 个活邻居,则下一步变成一个活细胞(诞生
  • 如果一个活细胞有 2 个或 3 个活邻居,则可以继续活下去(生存
  • 其他情况下,细胞将死去或保持死的状态(拥挤孤独

这一步跟据记录的信息,标记/更新下一轮存活/死亡的信息。

实际上,一句代码即可:

table[i][j]=(count[i][j]==3?true:(count[i][j]==2?table[i][j]:false));

此外,每一轮,经过循环控制就可以实现一代又一代的演变。

三、代码

#include<iostream>
#include<cstdio>
#include<random>
#include<time.h>
#include<windows.h>

#define SIZE 30
#define TIMES 1000
using namespace std;

bool table[SIZE][SIZE];
int count[SIZE][SIZE];//存储该网格周围存活细胞数

void init();//初始化table
void show();//打印table
void count_live();  //计算所有网格周围存活细胞数,结果存在count中
int calcu(int x,int y);//计算单个网格周围存活细胞数
void live_next();//计算下一个时间片存活的情况

int main()
{
    init();
    int times=0;
    while(times++<TIMES)
    {
        show();
        Sleep(20);
        count_live();
        live_next();
        system("cls");
    }
    system("pause");
    return 0;
}

void init()
{
    srand(time(0));
    for(int i=0;i<SIZE;++i)
        for(int j=0;j<SIZE;++j)
        {
            table[i][j]=(rand()%3==0);
        }
}

void show()//打印table
{
    for(int i=0;i<SIZE;++i)
    {
        cout<<endl;
        for(int j=0;j<SIZE;++j)
        {
            if(table[i][j])cout<<"*"<<" ";
            else cout<<" "<<" ";
        }
        cout<<endl;
    }
}

void count_live()
{
    for(int i=0;i<SIZE;++i)
        for(int j=0;j<SIZE;++j)
        {
            count[i][j]=calcu(i,j);
        }
}

int calcu(int x,int y)//计算单个网格周围存活细胞数
{
    int num=0;
    if(table[(x-1+SIZE)%SIZE][(y-1+SIZE)%SIZE])num++;
    if(table[(x-1+SIZE)%SIZE][(y+SIZE)%SIZE])num++;
    if(table[(x-1+SIZE)%SIZE][(y+1+SIZE)%SIZE])num++;
    if(table[(x+SIZE)%SIZE][(y-1+SIZE)%SIZE])num++;
    if(table[(x+SIZE)%SIZE][(y+1+SIZE)%SIZE])num++;
    if(table[(x+1+SIZE)%SIZE][(y-1+SIZE)%SIZE])num++;
    if(table[(x+1+SIZE)%SIZE][(y+SIZE)%SIZE])num++;
    if(table[(x+1+SIZE)%SIZE][(y+1+SIZE)%SIZE])num++;
    return num;
}

void live_next()//计算下一个时间片存活的情况
{
    for(int i=0;i<SIZE;++i)
    {
        for(int j=0;j<SIZE;++j)
        {
            table[i][j]=(count[i][j]==3?true:(count[i][j]==2?table[i][j]:false));
        }
    }
}

说明

#define SIZE 30
#define TIMES 1000

用于控制地图的大小、循环的轮次。 

//init():
table[i][j]=(rand()%3==0);

用于控制初始化时,初始状态的网格点存活的概率,通过修改可以调整初始存活生命的多与少。

//show():
if(table[i][j])cout<<"*"<<" ";
else cout<<" "<<" ";

用于显示死亡/存活,可以自己修改显示的方式。

//main():
Sleep(20);

用于控制显示的帧率。

//calcu():
if(table[(x-1+SIZE)%SIZE][(y-1+SIZE)%SIZE])num++;
if(table[(x-1+SIZE)%SIZE][(y+SIZE)%SIZE])num++;
if(table[(x-1+SIZE)%SIZE][(y+1+SIZE)%SIZE])num++;
if(table[(x+SIZE)%SIZE][(y-1+SIZE)%SIZE])num++;
if(table[(x+SIZE)%SIZE][(y+1+SIZE)%SIZE])num++;
if(table[(x+1+SIZE)%SIZE][(y-1+SIZE)%SIZE])num++;
if(table[(x+1+SIZE)%SIZE][(y+SIZE)%SIZE])num++;
if(table[(x+1+SIZE)%SIZE][(y+1+SIZE)%SIZE])num++;

采用了边界取模循环,类比于空间无限大,回避边界问题。 

可视化通过cmd窗口实现 ,比较丑陋。(下面是过程的图)


结语

实现起来还是非常有趣且简单的!!

  • 1
    点赞
  • 17
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
VC++场景游戏,人物移动,学VC、编游戏中的示例,它的实现,靠的是以下知识和技术:   1.建立DirectX环境和创建工作页面的方法。   2.各种页面内容的拷贝方法。   3.GDI与DirectX图形处理方法的简单比较。   游戏测试操作方法:   A、在场景内点任意点,指挥主角移动。   B、将鼠标移到场景外,可以移动地图。   C、在微缩地图上点一下,可以快速定位。   D、ESC键,退出游戏。   你可以指挥主角去打猎了。但打不死的,因为这里我们还没有加对象的生命值。      部分代码:   #define MAXINT 8192 //定义一个最大整数, 地图上任意两点距离不会超过它8192   #define STACKSIZE 38536 //保存搜索节点的堆栈大小65536   #define tile_num(x,y) ((y)*map_w+(x)) //将 x,y 坐标转换为地图上块的编号   #define tile_x(n) ((n)%map_w) //由块编号得出 x,y 坐标   char map[WIDTH*SCRP/GX+2][HEIGHT*SCRP/GY+2];//地图障碍格数据    int map_w,map_h;//地图障碍格宽和高    int start_x,start_y,end_x,end_y; //起点坐标,终点坐标    PATHN pathn[500];//重组路径    int findpath();//路径寻找主函数    int stackmax;//最大值    private://私有,类内部使用    LINK queue;//保存没有处理的行走方法的节点    TREE stack[STACKSIZE]; //保存已经处理过的节点(搜索完后释放)    int dis_map[WIDTH*SCRP/GX+2][HEIGHT*SCRP/GY+2];//保存搜索路径时,中间目标地最优解    void init_queue();// 初始化队列    void enter_queue(TREE node,int f);//待处理节点入队列,依靠对目的地估价距离插入排序    TREE get_from_queue(); //将离目的地估计最近的方案出队列    void freetree();//释放申请过的所有节点    int judge(int x,int y);//估价函数,估价x,y到目的地的距离,估计值必须保证比实际值小    int trytile(int x,int y,TREE father);//尝试下一步移动到x,y可行否    int zlpath(); //重组路径
好的,下面是一个简单的打飞机小游戏代码示例,使用C++和SFML库实现。 ```c++ #include <SFML/Graphics.hpp> #include <SFML/Audio.hpp> #include <iostream> #include <vector> #include <cstdlib> #include <ctime> using namespace std; const int WINDOW_WIDTH = 800; const int WINDOW_HEIGHT = 600; const int PLAYER_SIZE = 50; const int PLAYER_SPEED = 10; const int PLAYER_LIVES = 3; const int BULLET_SIZE = 10; const int BULLET_SPEED = 20; const int ENEMY_SIZE = 50; const int ENEMY_SPEED = 5; const int ENEMY_SPAWN_TIME = 30; const int SCORE_POS_X = 10; const int SCORE_POS_Y = 10; const int GAME_OVER_POS_X = 200; const int GAME_OVER_POS_Y = 250; const string FONT_PATH = "font.ttf"; const string BACKGROUND_MUSIC_PATH = "music.ogg"; const string SHOOT_SOUND_PATH = "shoot.ogg"; const string EXPLOSION_SOUND_PATH = "explosion.ogg"; class Player { public: sf::RectangleShape shape; int lives; int score; Player() { shape.setSize(sf::Vector2f(PLAYER_SIZE, PLAYER_SIZE)); shape.setFillColor(sf::Color::White); shape.setOrigin(PLAYER_SIZE / 2, PLAYER_SIZE / 2); shape.setPosition(WINDOW_WIDTH / 2, WINDOW_HEIGHT - PLAYER_SIZE / 2); lives = PLAYER_LIVES; score = 0; } void moveLeft() { if (shape.getPosition().x > PLAYER_SIZE / 2) { shape.move(-PLAYER_SPEED, 0); } } void moveRight() { if (shape.getPosition().x < WINDOW_WIDTH - PLAYER_SIZE / 2) { shape.move(PLAYER_SPEED, 0); } } void moveUp() { if (shape.getPosition().y > PLAYER_SIZE / 2) { shape.move(0, -PLAYER_SPEED); } } void moveDown() { if (shape.getPosition().y < WINDOW_HEIGHT - PLAYER_SIZE / 2) { shape.move(0, PLAYER_SPEED); } } void shoot(vector<sf::CircleShape>& bullets, sf::Sound& shootSound) { bullets.push_back(sf::CircleShape(BULLET_SIZE)); bullets.back().setFillColor(sf::Color::Yellow); bullets.back().setOrigin(BULLET_SIZE / 2, BULLET_SIZE / 2); bullets.back().setPosition(shape.getPosition()); shootSound.play(); } void update(vector<sf::CircleShape>& bullets) { for (int i = 0; i < bullets.size(); i++) { if (bullets[i].getPosition().y < 0) { bullets.erase(bullets.begin() + i); i--; } else { bullets[i].move(0, -BULLET_SPEED); } } } }; class Enemy { public: sf::RectangleShape shape; Enemy() { shape.setSize(sf::Vector2f(ENEMY_SIZE, ENEMY_SIZE)); shape.setFillColor(sf::Color::Red); shape.setOrigin(ENEMY_SIZE / 2, ENEMY_SIZE / 2); shape.setPosition(rand() % WINDOW_WIDTH, -ENEMY_SIZE / 2); } void update() { shape.move(0, ENEMY_SPEED); } }; int main() { srand(time(NULL)); sf::RenderWindow window(sf::VideoMode(WINDOW_WIDTH, WINDOW_HEIGHT), "SFML Game"); window.setFramerateLimit(60); sf::Font font; if (!font.loadFromFile(FONT_PATH)) { cout << "Error loading font" << endl; return -1; } sf::Text scoreText; scoreText.setFont(font); scoreText.setCharacterSize(30); scoreText.setFillColor(sf::Color::White); scoreText.setPosition(SCORE_POS_X, SCORE_POS_Y); sf::Text gameOverText; gameOverText.setFont(font); gameOverText.setCharacterSize(50); gameOverText.setFillColor(sf::Color::White); gameOverText.setPosition(GAME_OVER_POS_X, GAME_OVER_POS_Y); gameOverText.setString("GAME OVER"); sf::Music backgroundMusic; if (!backgroundMusic.openFromFile(BACKGROUND_MUSIC_PATH)) { cout << "Error loading music" << endl; return -1; } backgroundMusic.setVolume(50); backgroundMusic.setLoop(true); backgroundMusic.play(); sf::SoundBuffer shootBuffer; if (!shootBuffer.loadFromFile(SHOOT_SOUND_PATH)) { cout << "Error loading sound" << endl; return -1; } sf::Sound shootSound(shootBuffer); sf::SoundBuffer explosionBuffer; if (!explosionBuffer.loadFromFile(EXPLOSION_SOUND_PATH)) { cout << "Error loading sound" << endl; return -1; } sf::Sound explosionSound(explosionBuffer); Player player; vector<sf::CircleShape> bullets; vector<Enemy> enemies; int enemySpawnTimer = ENEMY_SPAWN_TIME; while (window.isOpen()) { sf::Event event; while (window.pollEvent(event)) { if (event.type == sf::Event::Closed) { window.close(); } } if (player.lives > 0) { if (sf::Keyboard::isKeyPressed(sf::Keyboard::Left)) { player.moveLeft(); } if (sf::Keyboard::isKeyPressed(sf::Keyboard::Right)) { player.moveRight(); } if (sf::Keyboard::isKeyPressed(sf::Keyboard::Up)) { player.moveUp(); } if (sf::Keyboard::isKeyPressed(sf::Keyboard::Down)) { player.moveDown(); } if (sf::Keyboard::isKeyPressed(sf::Keyboard::Space)) { player.shoot(bullets, shootSound); } player.update(bullets); if (enemySpawnTimer > 0) { enemySpawnTimer--; } else { enemies.push_back(Enemy()); enemySpawnTimer = ENEMY_SPAWN_TIME; } for (int i = 0; i < enemies.size(); i++) { enemies[i].update(); if (enemies[i].shape.getGlobalBounds().intersects(player.shape.getGlobalBounds())) { explosionSound.play(); enemies.erase(enemies.begin() + i); i--; player.lives--; } else { for (int j = 0; j < bullets.size(); j++) { if (enemies[i].shape.getGlobalBounds().intersects(bullets[j].getGlobalBounds())) { explosionSound.play(); enemies.erase(enemies.begin() + i); i--; bullets.erase(bullets.begin() + j); j--; player.score++; } } } } scoreText.setString("Score: " + to_string(player.score) + "\nLives: " + to_string(player.lives)); } window.clear(); for (int i = 0; i < bullets.size(); i++) { window.draw(bullets[i]); } for (int i = 0; i < enemies.size(); i++) { window.draw(enemies[i].shape); } window.draw(player.shape); window.draw(scoreText); if (player.lives <= 0) { window.draw(gameOverText); } window.display(); } return 0; } ``` 这个代码示例使用了SFML库来创建窗口和处理用户输入,同时实现了玩家、子弹和敌机的移动和碰撞检测,以及游戏得分和生命值的显示,还有背景音乐和音效的播放。你可以根据自己的需要和喜好修改代码并添加更多功能。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值