大家好,我是公众号3分钟学堂的郭立员~
前言
随着脚本的出现,各种限制脚本运行的验证码也随之出现,前两天在群里看到有人付费求解五子棋验证码的方法,所以今天拿来和大家讲讲解决思路。
因为我也是第一次看到这种验证码,所以解决的算法难免比较复杂,如果你有更好的算法欢迎指正。
一、五子棋验证码的样子
二、完成验证的要求
移动1个棋子,使其连续5个棋子同色即可完成验证。
对于5*5的棋盘来说,能够组成5子相连,一共有12中情况:
①每一列5子相连,一共5种
②每一行5子相连,也是5种
③对角线5子相连,有2种
三、解决验证的思路
既然已经知道5子相连有12种可能,那么就逐个验证当前图片符合哪种可能性。
我们知道验证码要想完成验证,需要移动1个棋子,也就说目前棋盘上的棋子并没有5子相连,而是4子相连(包括间隔1子的相连),那么我们就要逐个查看12种可能性中,哪个是有4子相连的。
找到4子相连以后,确定2件事儿,一是4子是什么颜色,二是空缺的第5子在什么位置。
之后找到棋盘上的其他位置和4子一样颜色的那个棋子,把它移动到空缺的第5子位置。
通过上面的思路可以知道我们最终的目的是得到两个坐标:
坐标1:空缺棋子的位置
坐标2:补齐空缺的棋子位置
四、解决步骤:
第一步:获取全盘的颜色,知道每一个位置都是什么棋子,把它们保存在二维数组中。这里每一个棋子用编号1-4表示,空缺位置用0表示
①、获取第一个棋子的中心点坐标,每隔固定位置获取下一个棋子的中心点坐标。
通过横向和纵向的偏移,得到所有棋子中心点的坐标。
②、获取灰、黄、蓝、白、黑五种棋子的颜色值。
③、遍历第1步得到所有中心点坐标位置的颜色值和灰、黄、蓝、白、黑五色进行比色,看看棋子是哪种颜色,把对应的编号写入数组。
五色的编号可以自行对应,比如我的对应编号:
灰色:0 代表空
黄色:1
蓝色:2
白色:3
黑色:4
- Dim x=130,y=105 //间距x,y
- Dim x0=102,y0=437 //第一个棋子中心点的坐标
- Dim n
- Dim arr(0,0)
- For j = 0 To 4
- arr[j+1]={null}
- For i = 0 To 4
- n = CmpColor(x0+x*i,y0+y*j, "E4DAD0|6DD2F6|FF966D|FDF8F5|5A584E", 0.9)
- arr[j+1][i+1]=n
- Next
- Next
- TracePrint encode.TableToJson(arr)
复制代码输出结果:格式化后展示效果
- [
- [4, 1, 1, 1, 2],
- [3, 4, 0, 3, 1],
- [1, 3, 0, 3, 1],
- [0, 3, 3, 4, 1],
- [1, 2, 2, 4, 4]
- ]
复制代码第二步:判断二维数组符合12种可能性的哪一种
12种可能性分成4类:
①在一行里有4子同色
- For k = 0 To 4
- For j = 1 To 5
- m = 0
- For i = 1 To 5
- If k = arr[j][i] Then
- m=m+1
- End If
- If m = 4 Then
- TracePrint j,k
- TracePrint "第"&j&"行有同色4子,色号为"&k
- For s = 1 To 5
- If arr[j][s] = 0 Then
- TracePrint "第"&j&"行,第"&s&"个,缺少一个色号"&k
- End If
- Next
- End If
- Next
- Next
- Next
复制代码②在一列中有4子同色
- For k = 1 To 4
- For i = 1 To 5
- m = 0
- For j = 1 To 5
- If k = arr[j][i] Then
- m=m+1
- End If
- If m = 4 Then
- TracePrint i,k,j
- TracePrint "第"&i&"列有同色4子,色号为"&k
- For s = 1 To 5
- If arr[s][i] = 0 Then
- TracePrint "第"&i&"列,第"&s&"个,缺少一个色号"&k
- End If
- Next
- End If
- Next
- Next
- Next
复制代码③左上右下对角线有4子同色
- For k = 1 To 4
- m = 0
- For i = 1 To 5
- For j = 1 To 5
- If k = arr[j][i] and i=j Then
- m=m+1
- End If
- If m = 4 Then
- TracePrint i,k,j
- TracePrint "左上右下对角线,色号为"&k
- For s = 1 To 5
- If arr[s][s] = 0 Then
- TracePrint "第"&s&"行,第"&s&"列,缺少一个色号"&k
- End If
- Next
- End If
- Next
- Next
- Next
复制代码④左下右上对角线有4子同色
- For k = 1 To 4
- m = 0
- For i = 1 To 5
- For j = 1 To 5
- If k = arr[j][i] and i+j=6 Then
- m=m+1
- End If
- If m = 4 Then
- TracePrint i,k,j
- TracePrint "左下右上对角线,色号为"&k
- For s = 1 To 5
- If arr[s][6-s] = 0 Then
- TracePrint "第"&s&"行,第"&6-s&"列,缺少一个色号"&k
- End If
- Next
- End If
- Next
- Next
- Next
复制代码4类方法原理是相同的,在12种可能性的位置找同一种棋子,每找到一个就记录1次,当次数达到4次就说明有4子同色。
这里需要大量的遍历数组,同时注意每验证一种可能位置后,清空记录次数,保证下一种可能性测试是从0开始计数。
在知道4子同色后,第5个非同色就是空缺位置,这个坐标也是我们想要获得的。
第三步、找到补齐所需棋子的位置
①行验证
假设第1行是有4连同色的棋子,颜色是黄色,那么我们就要找不在第1行的黄色棋子的位置,这个位置就是我们的目标位置。
- Function 行验证(h,k)
- For j = 1 To 5
- For i = 1 To 5
- If j <> h and arr[j][i]=k Then
- TracePrint "补齐所需的棋子在第"&j&"行,第"&i&"列"
- End If
- Next
- Next
- End Function
复制代码②列验证
原理和行验证一样,把行改成列即可
- Function 列验证(l,k)
- For j = 1 To 5
- For i = 1 To 5
- If i <> l and arr[j][i]=k Then
- TracePrint "补齐所需的棋子在第"&j&"行,第"&i&"列"
- End If
- Next
- Next
- End Function
复制代码③左上右下对角线验证
这个对角线的特点就是行号和列号相同,只要找到行号列号不同,并且是指定的那个颜色,就是我们要的位置了。
- Function 左上右下验证(k)
- For j = 1 To 5
- For i = 1 To 5
- If i <> j and arr[j][i]=k Then
- TracePrint "补齐所需的棋子在第"&j&"行,第"&i&"列"
- End If
- Next
- Next
- End Function
复制代码④左下右上对角线验证
这个对角线的特点是行号+列号=6,其他验证方法也一样
- Function 左下右上验证(k)
- For j = 1 To 5
- For i = 1 To 5
- If i <> 6-j and arr[j][i]=k Then
- TracePrint "补齐所需的棋子在第"&j&"行,第"&i&"列"
- End If
- Next
- Next
- End Function
复制代码通过验证函数,可以知道补齐所需棋子的位置。
第四步:移动棋子
完成以上步骤之后,我们可以得到两个位置:
①空缺的位置
②补齐所需棋子的位置
把补齐所需的棋子移动到空缺位置。
到这里整个验证过程就结束了,其中遍历大量无效数据,但是我也不知道怎么优化掉,就先这样了。