注意:

本文为前文 再探 游戏 《 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. 你唯一需要的是“Wide Events”,而非“Metrics、Logs、Traces”

    Charity Majors 的这句话可能是对科技行业当前可观察性状态的最好总结--完全的.大规模的混乱.大家都很困惑.什么是 trace?什么是 span?一行日志就是一个 span 吗?如果我有日 ...

  2. 夜莺项目发布 v6.4.0 版本,新增全局宏变量功能

    大家好,夜莺项目发布 v6.4.0 版本,新增全局宏变量功能,本文为大家简要介绍一下相关更新内容. 全局宏变量功能 像 SMTP 的配置中密码类型的信息,之前都是以明文的方式在页面展示,夜莺支持全局宏 ...

  3. requests高级操作

    requests的Cookie处理 有时相关的需求会让我们去爬取基于某些用户的相关用户信息,例如爬取张三人人网账户中的个人身份信息.好友账号信息等. 那么这个时候,我们就需要对当前用户进行登录操作,登 ...

  4. 2个线程交替输出A1B2C3......Z26

    引言 经典多线程编程面试题 使用两个线程交替输出A1B2C3......Z26 实现方案1 public static void method2() throws InterruptedExcepti ...

  5. Exception:kylin构建cube, Cannot modify mapReduce.queue.name at runtime

    Failed to open new session: java.lang.IllegalArgumentException: Cannot modify tez.queue.name at runt ...

  6. centos8使用nmcli实现bond

    #添加bonding接口 nmcli con add type bond con-name bond0 ifname bond0 mode active-backup ipv4.method manu ...

  7. iOS:长图切割并转为动画gif——精灵表单sprite Sheet的转化

    iOS:长图切割并转为动画gif--精灵表单sprite Sheet的转化 通常的,iOS显示gif可以将文件转为NSData后再对其进行解析,通过CADisplayLink逐帧进行提取.播放,判断N ...

  8. R语言遍历文件夹求取其中所有栅格文件的平均值

      本文介绍基于R语言中的raster包,遍历读取多个文件夹下的多张栅格遥感影像,分别批量对每一个文件夹中的多个栅格图像计算平均值,并将所得各个结果栅格分别加以保存的方法.   其中,本文是用R语言来 ...

  9. 背包dp——01背包

    01背包是背包dp的基础的重点,重点的基础!!! 题意概要:有 n 个物品和一个容量为 W 的背包,每个物品有重量 w_{i} 和价值 v_{i} 两种属性,要求选若干物品放入背包使背包中物品的总价值 ...

  10. 【AppStore】一文让你学会IOS应用上架Appstore

    前言 咱们国内现在手机分为两类,Android手机与苹果手机,现在用的各类APP,为了手机的使用安全,避免下载到病毒软件,官方都极力推荐使用手机自带的应用商城进行下载,但是国内Android手机品类众 ...