鸿蒙小案例-五子棋

鸿蒙小案例-五子棋

1.准备组件(组件布局)
2.下棋功能实现
3.机器人下棋功能实现
4.赢棋功能实现
5.附属功能实现

刚开始以为挺简单的,越写越…emo

因为代码有点多,所以这里就简单讲下逻辑,文末贴上代码

逻辑只是我个人想的,不代表只有这一种实现方式,有其他想法可以在下面留言

另外功能做的比较简单,有一些没实现,但是基本功能都有,大家可以自行优化


1.组件的准备

组件就比较简单,采用Canvas就可以,画出一个棋盘的布局

画布是一个300*300的,所以可下棋点位都可以计算出来

在这里插入图片描述


2.功能

1.前置状态校验


校验是否开始游戏,棋子颜色是否选择,没有选择给出弹窗提醒


2.校正触摸点的坐标

触摸点的坐标肯定不是精准的数字,要把它校正为符合棋盘规则的坐标

比如 53.666666666=》50,采用四舍五入方式


3.校验当前修正后的坐标点位是否有棋子

那么之前每一步的棋子要先加入一个全局变量,黑色和白色的还要再次单独区分并加入单独的变量

在绘制棋子


4.判断人工下棋完成后是否赢棋

因为我们的画布长宽都是固定的,所以每一个坐标点位都可以推断出来

在这里我们计算当前坐标横向,纵向,西北,东北四个方向,每个方向5种赢棋情况的坐标点位

每个方向的5种赢棋情况应为:

当前坐标分别处于第一位,第二位,第三位,第四位,第五位时,如下图

在这里插入图片描述

以上的情况已经包含了所有的赢棋情况

当所有坐标点位拿到后,判断每个方向的4个坐标点是否全部在已落子坐标数据变量中,如果有一个方向是,就赢,1个都没有那就继续下棋

(这点比较难理解,可以参考代码实现)


5.机器下棋

当走到这一步时肯定没有赢棋了,那么就该继续下棋了

首先需要获取到人工落子坐标周围的8个坐标点,结合实时更新的已落子坐标点位,拿到人工坐标周边的空余可下棋坐标点位,随机(这里是决定机器人智能程度的关键,我只做了最简单的)生成1个位置,绘制坐标

绘制完后,还要判断机器人的是否赢棋,调用方法即可

到这里功能基本都完了


6.小功能实现

开始游戏/重新开始:清理棋盘

白棋/黑棋:选中人工下棋的棋色

悔棋:结合已落子坐标后退两步

结束游戏:清理棋盘

认输:清理棋盘

demo写的比较简单,但鉴于时间关系还是有一些功能没实现,写在下面,有需要的可以自行优化

待完成功能:
1.判断赢棋的条件不精准:有时候(偶发)4个也会显示胜利
2.刚下完的棋子要给加亮处理
3.悔棋功能的书写
4.棋子最外边一层,不允许落子
5.赢棋后,需要加亮显示赢棋的那一条线
6.机器人的智能不高,需要判断对方3个或者双3的情况去堵它

针对第六点,大家可以接入AI大模型,实时对战更刺激

当然也可以改造成联网,真人对战的,那这里就要用到数据库了,每下一步棋都要同步到数据库,并且要同步到正在下棋的两个人那里,这个就看大家的精力了


完整代码如下:

import promptAction from '@ohos.promptAction';
@Entry
@Preview
@Component
struct Wuziqi {private context: CanvasRenderingContext2D = new CanvasRenderingContext2D(new RenderingContextSettings(true))/*** 待完成功能:* 1,判断赢棋的条件不精准:有时候4个也会显示胜利* 2.刚下完的棋子要给加亮处理* 3.悔棋功能的书写* 4.棋子最外边一层,不允许落子* 5.赢棋后,需要加亮显示赢棋的那一条线* 6.AI的智能不高,需要判断对方3个或者双3的情况去堵它*///棋盘宽度qpWidth: number = 300//棋盘高度qpHeight: number = 300//白旗下棋坐标集合,悔棋使用@StatehqzbList: qpzbClass[] = []//黑旗下棋坐标集合,悔棋使用@StatebqzbList: qpzbClass[] = []//已经占用的坐标集合@StatecomzbList: qpzbClass[] = []//棋盘允许下棋的坐标点集合@StateqpZbList: qpzbClass[] = []//是否开始游戏,游戏进行状态@StateisStatus: boolean = false//当前用户选择的 棋色,''代表初始,还未选择颜色@StatenowColor: Color.White | Color.Black | '' = ''//棋盘内网格线的颜色,黑色qpLineColor: string = Color.Black//角标坐标集合jbList: qpzbClass[] = [{ x: 60, y: 60 }, { x: 200, y: 60 }, { x: 60, y: 200 }, { x: 200, y: 200 }]//当前棋子的坐标@Statezb: qpzbClass = { x: 0, y: 0 }//赢棋的常量isWinPD(tszb: qpzbClass[]) {let x: number = this.zb.xlet y: number = this.zb.y//横向let conZbList1: qpzbClass[] = [{ x: x + 20, y: y }, { x: x + 40, y: y }, { x: x + 60, y: y }, { x: x + 80, y: y }]let conZbList2: qpzbClass[] = [{ x: x - 20, y: y }, { x: x + 20, y: y }, { x: x + 40, y: y }, { x: x + 60, y: y }]let conZbList3: qpzbClass[] = [{ x: x - 40, y: y }, { x: x - 20, y: y }, { x: x + 20, y: y }, { x: x + 40, y: y }]let conZbList4: qpzbClass[] = [{ x: x - 60, y: y }, { x: x - 40, y: y }, { x: x - 20, y: y }, { x: x + 20, y: y }]let conZbList5: qpzbClass[] = [{ x: x - 80, y: y }, { x: x - 60, y: y }, { x: x - 40, y: y }, { x: x - 20, y: y }]//竖向let conZbList6: qpzbClass[] = [{ x: x, y: y + 20 }, { x: x, y: y + 40 }, { x: x, y: y + 60 }, { x: x, y: y + 80 }]let conZbList7: qpzbClass[] = [{ x: x, y: y - 20 }, { x: x, y: y + 20 }, { x: x, y: y + 40 }, { x: x, y: y + 60 }]let conZbList8: qpzbClass[] = [{ x: x, y: y - 40 }, { x: x, y: y - 20 }, { x: x, y: y + 20 }, { x: x, y: y + 40 }]let conZbList9: qpzbClass[] = [{ x: x, y: y - 60 }, { x: x, y: y - 40 }, { x: x, y: y - 20 }, { x: x, y: y + 20 }]let conZbList10: qpzbClass[] = [{ x: x, y: y - 80 }, { x: x, y: y - 60 }, { x: x, y: y - 40 }, { x: x, y: y - 20 }]//西北let conZbList11: qpzbClass[] = [{ x: x + 20, y: y + 20 }, { x: x + 40, y: y + 40 }, { x: x + 60, y: y + 60 }, {x: x + 80,y: y + 80}]let conZbList12: qpzbClass[] = [{ x: x - 20, y: y - 20 }, { x: x + 20, y: y + 20 }, { x: x + 40, y: y + 40 }, {x: x + 60,y: y + 60}]let conZbList13: qpzbClass[] = [{ x: x - 40, y: y - 40 }, { x: x - 20, y: y - 20 }, { x: x + 20, y: y + 20 }, {x: x + 40,y: y + 40}]let conZbList14: qpzbClass[] = [{ x: x - 60, y: y - 60 }, { x: x - 40, y: y - 40 }, { x: x - 20, y: y - 20 }, {x: x + 20,y: y + 20}]let conZbList15: qpzbClass[] = [{ x: x - 80, y: y - 80 }, { x: x - 60, y: y - 60 }, { x: x - 40, y: y - 40 }, {x: x - 20,y: y - 20}]//东北let conZbList16: qpzbClass[] = [{ x: x - 20, y: y + 20 }, { x: x - 40, y: y + 40 }, { x: x - 60, y: y + 60 }, {x: x - 80,y: y + 80}]let conZbList17: qpzbClass[] = [{ x: x + 20, y: y - 20 }, { x: x - 20, y: y + 20 }, { x: x - 40, y: y + 40 }, {x: x - 60,y: y + 60}]let conZbList18: qpzbClass[] = [{ x: x + 40, y: y - 40 }, { x: x + 20, y: y - 20 }, { x: x - 20, y: y + 20 }, {x: x - 40,y: y + 40}]let conZbList19: qpzbClass[] = [{ x: x + 60, y: y - 60 }, { x: x + 40, y: y - 40 }, { x: x + 20, y: y - 20 }, {x: x - 20,y: y + 20}]let conZbList20: qpzbClass[] = [{ x: x + 80, y: y - 80 }, { x: x + 60, y: y - 60 }, { x: x + 40, y: y - 40 }, {x: x + 20,y: y + 20}]//获取这4位坐标是否全部存在 存在,即获胜,整个for循环直接停掉,结束,// AlertDialog.show({message:'tszb:'+JSON.stringify(tszb)+';conZbList1:'+JSON.stringify(conZbList1)})if (this.arr1Containarr2(tszb, conZbList1) || this.arr1Containarr2(tszb, conZbList2) ||this.arr1Containarr2(tszb, conZbList3) || this.arr1Containarr2(tszb, conZbList4)|| this.arr1Containarr2(tszb, conZbList5) || this.arr1Containarr2(tszb, conZbList6)|| this.arr1Containarr2(tszb, conZbList7) || this.arr1Containarr2(tszb, conZbList8)|| this.arr1Containarr2(tszb, conZbList9) || this.arr1Containarr2(tszb, conZbList10)|| this.arr1Containarr2(tszb, conZbList11) || this.arr1Containarr2(tszb, conZbList12)|| this.arr1Containarr2(tszb, conZbList13) || this.arr1Containarr2(tszb, conZbList14)|| this.arr1Containarr2(tszb, conZbList15) || this.arr1Containarr2(tszb, conZbList16)|| this.arr1Containarr2(tszb, conZbList17) || this.arr1Containarr2(tszb, conZbList18)|| this.arr1Containarr2(tszb, conZbList19) || this.arr1Containarr2(tszb, conZbList20)) {return true}return false}//判断是否赢棋isWin(zb: qpzbClass, color: string) {//需要判断4个方向,每个方向5种情况的  赢棋情况//当前需要用到的颜色的棋子的坐标集合let tszb: qpzbClass[] = color === Color.White ? this.bqzbList : this.hqzbListif (this.isWinPD(tszb)) {AlertDialog.show({ message: color === Color.White ? '白棋胜利' : '黑棋胜利' })this.isStatus = falsereturn true}return false}//判断1个数组是否全部存在另一个数组中arr1Containarr2(arr1: qpzbClass[], arr2: qpzbClass[]) {if (arr2.length > 1) {for (let i: number = 0; i < arr2.length; i++) {if (!this.arr1Containarr2(arr1, [arr2[i]])) {return false}}} else {for (let i: number = 0; i < arr1.length; i++) {if (JSON.stringify(arr1[i]) === JSON.stringify(arr2[0])) {return true}}return false}return true}//校验下棋的前置状态checkBeforeStatus() {//校验各项状态if (this.nowColor === '') {AlertDialog.show({ message: '请先选择棋色' })return false}if (!this.isStatus) {AlertDialog.show({ message: '未开始游戏' })return false}return true}//下棋操作running(qz: qpzbClass) {//计算触摸点的坐标点为 最近的可落子的坐标点qz = this.conuntNowZb(qz)this.zb = qz//校验当前坐标是否有棋子if (this.checkZb(qz)) {promptAction.showToast({ message: '点击无效' })return}//记录棋子的坐标,分别记录黑白色的this.nowColor === Color.White ? this.bqzbList.push(qz) : this.hqzbList.push(qz)this.drowQz(qz, this.nowColor)if (!this.isWin(qz, this.nowColor)) {//机器人下棋this.aiRunning(qz)}}//校验当前坐标是否有棋子checkZb(qz: qpzbClass) {let st: boolean = falsethis.comzbList.some(ev => {if (JSON.stringify(ev) === JSON.stringify(qz)) {st = truereturn true}})return st}//机器人下棋aiRunning(qz: qpzbClass) {//获取当前人工棋子周围可落子坐标点,需要去除已经落子的坐标let pZb: qpzbClass[] = this.countPeripheryZb(qz)let random: number = Math.floor(Math.random() * pZb.length)let p: qpzbClass = pZb[random]this.drowQz(p, this.nowColor === Color.White ? Color.Black : Color.White)this.zb = pif (!this.isWin(p, this.nowColor)) {this.nowColor === Color.White ? this.hqzbList.push(p) : this.bqzbList.push(p)}}//获取一个坐标的8个周边 坐标点getZbZb(qz: qpzbClass) {let x: number = qz.xlet y: number = qz.ylet pZb: qpzbClass[] = [{ x: x - 20, y: y }, { x: x + 20, y: y }, { x: x - 20, y: y - 20 }, { x: x, y: y - 20 },{ x: x + 20, y: y - 20 }, { x: x - 20, y: y + 20 }, { x: x, y: y + 20 }, { x: x + 20, y: y + 20 }]return pZb}//获取当前人工棋子周围  可落子坐标点countPeripheryZb(qz: qpzbClass) {//固定写死的周边 坐标点let pZb: qpzbClass[] = this.getZbZb(qz)//校验位置是否有棋子let duplicates: qpzbClass[] = [...pZb]for (let i = duplicates.length - 1; i >= 0; i--) {// 检查当前A数组的子数组是否在B数组中存在let found = this.comzbList.some(subB => JSON.stringify(subB) === JSON.stringify(duplicates[i]));if (found) {duplicates.splice(i, 1);}}return duplicates}//计算触摸点的坐标点为 最近的可落子的坐标点conuntNowZb(qz: qpzbClass) {return { x: Math.round(Math.round(qz.x) / 20) * 20, y: Math.round(Math.round(qz.y) / 20) * 20 }}//绘制角标drowJb() {for (let index: number = 0; index < this.jbList.length; index++) {this.context.beginPath()let x: number = this.jbList[index].xlet y: number = this.jbList[index].ythis.context.arc(x, y, 4, 0, 10)this.context.strokeStyle = this.qpLineColor //角标边框颜色this.context.stroke()this.context.closePath()}}//绘制棋子drowQz(qz: qpzbClass, color: string) {this.context.beginPath()this.context.arc(qz.x, qz.y, 8, 0, 10)this.context.fillStyle = colorthis.context.fill() //填充颜色this.context.strokeStyle = Color.YELLOW//棋子边框颜色this.context.stroke()this.context.closePath()//记录已经占用的棋子位置this.comzbList.push(qz)}//计算棋盘内可落子的 坐标点countZb(i: number) {for (let i2 = 1; i2 <= 13; i2++) {this.qpZbList.push({ x: i2 * 20, y: i * 20 })}}//棋盘绘制qpCreate() {this.context.beginPath();//设置棋盘内网格线的颜色this.context.strokeStyle = this.qpLineColorthis.context.fill()//横向棋线for (let i: number = 1; i <= 15; i++) {this.context.moveTo(0, i * 20);this.context.lineTo(this.qpWidth - 20, i * 20);this.context.stroke();this.countZb(i)}//纵向棋线for (let i: number = 1; i <= 15; i++) {this.context.moveTo(i * 20, 0);this.context.lineTo(i * 20, this.qpHeight - 20);this.context.stroke();}this.context.closePath();//设置角标this.drowJb()}//棋盘,棋子,清除clearQp() {this.hqzbList = []this.bqzbList = []this.comzbList = []this.context.clearRect(0, 0, this.qpWidth, this.qpHeight) //清理画布内绘画this.qpCreate() //重新绘制棋盘}@StylesbuttonStyle_height20(){.height(20).backgroundColor(Color.White)}@StylesbuttonStyle_height35(){.height(35).backgroundColor(Color.White)}@StylesrowPadding(){.padding({top: 20,bottom: 20})}build() {Column() {//上功能区Row({ space: 20 }) {Button('白棋').buttonStyle_height20().fontWeight(FontWeight.Bold).fontSize(25).fontColor(Color.Black).onClick(() => {if (this.nowColor === '' || this.comzbList.length<1) {this.nowColor = Color.White}else{promptAction.showToast({message:'点击无效'})}}).backgroundColor(this.nowColor === Color.White ? Color.YELLOW : '')Button(this.nowColor!=='' && this.comzbList.length>1?'重新开始':'开始游戏').buttonStyle_height35().fontWeight(FontWeight.Bold).fontSize(35).fontColor(Color.Black).onClick(() => {this.isStatus = truethis.clearQp()})Button('黑棋').buttonStyle_height20().fontWeight(FontWeight.Bold).fontSize(25).fontColor(Color.Black).onClick(() => {if (this.nowColor === '' || this.comzbList.length<1 ) {this.nowColor = Color.Black}else{promptAction.showToast({message:'点击无效'})}}).backgroundColor(this.nowColor === Color.Black ? Color.YELLOW : '')}.justifyContent(FlexAlign.SpaceBetween).height(50)//棋盘位置Row() {Column() {Canvas(this.context) {}.onTouch((event: TouchEvent) => {//按下时触发,就近坐标点,绘制一个圆块if (event.type === TouchType.Up) {if (this.checkBeforeStatus()) {this.running({ x: event.touches[0].x, y: event.touches[0].y })}}}).onReady(() => {//设置绘画边框宽度this.context.lineWidth = 1this.qpCreate()}).backgroundColor(Color.Yuanm).margin({top: 15,bottom: 15}).border({width: 1,color: Color.Black})}.width(this.qpWidth).height(this.qpHeight).border({width: 5,color: Color.Black,radius: 1,style: BorderStyle.Solid}).padding({left: 15,right: 15})}.justifyContent(FlexAlign.Center).alignItems(VerticalAlign.Center).width('100%').height(450).rowPadding().backgroundColor(Color.Yuanm)//下功能区Row({ space: 20 }) {Button('悔棋').buttonStyle_height20().fontWeight(FontWeight.Bold).fontSize(25).fontColor(Color.Black).onClick(() => {//悔棋操作AlertDialog.show({message:'功能待开发'})})Button('结束游戏').buttonStyle_height35().fontWeight(FontWeight.Bold).fontSize(35).fontColor(Color.Black).onClick(() => {//结束游戏this.isStatus = false//清理棋盘,重新绘制棋盘this.clearQp()})Button('认输').buttonStyle_height20().fontWeight(FontWeight.Bold).fontSize(25).fontColor(Color.Black).onClick(() => {//认输this.isStatus = false//清理棋盘,重新绘制棋盘this.clearQp()})}.justifyContent(FlexAlign.SpaceBetween).height(50)}.width('100%').height('100%').rowPadding()}
}class qpzbClass {x: number = 0y: number = 0
}//颜色枚举
enum Color {Black = '#000000',White = '#FFFFFF',Yuanm = 'RGB(245,173,96)',YELLOW = 'RGB(218, 165, 32)'
}

代码可能稍微有点乱,没有时间去做精细的优化,本来就是个小demo,凑合着用吧-

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/692637.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

线阵相机参数介绍之轴编码器控制

1.1 功能介绍 编码器是将检测对象的运动与相机拍摄取图相匹配的设备&#xff0c;也即检测对象运动一定距离&#xff0c;相机就拍摄一定行高的图像。 编码器会将检测对象的实际位移转换为固定数量电信号。例如&#xff1a;编码器的精度是2000p/r,该参数的含义是编码器每转一圈输…

IDEA插件推荐:免费好用!

IDEA是一款功能强大的集成开发环境&#xff08;IDE&#xff09;&#xff0c;它可以帮助开发人员更加高效地编写、调试和部署软件应用程序。我们在编写完接口代码后需要进行接口调试等操作&#xff0c;一般需要打开额外的调试工具。 今天给大家介绍一款IDEA插件&#xff1a;Api…

C语言------------指针笔试题目深度剖析

1. #include <stdio.h> int main() { int a[5] { 1, 2, 3, 4, 5 }; int *ptr (int *)(&a 1); printf( "%d,%d", *(a 1), *(ptr - 1)); return 0; } 首先要明白这个强制类型转换&#xff0c;即int(*)[5]类型转换成int(*)类型&#xff1b; *&#xff…

MySQL 安装步骤

下载地址&#xff1a;https://downloads.mysql.com/archives/community/&#xff0c; 选择第二个 将下载的压缩包解压到自己想要放到的目录下&#xff08;路径中最好不要有中文&#xff09; 一、添加环境变量 环境变量里面有很多选项&#xff0c;这里我们只用到Path这个参数…

爬虫知识--02

免费代理池搭建 # 代理有免费和收费代理 # 代理有http代理和https代理 # 匿名度&#xff1a; 高匿&#xff1a;隐藏访问者ip 透明&#xff1a;服务端能拿到访问者ip 作为后端&#xff0c;如何拿到使用代理人的ip 请求头中&#xff1a;x-forwor…

day3 2/20

1> 使用多进程完成两个文件的拷贝&#xff0c;父进程拷贝前一半&#xff0c;子进程拷贝后一半&#xff0c;父进程回收子进程的资源 #include<myhead.h> int main(int argc, const char *argv[]) {int fd1-1,fd2-1;if((fd1open("./ggb.bmp",O_RDONLY,0664))…

Go语言中的流程控制

「万事开头难&#xff0c;视频号500粉直播需要你的助力&#xff01;你的支持是我前进的动力&#xff01;」 1、Golang 中的流程控制 流程控制是每种编程语言控制逻辑走向和执行次序的重要部分&#xff0c;流程控制可以说是一门语言的“经脉”。Go 语言中最常用的流程控制有 if …

【案例研习笔记】KodeRover_云时代 DevOps 建设

轻度量、轻流程、重开发者体验生产力工具建设要大于管理工具建设贴合自己业务&#xff0c;不要去求大求全

回避型人格适合什么职业?如何改善回避型人格?

回避型人格最突出的特点,就是对外界的排斥极度敏感&#xff0c;他们非常害怕别人的不认可&#xff0c;也特别害惧失败&#xff0c;因此不敢与人交往&#xff0c;同时也害怕新事物。因为受到这一性格的影响&#xff0c;他们极度缺乏社交能力&#xff0c;也一直在否定自身能力。 …

网络协议汇总

1.HTTP协议 1.认识URL 平时我们俗称的 "网址" 其实就是说的 URL URL中的字符只能是ASCII字符&#xff0c;但是ASCII字符比较少&#xff0c;而URL则常常包含ASCII字符集以外的字符&#xff0c;如非英语字符、汉字、特殊符号等等&#xff0c;所以要对URL进行转换。这个…

已解决Application run failed org.springframework.beans.factory.BeanNot

问题原因&#xff1a;SpringBoot的版本与mybiats-puls版本不对应且&#xff0c;spring自带的mybiats与mybiats-puls版本不对应 这里我用的是3.2.2版本的SpringBoot&#xff0c;之前mybiats-puls版本是3.5.3.1有所不同。 问题&#xff1a;版本对不上 解决办法&#xff1a;完整…

宝塔nginx配置SpringBoot服务集群代理

宝塔nginx配置SpringBoot服务集群代理 1、需求&#xff1a; 现有一个springboot服务需要部署成集群&#xff0c;通过nginx负载均衡进行访问&#xff0c;其中这个springboot服务内置了MQTT服务、HTTP服务、TCP服务。 MQTT服务开放了1889端口 HTTP服务开放了8891端口 HTTP服务开…

LeetCode94.二叉树的中序遍历

题目 给定一个二叉树的根节点 root &#xff0c;返回 它的 中序 遍历 。 示例 &#xff1a; 输入&#xff1a;root [1,null,2,3] 输出&#xff1a;[1,3,2] 思路 中序遍历的顺序是左子树 -> 根节点 -> 右子树。因此&#xff0c;我们可以通过递归的方式遍历二叉树&…

[word] word 怎样批量把英文单词的首字母全部改成大写 #笔记#其他#学习方法

word 怎样批量把英文单词的首字母全部改成大写 word在处理长文档的过程中&#xff0c;有时候一个单词在多页重复出现。如果要把该单词的首字母改成大写&#xff0c;如果一个一个的改&#xff0c;费时费力。 方法&#xff1a;替换功能 如&#xff1a;我要把camtasia批量改成C…

【riscv】使用qemu运行riscv裸机freestanding程序

文章目录 1. 运行显示2. 工具准备3. 裸机代码和编译3.1 源码3.2 编译 4. 使用qemu仿真运行riscv裸机程序 1. 运行显示 详见左下角&#xff0c; 运行时串口输出的字符 A ; 2. 工具准备 # for riscv64-linux-gnu-gcc sudo apt-get install gcc-riscv64-linux-gnu# for qemu-s…

适用于高云FPGA的JTAG

目标板卡&#xff1a;小梅哥芯海无涯GOWIN高云ACG525(GW5A-LV25UG324) 1.软件要求&#xff1a;必须用商业版&#xff0c;因为教育版(V1.9.9Beta-4 Education)不支持此封装的GW5A。商业版需要上网申请License&#xff0c;此处提供D4D853392AD8.lic文件&#xff08;此方法为临时…

基于stm32F103的蜂鸣器周期发声实验

蜂鸣器作为一种声音报警器件,应用广泛。本实验基于stm32F103单片机,通过控制蜂鸣器的IO口电平电压,使其周期性地进行电平翻转,从而驱动蜂鸣器发出周期性的鸣叫声。该实验主要运用了stm32的GPIO和定时器TIM的相关功能,不仅可以巩固这些外设的使用,也可以通过改变时间参数,控制蜂…

软件测试面试题汇总

一、面试基础题 简述测试流程: 1、阅读相关技术文档&#xff08;如产品PRD、UI设计、产品流程图等&#xff09;。 2、参加需求评审会议。 3、根据最终确定的需求文档编写测试计划。 4、编写测试用例&#xff08;等价类划分法、边界值分析法等&#xff09;。 5、用例评审(…

OpenHarmony JS和TS三方组件使用指导

OpenHarmony JS和TS三方组件介绍 OpenHarmony JS和TS三方组件使用的是OpenHarmony静态共享包&#xff0c;即HAR(Harmony Archive)&#xff0c;可以包含js/ts代码、c库、资源和配置文件。通过HAR&#xff0c;可以实现多个模块或者多个工程共享ArkUI组件、资源等相关代码。HAR不…

文件上传漏洞--Upload-labs--Pass07--点绕过

一、什么是点绕过 在Windows系统中&#xff0c;Windows特性会将文件后缀名后多余的点自动删除&#xff0c;在网页源码中&#xff0c;通常使用 deldot()函数 对点进行去除&#xff0c;若发现网页源代码中没有 deldot() 函数&#xff0c;则可能存在 点绕过漏洞。通过点绕过漏洞&…