使用Tableau制作扫雷游戏和三维地图
一种利用低代码可视化工具处理复杂逻辑的有益尝试。
可视化作品的复杂度无外乎两种:
模型处理层的复杂度 和 可视化设计层的复杂度
模型处理层的复杂度
当计算逻辑异常复杂,无法直接通过线性计算获取计算结果时,需要将计算逻辑下层至模型层,将需要的数据通过数据库语言,算法,程序,建模工具等各种手段预先处理好,保存为结果表,可视化工具直接读取结果表数据,提高图形展示的速度。这里的难点在于如何设计能给到前端使用的结果表以及前端如何去使用它,数据如何进行定时或实时地调取以及运维人员对数据结构含义以及处理过程的监控、把握。
可视化设计层的复杂度
为了展示复杂的图形和复杂的图形交互联动功能,而且在对数据的实时性要求较高的情形下,处理逻辑需要直接通过可视化工具进行。这里的难点在于需要对可视化工具的设计理念和图形控制逻辑有较深的认识,比如如何对原始表进行关联,如何设计合理必要的计算公式,以及如何控制图形的形状。图形越复杂,处理速度必然越慢,对可视化工具能力要求越高。如果需求方对产品的能力边界认识不清,仅仅是因为自己想要而提需求,必然因为产品功能无法满足而导致失败告终。
总之,低代码可视化工具的目标并不是为了为了设计如何复杂炫酷的图形,而是为了敏捷地响应数据变化,快速展示分析数据价值。
这篇文章分别介绍这两种复杂度对应的作品。
模型处理层的复杂度
利用Tableau强大的联动筛选特性并结合MySQL实时查询来制作扫雷游戏。
效果图展示
需要解决的关键问题是
1.如何按照指定概率进行随机布雷,并且在Tableau中展示出来
2.如何在点击之后对棋盘进行过滤
两种方法:1,通过Tableau编写计算字段和筛选器进行过滤(无法进行递归和循环计算,此方法不可行)
2.利用Mysql函数将需要批量翻开的格子进行标识,然后在Tableau中进行筛选
MYSQL函数minesearch,批量翻开地雷的核心代码
对当前的位置之前已识别的可批量翻开的分类编码串进行处理,获取当前位置识别后的可批量翻开的分类编码串,将判断逻辑下层至数据库,简化Tableau筛选逻辑, 通过筛选上层工作表的矩形来实现批量扫雷的动作。
CREATE DEFINER=`root`@`localhost` FUNCTION `minesearch`(`row` int,`column` int,saftgrid text,markergrid text) RETURNS text CHARSET utf8 COLLATE utf8_bin
BEGIN
declare replaceid char default 'P';
declare oldid char default '';
declare areaidset text default '△▽○◇□☆▷◁♤♡♢♧▲▼●◆■★▶◀♠♥♦♣☼☽♀☺◐☑√✔☜☝☞☀♂☾☹◑☒✘☚☟☛♩♪♫♬§〼◎¤¶卍卐▬〓☌☍☋☊㉿◮◪◔◕♈♉♊♋♌♎♏♐♑♓♒♍※▨▤▧☯✲❈❉✿❀❃❁☸✖✚✪❤ღ❦❧ி₪✎✍✌✁✄☁☂☃☄♨☇☈☡➷⊹✉☏☢☣☠☭❂☪☮〄➹☩ஐ☎✈〠۩✙✟☤☥☦☧☨☫☬♟♙♜♖♞♘♝♗♛♕♚♔҉͜℘ೄζั͡ตԅ️✾೨Ͽೃيℳ༺๑༻დ﹏এృةʚΐɞﻬ๓༒⁂⁎⁑✢✣✤✥✱✳✴✵✶✷✸✹✺✻✼✽❇❊❋ۣლ࿈༽༾ཊཏ༿༼ൢཌ༈ད•€™↑→↓⇝∞☉☐☻✓✝✞✠✡✦✧✩✮✯❄❅❆❝❞❣❥✛✜ϟ♁۞✫✬✭✰';if substring(saftgrid,(`row`-1)*16+`column`,1) = '1' thenif substring(markergrid,(`row`-1)*16+`column`,1) = '0' then-- SET replaceid = CAST(CHAR(areaid) AS char) ;SET replaceid = substring(areaidset,(`row`-1)*16+`column`,1);elseSET replaceid = substring(markergrid,(`row`-1)*16+`column`,1);end if;-- 将周围标记SET markergrid = INSERT(markergrid, (`row`-1)*16+`column`, 1, replaceid) ;if `column` > 1 thenset oldid = substring(markergrid,(`row`-1)*16+`column`-1,1);if oldid = '0' thenSET markergrid = INSERT(markergrid, (`row`-1)*16+`column`-1, 1, replaceid) ;elseif oldid != replaceid thenSET markergrid = replace(markergrid,oldid,replaceid);end if;end if;if `column`<16 thenset oldid = substring(markergrid,(`row`-1)*16+`column`+1,1);if oldid = '0' thenSET markergrid = INSERT(markergrid, (`row`-1)*16+`column`+1, 1, replaceid) ;elseif oldid != replaceid thenSET markergrid = replace(markergrid,oldid,replaceid);end if;end if;if `row`>1 thenset oldid = substring(markergrid,(`row`-2)*16+`column`,1);if oldid = '0' thenSET markergrid = INSERT(markergrid, (`row`-2)*16+`column`, 1, replaceid) ;elseif oldid != replaceid thenSET markergrid = replace(markergrid,oldid,replaceid);end if;if `column` > 1 thenset oldid = substring(markergrid,(`row`-2)*16+`column`-1,1);if oldid = '0' thenSET markergrid = INSERT(markergrid, (`row`-2)*16+`column`-1, 1, replaceid) ;elseif oldid != replaceid thenSET markergrid = replace(markergrid,oldid,replaceid);end if;end if;if `column`<16 thenset oldid = substring(markergrid,(`row`-2)*16+`column`+1,1);if oldid = '0' thenSET markergrid = INSERT(markergrid, (`row`-2)*16+`column`+1, 1, replaceid) ;elseif oldid != replaceid thenSET markergrid = replace(markergrid,oldid,replaceid);end if;end if;end if;if `row` < 16 thenset oldid = substring(markergrid,(`row`)*16+`column`,1);if oldid = '0' thenSET markergrid = INSERT(markergrid, (`row`)*16+`column`, 1, replaceid) ;elseif oldid != replaceid thenSET markergrid = replace(markergrid,oldid,replaceid);end if;if `column` > 1 thenset oldid = substring(markergrid,(`row`)*16+`column`-1,1);if oldid = '0' thenSET markergrid = INSERT(markergrid, (`row`)*16+`column`-1, 1, replaceid) ;elseif oldid != replaceid thenSET markergrid = replace(markergrid,oldid,replaceid);end if;end if;if `column`<16 thenset oldid = substring(markergrid,(`row`)*16+`column`+1,1);if oldid = '0' thenSET markergrid = INSERT(markergrid, (`row`)*16+`column`+1, 1, replaceid) ;elseif oldid != replaceid thenSET markergrid = replace(markergrid,oldid,replaceid);end if;end if;end if;RETURN markergrid;
elseRETURN markergrid;
end if;
END
调用以上自定义函数,生成扫雷必要的底层数据并存表,用于构建Tableau扫雷图形的骨架,并记录地雷的分布,周围的雷数,批量可翻开标识ID等字段信息。
MYSQL函数rand_01_string,随机布雷和辅助计算的核心代码
CREATE DEFINER=`root`@`localhost` FUNCTION `rand_01_string`(length INT,rate double,needUpdate bool) RETURNS text CHARSET utf8
BEGINDECLARE chars_str varchar(255) DEFAULT '01';DECLARE return_str text DEFAULT '';declare mark_str text default '';DECLARE i INT DEFAULT 0;DECLARE j INT DEFAULT 0;DECLARE minecount INT DEFAULT 0;if needUpdate then-- 在sqrt(length)*sqrt(length)的区域内随机布雷,概率为rateWHILE i < length DOSET return_str = concat(return_str,substring(chars_str , case when RAND()<rate then 2 else 1 end,1));SET i = i + 1;END WHILE;delete from minenumber where userid = 'cp';WHILE j < sqrt(length) DOSET i = 0;WHILE i < sqrt(length) DOINSERT into minenumber(`userid`,`id`,`row`,`column`,`hasmine`) VALUES('cp',i*sqrt(length)+j+1,i+1,j+1,substring(return_str,i*sqrt(length)+j+1,1) = '1');SET i = i + 1;END WHILE;SET j = j + 1;END WHILE;-- 计算每一个位置周围的雷数,并更新底表set i = 0;set j = 0;WHILE j < sqrt(length) DOSET i = 0;WHILE i < sqrt(length) DOselect sum(hasmine) into minecount from minenumber where `row` between i and i + 2and `column` between j and j + 2and `userid` = 'cp';UPDATE minenumber SET minecount = minecount where `row` = i + 1and `column` = j+1 and `userid` = 'cp';SET i = i + 1;END WHILE;SET j = j + 1;END WHILE;-- 对整块安全区域进行ID划分,增加ID标识,方便Tableau过滤set mark_str = (select `t`.`markergrid`from (select `a`.`id`,`a`.`row`,`a`.`column`,@`markergrid` := `minesearch`(`a`.`row`,`a`.`column`,`b`.`saftgrid`,@`markergrid`) as `markergrid`from `minenumber` as `a` cross join(select group_concat(if(`minenumber`.`minecount` = 0,'1','0') order by `id` SEPARATOR '') as `saftgrid`,@`markergrid`:= (repeat('0',256))from `minenumber`) as `b`order by `a`.`id`) `t` where `t`.`id` = 256); -- 更新抬头delete from mineswap where `userid` = 'cp';insert into mineswap values('cp',sqrt(length),return_str,mark_str);-- 更新明细表UPDATE minenumber SET areaid = substring(mark_str,(`row`-1)*16+`column`,1)where `userid` = 'cp';elseselect minecode into return_str from mineswap limit 1;end if;RETURN return_str;
END
Tableau调用编写自定义SQL。这里只调用了一个自定义函数,将Tableau参数传递给MySQL函数,触发底层是查询数据还是更新底层雷盘数据后再查询数据。
底表生成的数据
抬头表
其中
userid代表当前用户,
minecode记录每一个位置是否有雷的信息,1代表有雷,0代表无雷
saftcode记录是否可以批量翻开的ID类别,如果不能批量翻开,则记为0
明细表
用于构建Tableau扫雷的骨架,以及提前存储必要的计算字段
其中userid代表当前用户,
id唯一编号
row 行号
column列号
hasmine该位置是否有雷,Mysql函数中随机生成
-- 在sqrt(length)*sqrt(length)的区域内随机布雷,概率为rateWHILE i < length DOSET return_str = concat(return_str,substring(chars_str , case when RAND()<rate then 2 else 1 end,1));SET i = i + 1;END WHILE;
isopened 游戏过程字段,该位置是否已经翻开(Tableau通过集操作和参数可以记录历史操作数据,因此该字段没用到)
minecount 该位置周围的雷数,在Mysql函数中计算得出
set i = 0;set j = 0;WHILE j < sqrt(length) DOSET i = 0;WHILE i < sqrt(length) DOselect sum(hasmine) into minecount from minenumber where `row` between i and i + 2and `column` between j and j + 2and `userid` = 'cp';UPDATE minenumber SET minecount = minecount where `row` = i + 1and `column` = j+1 and `userid` = 'cp';SET i = i + 1;END WHILE;SET j = j + 1;END WHILE;
saftcode记录是否可以批量翻开的ID类别,如果不能批量翻开,则记为0
此部分计算逻辑较为复杂,Mysql函数也无法递归调用,使用字符串进行处理,
1.依次判断当前位置是否有雷,如果有雷,则将该位置周围9个格子记录一个唯一编号
2.如果周围8个格子任何一个格子已经被记录,则判断当前编号与周围编号是否相同,如果不同,则将当前位置的编号唯一字符ID替换掉码串中所有编码符等于周围的编号符,通过字符串替换实现递归的逻辑,通过Mysql变量记录每一次替换的结果码串。
3.SQL执行完后,将最后一次替换的码串取出
Tableau自定义SQL数据源
Tableau翻雷报表制作
计算字段
选中后将该字段传给参数,记录历史翻开操作
下层工作表
自定义形状
记录地雷位置和可批量翻开的字符ID工作表
扫雷的完成度工作表
重置按钮,将选中集清空,更新筛选器值
更新状态参数
扫雷完成度占比,全局联动,动态更新
可视化设计层的复杂度
另外一种使用Tableau工具开发的3维地图展示,以后有时间做详细教程。
球形变换与筛选器控制
中国地图经纬度数据映射到3D球面
月球地图着色与观察者视角
观察者视角多边形筛选器控制
观察者视角变换与坐标系变换
使用Tableau制作扫雷游戏和三维地图相关推荐
- ESMap平台如何制作多楼层室内三维地图-易景空间地图
随着三维可视化技术和空间定位数据技术的不断发展,三维地图呈现已经不断成熟,特别是在智慧园区.智慧工业.智慧能源.智慧商城等领域,三维地图的应用场景得到了进一步的发展.易景空间的ESMap平台利用地图编 ...
- java制作扫雷游戏中埋雷的难点_Java 实现经典扫雷游戏
最后一次更新于 2019/07/08 效果演示图 Java 实现经典扫雷游戏 本扫雷游戏有以下功能: 如果点中炸弹会显示炸弹. 玩家左键点击方块能显示该方块周围会出现几个炸弹,如果不存在炸弹的话扫描范 ...
- 用纯JavaScript制作扫雷游戏-2
网页扫雷游戏 - part 2
- 小心踩雷!手把手教你制作扫雷游戏简单版本
扫雷游戏----C语言必写游戏之一 扫雷游戏 背景 起源与玩法 基本实现思路 涉及语言的主要内容 具体实现步骤 1.基本框架 2.菜单页面的实现 3.初始化棋盘 4.在屏幕中显示棋盘 5.布置好棋盘中 ...
- java制作扫雷游戏中埋雷的难点_月薪30K程序员花了一个小时,用c++做出经典扫雷游戏 !...
上次发过一个俄罗斯方块的游戏源码,由于是通过Easy X实现的,但是很多和我一样的新手,一开始不知道Easy X是什么,到时源码拿过去之后,运行报错,我这次发的扫雷, 也是通过Easy X实现,Eas ...
- vue学习,制作扫雷游戏
文章目录 准备工作 引入vue.js html.css 游戏完整代码(附详细注释) 运行效果图 准备工作 引入vue.js <!-- cdn方式,调用vue的官方js --> <sc ...
- Unity制作扫雷游戏
曾经在网上看了一篇扫雷教程,链接如下:https://noobtuts.com/unity/2d-minesweeper-game 但是照着做出来有点问题,后来自己尝试的做了一个,效果如图: 主要有三 ...
- java制作扫雷游戏中埋雷的难点_java 扫雷游戏源码案例项目
代码如下import java.awt.*;import javax.swing.*;//图形计数器JCounter三位class JCounter extends JPanel { p ...
- javaScript开发扫雷游戏
前言 扫雷是windows自带的游戏,通过翻开小方块,来推理雷的位置 本文讲解如何通过javaScript制作扫雷游戏,并运用canvas画布绘制windows扫雷效果 一.技术拆分 canvas画图 ...
最新文章
- LNMP--Nginx的日志切割
- Android实现一个自己定义相机的界面
- python汉诺塔用循环结构实现_Python基于递归算法实现的汉诺塔与Fibonacci数列
- 如何让一个对话框全屏对话框
- mongodb save和insert区别
- mongo快速翻页方法(转载)
- pandas 非聚合函数
- 使用代码更新 UIVersion 属性
- spring cloud微服务分布式云架构-整合企业架构的技术点
- elementui中给input框赋值成功后input框不能进行编辑问题
- 解决过拟合现象的六种姿势
- 循序渐进之Spring AOP(1) - 原理
- [热门]Android系统特质 不需要太多剩余内存
- hawk物联网组态工具_物联网web组态网关在智慧农业中的应用
- 金蝶k3服务器物理内存过高,金蝶k3提示超出内存解决方案
- 服务器开发系列(二)——Jetson Xavier NX
- Ubuntu18.04设置在开机时自动链接蓝牙键盘
- 【脑电数据处理】electrophysiology and EEG(AP\LFP\ECoG\EEG)
- Vue tsx 使用自定义v-model修饰符
- 开票系统导出的OFD文档如何转换PDF格式?
热门文章
- 让机器人解惑传道,对话式AI能否为企业带来巨量的业务?
- [攻略行空]静谧的斑斓——舒兰红叶谷
- Ubuntu-16.04 Media change: please insert the disc labeled 的解决办法
- python成语接龙代码_eoLinker-API_Shop_成语大全_API接口_Python调用示例代码
- star ccm java api_Star CCM+使用Java宏实现批处理.doc
- Houdini2:软件设置
- Windows下载及安装TexLive(简单有效)
- 2016年北京中国云计算技术大会会后感
- 如何将文件上传到GitHub仓库-操作简述
- matlab最炫名族风,matlab版 “最炫民族风” --- 跟风之作