注意:

本文为前文 再探 游戏 《 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. OpenCompass 作业

    Smiling & Weeping ---- 愿我们都做生活的高手 -- 昭阳&乐瑶

  2. UE 5 NavMesh 烘培 逻辑流程

      关于UE引擎层面的东西: 在向场景重拖入一个NavMeshBoundsVolume时(或者修改时). 会调用 void UNavigationSystemV1::PerformNavigation ...

  3. Spark Structured Streaming(二)实战

    5. 实战Structured Streaming 5.1. Static版本 先读一份static 数据: val static = spark.read.json("s3://xxx/d ...

  4. 基于附带Attention机制的seq2seq模型架构实现英译法的案例

    模型架构 先上图 我们这里选用GRU来实现该任务,因此上图的十个方框框都是GRU块,如第二张图,放第一张图主要是强调编码器的输出是作用在解码器每一次输入的观点,具体的详细流程图将在代码实现部分给出. ...

  5. 3568F-PCIe 5G通信测试手册

  6. Python脚本报错:DeprecationWarning: Using or importing the ABCs from 'collections' instead of from 'collections.abc' is deprecated since Python 3.3,and in 3.9 it will stop working import pymssql

    报错信息: monitor_mssql.py:10: DeprecationWarning: Using or importing the ABCs from 'collections' instea ...

  7. Java类全路径冲突解决方法

    1. 问题 今天在开发中遇到这样一个问题,A同事在导入了我们的实验SDK后,发现实验无法正常获取,查看日志发现了NoClassDefFoundError异常,无法加载的的类中逻辑比较简单,只依赖了另外 ...

  8. yb课堂之用户登陆校验拦截器开发 《十一》

    开发对应的登陆拦截器 开发loginInterceptor 登陆校验成功放行 登陆不成功返回json数据 LoginInterceptor.java package net.ybclass.onlin ...

  9. Quartus Ⅱ调用FIFO IP核方法实现求和(Mega Wizard)

    摘要:本次实验学习记录主题为"FIFO_IP核实现算术求和",主要内容是上位机通过串口向FPGA发送一定规格的数字矩阵,FPGA对矩阵处理,按规定逻辑实现求和运算,将结果返回串口转 ...

  10. 使用中台 Admin.Core 实现了一个Razor模板的通用代码生成器

    前言 前面使用 Admin.Core 的代码生成器生成了通用代码生成器的基础模块 分组,模板,项目,项目模型,项目字段的基础功能,本篇继续完善,实现最核心的模板生成功能,并提供生成预览及代码文件压缩下 ...