注意:

本文为前文 再探 游戏 《 2048 》 —— AI方法—— 缘起、缘灭(1) —— Firefox浏览器自动运行篇 接续篇。

===========================================

下面给出在  鬼&泣 / 2048-ai   中对游戏环境的设计。

游戏环境的文件:

cpp_source/enviroment/2048_enviroment.cpp · 鬼&泣/2048-ai - Gitee.com

========================================

核心函数:

void init_tables()

static inline board_t transpose(board_t x)

static int count_empty(board_t x)
static inline board_t execute_move_0(board_t board)
static inline board_t execute_move_1(board_t board)
static inline board_t execute_move_2(board_t board)
static inline board_t execute_move_3(board_t board)

主要函数:

static board_t draw_tile()
 
static board_t insert_tile_rand(board_t board, board_t tile)
 
static board_t initial_board()
 
static float score_board(board_t board)
 
static float score_helper(board_t board, const float* table)
 

==================================================

void init_tables()  函数:

void init_tables() {
for (unsigned row = 0; row < 65536; ++row) {
unsigned line[4] = {
(row >> 0) & 0xf,
(row >> 4) & 0xf,
(row >> 8) & 0xf,
(row >> 12) & 0xf
}; // Score
float score = 0.0f;
for (int i = 0; i < 4; ++i) {
int rank = line[i];
if (rank >= 2) {
// the score is the total sum of the tile and all intermediate merged tiles
score += (rank - 1) * (1 << rank);
}
}
score_table[row] = score; // execute a move to the left
for (int i = 0; i < 3; ++i) {
int j;
for (j = i + 1; j < 4; ++j) {
if (line[j] != 0) break;
}
if (j == 4) break; // no more tiles to the right if (line[i] == 0) {
line[i] = line[j];
line[j] = 0;
i--; // retry this entry
} else if (line[i] == line[j]) {
if(line[i] != 0xf) {
/* Pretend that 32768 + 32768 = 32768 (representational limit). */
line[i]++;
}
line[j] = 0;
}
} row_t result = (line[0] << 0) |
(line[1] << 4) |
(line[2] << 8) |
(line[3] << 12);
row_t rev_result = reverse_row(result);
unsigned rev_row = reverse_row(row); row_left_table [ row] = row ^ result;
row_right_table[rev_row] = rev_row ^ rev_result;
col_up_table [ row] = unpack_col( row) ^ unpack_col( result);
col_down_table [rev_row] = unpack_col(rev_row) ^ unpack_col(rev_result);
}
}

游戏环境对一个游戏状态采用一个64bit长度的整数来进行表示,可以看到一个游戏状态包括16个数字,每个数字用4bit来表示,正好是16*4bit=64bit 。

由于一个格是用4bit来进行表示,那么可以表示的数字为0~15,这里分别用0~15表示0,2**1,2**2,2**3,......,2**15 。

每个格最大可以表示的数值为:

游戏状态中一行数据为4格数字,每个格数字用4bit表示(每个格可以表示的数字为0~15),一行数据用16bit表示,那么一行数据共有2**16种表示,即 65536 。

在函数  init_tables()   中遍历所有可表示状态:

在2048游戏中每一步可以获得一定的得分,该得分是根据该步骤操作可以获得的新数字的大小来计算的,比如将两个2合并为一个4,那么得分就是4;如果把两个8合并为一个16,那么得分就是16。但是需要注意的是游戏自动生成的新块是不进行得分计算的。因此在2048游戏中一个游戏状态在得知整个游戏过程中自动生成的4数字块的个数就可以根据此时的游戏状态计算出此时的游戏得分。在整个游戏过程中计数共自动生成了多少4数字块,scorepenalty 变量为生成的4数字块个数乘以得分4,具体实现为在每一步新块生成时如果是 4则自动为scorepenalty 变量加 4。

计算游戏状态的得分时我们分别根据不同行对应的的得分(score_table中的值)的和再减去 scorepenalty 变量即可。

从上代码可知,每行数据用数组line表示,从左向右分别为:line[0],line[1],line[2],line[3]。

每行数据向左移动的话生成的新的行数据可以如此计算:

需要注意的是在这里我们默认32768为最大表示数字,也就是说两个32768合并得到依然是32768 。

/* Pretend that 32768 + 32768 = 32768 (representational limit). */

得到的新的行数据用64bit来表示:

由于行数据的左移动所得的新行数据等价于原行数据左右调换后的行数据的右移动所得的新行数据,给出下面计算:

也就是说行数据row左移动得到result,row数据的左右调换后的rev_row的右移动得到rev_result数据。

需要注意的一个问题是由于在打印游戏状态时代码:

也就是说计算机中对游戏状态的表示和打印给人看到的状态表示其实是上下互相调换,左右也互相调换的。

=========================================

再探 游戏 《 2048 》 —— AI方法—— 缘起、缘灭(2) —— 游戏环境设计篇的更多相关文章

  1. 跟k8s工作负载Deployments的缘起缘灭

    跟k8s工作负载Deployments的缘起缘灭 考点之简单介绍一下什么是Deployments吧? 考点之怎么查看 Deployment 上线状态? 考点之集群中能不能设置多个Deployments ...

  2. 再探JS数组原生方法—没想到你是这样的数组

    最近作死又去做了一遍javascript-puzzlers上的44道变态题,这些题号称"JS语言专业八级"的水准,建议可以去试试,这里我不去解析这44道题了, ...

  3. 2048游戏分析、讨论与扩展 - Part I - 游戏分析与讨论

    2048这个游戏从刚出開始就风靡整个世界. 本技术博客的目的是想对2048涉及到相关的全部问题进行仔细的分析与讨论,得到一些大家能够接受而且理解的结果. 在这基础上,扩展2048的游戏性,使其变得更好 ...

  4. Android 带你玩转实现游戏2048 其实2048只是个普通的控件(转)

    1.概述 博主本想踏入游戏开放行业,无奈水太深,不会游泳:于是乎,只能继续开发应用,但是原生Android也能开发游戏么,2048.像素鸟.别踩什么来着:今天给大家带来一篇2048的开发篇,别怕不分上 ...

  5. Android 带你玩转实现游戏2048 其实2048只是个普通的控件

    转载请标明出处:http://blog.csdn.net/lmj623565791/article/details/40020137,本文出自:[张鸿洋的博客] 1.概述 博主本想踏入游戏开放行业,无 ...

  6. 制作 2D 素材|基于 AI 5 天创建一个农场游戏,第 4 天

    欢迎使用 AI 进行游戏开发! 在本系列中,我们将使用 AI 工具在 5 天内创建一个功能完备的农场游戏.到本系列结束时,您将了解到如何将多种 AI 工具整合到游戏开发流程中.本系列文章将向您展示如何 ...

  7. ChatGPT 设计游戏剧情 | 基于 AI 5 天创建一个农场游戏,完结篇!

    欢迎使用 AI 进行游戏开发! 在本系列中,我们将使用 AI 工具在 5 天内创建一个功能完备的农场游戏.到本系列结束时,您将了解到如何将多种 AI 工具整合到游戏开发流程中.本文将向您展示如何将 A ...

  8. 【再探backbone 02】集合-Collection

    前言 昨天我们一起学习了backbone的model,我个人对backbone的熟悉程度提高了,但是也发现一个严重的问题!!! 我平时压根没有用到model这块的东西,事实上我只用到了view,所以昨 ...

  9. 再探jQuery

    再探jQuery 前言:在使用jQuery的时候发现一些知识点记得并不牢固,因此希望通过总结知识点加深对jQuery的应用,也希望和各位博友共同分享. jQuery是一个JavaScript库,它极大 ...

  10. [老老实实学WCF] 第五篇 再探通信--ClientBase

    老老实实学WCF 第五篇 再探通信--ClientBase 在上一篇中,我们抛开了服务引用和元数据交换,在客户端中手动添加了元数据代码,并利用通道工厂ChannelFactory<>类创 ...

随机推荐

  1. Spring扩展——@Import注解

    引言 在Spring中有许多Enable开头的注解,比如以下常见注解 @EnableTransactionManagement @EanbleAsync @EnableCache @EnableAsp ...

  2. SingletonKit单例源码阅读学习

    阅读学习QFramwork中的SingletonKit源码. Singleton 普通类的单例 作为最常用的单例模块,通过继承单例泛型类来实现,需要私有构造: //使用第一种接口单例方式 intern ...

  3. windows server 安装.net framework 3.5失败

    windows server如果高版本的.net framework 那么在安装.net framework3.5时会提示已安装高版本的不能安装低版本的了 ---------------------- ...

  4. unity Entitas框架简介

    插件及文档:https://github.com/sschmid/Entitas-CSharp/wiki/Home 资料: https://zhuanlan.zhihu.com/p/78155704 ...

  5. 硬件开发笔记(二十):AD21导入外部下载的元器件原理图库、封装库和3D模型

    前言   在硬件设计的过程中,会遇到一些元器件,这些元器件在本地已有的库里面没有,但是可以从外部下载或者获取到对应的.  本篇就是引入TPS54331D电源芯片作为示例,详细描述整个过程.   创建T ...

  6. 我写CSS的常用套路(附demo的效果实现与源码)

    大赞: https://mp.weixin.qq.com/s/dYCWYeM629DwiSqmaaAs1w

  7. /etc/shadow文件破解,密码破解,md5,SHA256,SHA512破解

    环境 Kali系统 John the Ripper密码破解者 shadow文件解析 文件的格式为: {用户名}:{加密后的口令密码}:{口令最后修改时间距原点(1970-1-1)的天数}:{口令最小修 ...

  8. 为ssh服务器添加2fa认证,一个python脚本全搞定

    服务器ssh如果被别人登陆就是一场灾难,所以我研究了ssh认证,我发现Google Authenticator PAM可以实现ssh的2fa认证,但是安装和配置比较麻烦.因此我用python实现了ss ...

  9. C# pythonnet(2)_FFT傅里叶变换

    Python代码如下 import pandas as pd import numpy as np import matplotlib.pyplot as plt # 读取数据 data = pd.r ...

  10. Mybatis 中 foreach 的四种用法

    foreach的主要用在构建in条件中,它可以在SQL语句中进行迭代一个集合. foreach元素的属性主要有 item,index,collection,open,separator,close. ...