| 本帖最后由 脑的研发记录 于 2023-11-7 13:23 编辑 
 “数据结构课作业笔记”#004-数组-简单排列的变量和它们必然命运(下)
 
 所用编辑器版本0.25.0.4
 
 目录总览:
 零.再前情提要
 壹.第一个自由数组
 贰.所需语法 (代码如本节图示)
 叁.应用说明
 肆.相关参考链接 (返回主站)
 伍.专有名词的真相(类比之后,默认语境的调整,专业名词对照说明)
 陆.告一段落,回顾语
 
 
 零.再前情提要
 数组一次性赋值,实现了按计划传送。不过数组层面就只有读取数据,一切按既定计划进行。但是遇到临场变动,修改计划内容,想在第一次填充的数据的时候就可以符合新的需求就遇到了困难,代码报错说变量不存在,写入数据总是要一次性赋值然后再修改,精力消耗感觉大,膈应。这次补充数组的修改,完成第一个具有特殊身份的数组。
 壹.第一个自由数组
 不多说,上代码,新建脚本,复制粘贴跑就完事。
 
 
 interface see {
 a: number;
 check: Vector;
 }
 
 class seetest {
 public a: number;
 public check: Vector;
 }
 @Core.Class
 export default class add extends Core.Script {
 
 /** 当脚本被实例后,会在第一帧更新前调用此函数 */
 protected onStart(): void {
 
 
 // var arr_names:see[] = new Array(4)
 // var i = 0;
 // arr_names[0].a = 2
 // console.log(arr_names.a);
 // 日志提示警告:数组每一项的成员a不存在,而且也确实无法输出a。
 // 原因是see类型不是默认直接直接转化的类型,
 // 需要Array<see>类型转换,才能让数组识别
 
 
 // var arr_names: Array<see> = new Array(4)
 // var i = 0;
 // arr_names[0].a = 2
 // console.log(arr_names.a);
 // 日志依然提示警告:数组每一项的成员仍然不存在,而且也确实无法输出a。
 // 原因是see类型是interface类别的,不是默认直接直接转化的类型,
 // 需要Array<see>类型转换,才能让数组识别
 
 
 
 // var arr_names: Array<seetest> = new Array(4)
 // var i = 0;
 // var m = new seetest();
 // m.a = 1;
 // m.check = new Vector(100, 0, 0);
 // console.log("m=" + m.a);
 
 
 // arr_names[0] = m;
 // console.log(arr_names[0].a);
 
 
 var i = 0;
 var arr_names: Array<seetest> = new Array(6)
 for (i = 0; i < arr_names.length; i++) {
 arr_names[i]= new seetest();
 arr_names[i].a = i * 2;
 arr_names[i].check = new Vector(500 * i, 0, 300);
 console.log(arr_names[i].check.x)
 }
 i = 5;
 
 // arr_names[2].check = new Vector(100, 0, 1000);
 
 var chara: Gameplay.Character;
 setTimeout(() => {
 chara = Gameplay.getCurrentPlayer().character;
 chara.worldLocation = arr_names[i].check;
 var timer = setInterval(() => {
 if (i < 0) {
 // 如果i小于0,就清除定时器
 clearInterval(timer);
 
 }
 chara.worldLocation = arr_names[i].check;
 console.log(arr_names[i].check.x)
 console.log(i);
 i--;
 // 每500毫秒i减少1
 }, 500);
 }, 2000);
 
 }
 
 }
 
 
 
 数组不用预先一个一个敲数字进行赋值,实现了自动填充。然后再按新的计划控制角色闪现。
 绿色的大块字符是数组编写过程中遇到的bug,是在穷举到成功满足需求的之后才明白代码输出失败的问题。
 代码拆解
 
 
 对数组第一次赋值,人称“初始化”。
 
 var i = 0;
 var arr_names: Array<seetest> = new Array(6)
 for (i = 0; i < arr_names.length; i++) {
 arr_names[i]= new seetest();
 arr_names[i].a = i * 2;
 arr_names[i].check = new Vector(500 * i, 0, 300);
 console.log(arr_names[i].check.x)
 }
 
 
 先声明数组,类型是seetest, 长度是6
 
 然后数组的每一项都新建了一个seetest的新变量,
 每一项的名叫"a"的变量成员都存储了一个数字,
 每一项的名叫“check”的变量成员都存储了一个位置信息。
 然后打印每一项的位置信息的x坐标。
 
 
 这也是一种初始化,其实这俩都相当于产生铭牌,每个铭牌给一个房子。只不过下面的代码是先一下子产生所需的铭牌,然后再把铭牌挂到房子上
 
  var i = 0;
 
 // 产生6个铭牌
 var arr_names: Array<seetest> = new Array(6)
 
 // 对每一个铭牌分配一个seetest户型的房子
 for (i = 0; i < arr_names.length; i++) {
 arr_names[i]= new seetest();
 
 }
 
 // 每个铭牌指定的房子里安排进家具
 for(i=0;i<arr_names.length;i++){
 arr_names[i].a = i * 2;
 arr_names[i].check = new Vector(500 * i, 0, 300);
 console.log(arr_names[i].check.x)
 }
 
 
 
 
 这样之后,可以把用函数打包一些句子,变成这样,就可以实现存入数据,in一次就存入一项seetest格式的数据,in两次就存入两项seetest格式的数据。
 
 
 // 对每一个铭牌分配一个seetest户型的房子
 for (this.i = 0; this.i < this.arr_names.length; this.i++) {
 this.arr_names[this.i] = new seetest();
 }
 
 // 每个铭牌指定的房子里安排进家具
 for (this.i = 0; this.i < this.arr_names.length;) {
 this.in(new Vector(500 * this.i, 0, 300), this.i * 2);
 }
 
 
 
 其中的in函数样子如下
 
 public in(check: Vector, a: number) {
 this.arr_names[this.i].a = a
 this.arr_names[this.i].check = check;
 console.log(this.arr_names[this.i].check.x)
 this.i++;
 }
 
 
 
 然后想着输入已经打包了,封装一个输出,注意到代码
 
  var chara: Gameplay.Character;setTimeout(() => {
 chara = Gameplay.getCurrentPlayer().character;
 chara.worldLocation = arr_names[i].check;
 var timer = setInterval(() => {
 if (i < 0) {
 // 如果i小于0,就清除定时器
 clearInterval(timer);
 
 }
 chara.worldLocation = arr_names[i].check;
 console.log(arr_names[i].check.x)
 console.log(i);
 i--;
 // 每500毫秒i减少1
 }, 500);
 }, 2000);
 
 
 找不同,对小学生来说有点幼稚,对大学生来说刚刚好。
 
 
 var chara: Gameplay.Character;
 setTimeout(() => {
 chara = Gameplay.getCurrentPlayer().character;
 // chara.worldLocation = this.arr_names[this.i].check;
 chara.worldLocation = this.out().check;
 var timer = setInterval(() => {
 if (this.i < 0) {
 // 如果i小于0,就清除定时器
 clearInterval(timer);
 }
 
 // chara.worldLocation = this.arr_names[this.i].check;
 // console.log(this.arr_names[this.i].check.x)
 // console.log(this.i);
 // this.i--;
 // 每500毫秒i减少1
 
 
 
 // var c: seetest = new seetest();
 // c = this.out();
 // chara.worldLocation = c.check;
 // console.log(c.a);
 
 
 chara.worldLocation = this.out().check;
 
 
 
 }, 500);
 }, 2000);
 
 
 
 out 函数具体如下
 
 
 public out(): seetest {
 this.i--;
 var now: seetest = new seetest();
 now = this.arr_names[this.i];
 return now;
 }
 
 
 
 最后来一个代码全景,新建脚本,复制粘贴就能跑。
 最终成果
 
 
 class seetest {
 public a: number;
 public check: Vector;
 }
 
 
 @Core.Class
 export default class add extends Core.Script {
 
 public arr_names: Array<seetest> = new Array(6)
 public i: number = 0;
 
 /** 当脚本被实例后,会在第一帧更新前调用此函数 */
 protected onStart(): void {
 
 // 对每一个铭牌分配一个seetest户型的房子
 for (this.i = 0; this.i < this.arr_names.length; this.i++) {
 this.arr_names[this.i] = new seetest();
 }
 
 // 每个铭牌指定的房子里安排进家具
 for (this.i = 0; this.i < this.arr_names.length;) {
 this.in(new Vector(500 * this.i, 0, 300), this.i * 2);
 }
 
 var chara: Gameplay.Character;
 setTimeout(() => {
 chara = Gameplay.getCurrentPlayer().character;
 // chara.worldLocation = this.arr_names[this.i].check;
 chara.worldLocation = this.out().check;
 var timer = setInterval(() => {
 if (this.i < 0) {
 // 如果i小于0,就清除定时器
 clearInterval(timer);
 }
 
 chara.worldLocation = this.out().check;
 
 }, 500);
 }, 2000);
 
 }
 
 public in(check: Vector, a: number) {
 this.arr_names[this.i].a = a
 this.arr_names[this.i].check = check;
 console.log(this.arr_names[this.i].check.x)
 this.i++;
 }
 
 public out(): seetest {
 this.i--;
 var now: seetest = new seetest();
 now = this.arr_names[this.i];
 return now;
 }
 
 }
 
 
 
 对比前一节代码
 
 interface have {
 i: number;
 check: Vector;
 }
 // 说明一个数据类型,如代码所示,这个叫“have"的类型
 // 有一个叫“i“的变量,它的类型是numebr
 // 还有一个叫“check"的变量,它的类型是Vector
 
 @Core.Class
 export default class stack extends Core.Script {
 
 /** 当脚本被实例后,会在第一帧更新前调用此函数 */
 protected onStart(): void {
 var a: have[] = [
 { i: 0, check: new Vector(500, 0, 100) },
 { i: 1, check: new Vector(1000, 0, 100) },
 { i: 2, check: new Vector(1500, 0, 100) },
 { i: 3, check: new Vector(2000, 0, 100) },
 { i: 4, check: new Vector(2500, 0, 100) },
 { i: 5, check: new Vector(3000, 0, 200) }
 ];
 
 
 var i = 5;
 var chara: Gameplay.Character;
 setTimeout(() => {
 chara = Gameplay.getCurrentPlayer().character;
 chara.worldLocation = a[i].check;
 var timer = setInterval(() => {
 if (i < 0) {
 // 如果i小于0,就清除定时器
 clearInterval(timer);
 
 }
 chara.worldLocation = a[i].check;
 i--;
 // 每500毫秒i减少1
 }, 500);
 }, 2000);
 }
 }
 
 
 代码就着文案现写现改,总得来说分成两个部分:封装和解决封装遇到的报错。
 把i变量从里面提到外部,其他函数可以直接获取i,进行修改,原来传进参数修改的路线失败了。
 然后封装过程中,使用的数据seetest类型的改变,从interface到class,每个数据初始化都需要new 来执行分配空间。
 初始化数组的时候,数组也需要重新传入数据格式,传入数据格式的方法也变化了。
 其他就按照前节的代码手动输入。
 总得来说,代码修改,像从小房子装水管,从水管到简单挂起,再到管线臃肿混乱,在意料之外的报错中拿到经验,最后拆除重写,小房子才有了新的管道线路。
 本质来说是代码之间的联系更准确了,准确的同时,也多了支持精准处理的变量,变量位置调整。
 
 功能依旧是 提前写入,按计划使得角色倒退。
 但是封装之后,in out的操作,使得总是处理数组一段的数据,最后产生的却先使用,最先产生的最后使用。
 500 1000 1500 2000 2500 3000
 输出是
 3000 2500 2000 1500 1000 500
 倒着输出了
 
 但是如果在输出3000之后,输出2500之前,又输入一个数字3500
 下次输出的就是3500
 
 输出3500之后,再输出2500之前,又输入4000,
 下次输出的就是4000。
 
 
 进进出出,数字还是数字,代码层面确实是这样就结束了。
 
 
 贰.参考语法
 TypeScript 类 | 菜鸟教程 (runoob.com)
 别看太久,我觉得代码跑起来就行,看了不能立即敲代码改参数的还不是这个阶段的事情。
 叁.应用说明
 数字进出,可以赋予数字意义,数字代表,数字进出,方向进出,走迷宫,走到死路,回滚步数,倒回一步换另一个方向,再探测,不通,回到原来方向,换另另一个方向再探测,不通,回到原来方向,换另另另外一个方向探测。穷举完倒数第一步的四种方向,再穷举倒数第二步,换另一个方向上的倒数第一步,再穷举四个方向,如果不通,就在倒回第二步,换再穷举倒数第三步。
 以上操作的高大上名称为“深度优先寻路”。“一直往下走,走不通回头,换条路再走,直到无路可走”。
 以上操作的代码层面的名称——栈,后进先出。
 游戏方面,走迷宫,回退到上一个分支。
 
 肆.相关参考链接 (返回主站)
 
 普通大学生“数据结构”课作业笔记#000-目录-逻辑结构与存储结构 口袋方舟论坛|面向全年龄的UGC互动内容平台与交流社区 (ark.online)
 
 伍.专有名词的真相(拓展视野,饭后闲聊)
 
 
 不过是在默认语境(直觉)下,为了一语中的,才产生的专有名词。
 成员变量(简称 “成员”)(member variable)
 类(class)
 指针(pointer)
 
 地址(address)
 分配内存(函数new)
 指针数组(Array of pointers)
 只要铭牌挂在房子上,就能修改数组里面的具体变量
 铭牌就是变量名,房子就是一块地,就是内存,
 铭牌刻上的就是房子的地址,
 变量存着的是内存的地址,
 底层支持:CPU找内存
 用腿跑路,拿着铭牌里的名字比对去找房子,如何奔跑按图索骥到达房子不多说,
 用CPU找,拿着数组里的地址比对去找内存,如何遍历按图索骥到达内存不多说。
 底层优化本质:让CPU找更少次数
 
 
 
 陆.告一段落,回顾语
 
 文案现写,代码现写,注释无数,回滚无数,踩坑无数。
 这是量大的预兆,这是标记的提醒。
 标记换个顺序,代码就得天翻地覆一次。
 教程不好写。
 现在才知道教材原来是势力平衡的结果:省略一步,穷举十次,省略两步,穷举百次。不省略,细节多如牛毛。
 
 
 从数组到栈,中间我们老师讲了其他的数据,铺垫了如数据类型,如抽象数据对象,数据项,数据元素,队列,顺序表,链表等等。
 我觉得还是离代码有点远,或者是从一个已经预料到结果的视角开始入手,就会跳过了自己的那部分随意发挥才华的故事。
 等着,哪天咱也出点靠谱教材,第一人称,全过程记录,平地起高楼。
 
 
 |