日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪(fǎng)問(wèn) 生活随笔!

生活随笔

當(dāng)前位置: 首頁(yè) > 编程资源 > 编程问答 >内容正文

编程问答

编程探究智能手机的图案解锁

發(fā)布時(shí)間:2023/12/29 编程问答 53 豆豆
生活随笔 收集整理的這篇文章主要介紹了 编程探究智能手机的图案解锁 小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

概述

? ? 圖案解鎖是現(xiàn)今智能手機(jī)比較常見(jiàn)的解鎖方式,用戶(hù)通過(guò)在3×3的點(diǎn)陣中繪制圖案來(lái)設(shè)置密碼,解鎖時(shí),也通過(guò)實(shí)時(shí)繪制圖案來(lái)實(shí)現(xiàn)解鎖驗(yàn)證。例如,下圖就是幾個(gè)解鎖的圖案示例:

下文中筆者通過(guò)編程對(duì)圖案解鎖的情況進(jìn)行探究,主要計(jì)算一些統(tǒng)計(jì)信息。首先給出圖案解鎖中對(duì)于圖案繪制的規(guī)則,然后說(shuō)明為實(shí)現(xiàn)相關(guān)計(jì)算而進(jìn)行編程的思路,最后根據(jù)程序輸出結(jié)果說(shuō)明一些統(tǒng)計(jì)信息。

繪圖規(guī)則

? ? 對(duì)于目前圖案解鎖的實(shí)現(xiàn),在繪制解鎖圖案過(guò)程中,需要遵循如下的規(guī)則:

(1) 繪制的圖案是一條經(jīng)過(guò)若干個(gè)點(diǎn)的折線(xiàn)軌跡,至少要經(jīng)過(guò)4個(gè)點(diǎn)。

(2) 點(diǎn)陣中每個(gè)點(diǎn)只能經(jīng)過(guò)1次,軌跡中也一定沒(méi)有回路。

(3) 點(diǎn)陣中任意兩點(diǎn),均可以通過(guò)一條邊直連,水平的邊、豎直的邊,傾斜的邊均合法,如下圖所示:
(4) 如果兩點(diǎn)之間的邊經(jīng)過(guò)了第三個(gè)點(diǎn),則只有位于邊中部的點(diǎn)已被經(jīng)過(guò),該邊才有效。這里為了便于說(shuō)明,將點(diǎn)陣中的各個(gè)點(diǎn)進(jìn)行編號(hào),如下:

此時(shí),軌跡:2->1->3->5是正確的,當(dāng)從點(diǎn)1到達(dá)點(diǎn)3時(shí),點(diǎn)2已經(jīng)被經(jīng)過(guò),因此可以從點(diǎn)1到達(dá)點(diǎn)3,而軌跡1->3->2->5則是錯(cuò)誤的,因?yàn)閺狞c(diǎn)1到達(dá)點(diǎn)3是,點(diǎn)2未被經(jīng)過(guò),不能從點(diǎn)1到達(dá)點(diǎn)3,如下圖:


以上為圖案的繪制規(guī)則。

編程分析

? ? 接下來(lái)通過(guò)編程來(lái)對(duì)圖案解鎖的情況進(jìn)行分析,這里主要關(guān)注一些統(tǒng)計(jì)信息,包括:不同密碼的種類(lèi)數(shù)、不同圖案的種類(lèi)數(shù)以及圖案和密碼的對(duì)應(yīng)關(guān)系。

·邊的分類(lèi)

? ? 為了便于編程實(shí)現(xiàn),首先對(duì)邊進(jìn)行分類(lèi)。根據(jù)上文中對(duì)于繪圖規(guī)則的描述,這里將繪圖中用到的邊劃分為如下的4類(lèi):
(1)直邊:連接相鄰兩個(gè)點(diǎn)的水平邊和垂直邊稱(chēng)為直邊,在解鎖圖案中,可以使用的直邊有12條。(2)45度斜邊:45度傾斜的連接兩個(gè)相鄰點(diǎn)的邊稱(chēng)為45度斜邊,在圖案中,可以使用的45度斜邊有8條。(3)26度斜邊:除45度斜邊外,圖案中還可以使用另一種斜邊,該邊的傾斜度大約為26度,在圖中,可用的26度斜邊也有8條。(4)跳邊:連接兩個(gè)不相鄰的點(diǎn)的邊稱(chēng)為跳邊,通過(guò)跳邊連接的兩個(gè)點(diǎn)中間一定會(huì)經(jīng)過(guò)第3個(gè)點(diǎn),這個(gè)點(diǎn)我們稱(chēng)其為“中介點(diǎn)”,根據(jù)上文中的繪圖規(guī)則,只有中介點(diǎn)已經(jīng)被經(jīng)過(guò)是,跳邊才合法。在圖案中,跳邊有8條。根據(jù)邊的傾斜情況,跳邊還可以細(xì)分為直跳邊和斜跳邊。

下圖描述了4種類(lèi)型的邊的情況:


在Java代碼中,我們用整型常量代表每一種邊的類(lèi)型,同時(shí)用鄰接矩陣的方式表示圖中任意兩點(diǎn)的邊,代碼如下:

/*** Edge types.*/private static final int NONE = 0, // 無(wú)邊 STRAIGHT = 1, // 直邊DECLINE_45 = 2, // 45度斜邊DECLINE_26 = 3, // 26度斜邊SKIP_STRAIGHT = 4, // 直跳邊SKIP_DECLINE = 5; // 斜跳邊/*** The accessible matrix of each vertex. for each element matrix[i][j] is* the type of edge <i, j>.*/private static int[][] matrix = new int[][] {{ NONE, NONE, NONE, NONE, NONE, NONE, NONE, NONE, NONE, NONE },{ NONE, NONE, STRAIGHT, SKIP_STRAIGHT, STRAIGHT, DECLINE_45, DECLINE_26, SKIP_STRAIGHT, DECLINE_26, SKIP_DECLINE },{ NONE, STRAIGHT, NONE, STRAIGHT, DECLINE_45, STRAIGHT, DECLINE_45, DECLINE_26, SKIP_STRAIGHT, DECLINE_26 },{ NONE, SKIP_STRAIGHT, STRAIGHT, NONE, DECLINE_26, DECLINE_45, STRAIGHT, SKIP_DECLINE, DECLINE_26, SKIP_STRAIGHT },{ NONE, STRAIGHT, DECLINE_45, DECLINE_26, NONE, STRAIGHT, SKIP_STRAIGHT, STRAIGHT, DECLINE_45, DECLINE_26 },{ NONE, DECLINE_45, STRAIGHT, DECLINE_45, STRAIGHT, NONE, STRAIGHT, DECLINE_45, STRAIGHT, DECLINE_45 },{ NONE, DECLINE_26, DECLINE_45, STRAIGHT, SKIP_STRAIGHT, STRAIGHT, NONE, DECLINE_26, DECLINE_45, STRAIGHT },{ NONE, SKIP_STRAIGHT, DECLINE_26, SKIP_DECLINE, STRAIGHT, DECLINE_45, DECLINE_26, NONE, STRAIGHT, SKIP_STRAIGHT },{ NONE, DECLINE_26, SKIP_STRAIGHT, DECLINE_26, DECLINE_45, STRAIGHT, DECLINE_45, STRAIGHT, NONE, STRAIGHT },{ NONE, SKIP_DECLINE, DECLINE_26, SKIP_STRAIGHT, DECLINE_26, DECLINE_45, STRAIGHT, SKIP_STRAIGHT, STRAIGHT, NONE } }; 矩陣中第i行第j列記錄了點(diǎn)i到點(diǎn)j之間的邊的類(lèi)型,由于數(shù)組下標(biāo)從0開(kāi)始,而我們的編號(hào)為1-9,因此在鄰接矩陣中有冗余的第0行和第0列,編號(hào)為0的點(diǎn)不存在,因此和其他點(diǎn)的邊也不存在,記為NONE,另外,同一個(gè)點(diǎn)之間也沒(méi)有邊,因此第i行第i列的元素總是NONE。

·跳邊的規(guī)則

? ? 根據(jù)前文中對(duì)于跳邊的描述,只有中介點(diǎn)被經(jīng)過(guò)時(shí),跳邊才可用,我們需要在代碼中將這些規(guī)則記錄下來(lái),這里采用Map容器來(lái)存儲(chǔ),其中key值為跳邊的端點(diǎn),value值為中介點(diǎn),為了便于表示,這里將key值轉(zhuǎn)換為字符串,格式為"v1#v2",其中v1和v2是端點(diǎn)的編號(hào),代碼實(shí)現(xiàn)如下:

/*** The condition for the condition accessible. the pattern of the key is* "v1#v2", and the value is an integer M. It means the vertex is accessible* when the vertex M is visited.*/private static Map<String, Integer> conditions = new HashMap<>();conditions.put("1#3", 2);conditions.put("1#7", 4);conditions.put("1#9", 5);conditions.put("2#8", 5);conditions.put("3#7", 5);conditions.put("3#9", 6);conditions.put("4#6", 5);conditions.put("7#9", 8);

·圖和密碼的表示和存儲(chǔ)

? ? 為了便于在程序中存儲(chǔ)每一個(gè)圖形和每一個(gè)密碼,這里將圖形和密碼分別轉(zhuǎn)換為int整形和字符串來(lái)存儲(chǔ)。

? ? 對(duì)于圖形,由于已經(jīng)給定了不同的點(diǎn),因此不同的圖形主要根據(jù)不同的邊來(lái)區(qū)分,根據(jù)上文的分析,不同的邊的個(gè)數(shù)有28條,這里沒(méi)有把跳邊記錄在內(nèi),對(duì)于一個(gè)圖形而言,每一個(gè)跳邊都可由2個(gè)非跳邊來(lái)取代,這里將每一條邊進(jìn)行編號(hào),對(duì)于某一個(gè)圖形,當(dāng)其包含編號(hào)為i的邊是,就將int整數(shù)中的第i位二進(jìn)制位置為1,這樣就將一個(gè)圖像轉(zhuǎn)換為一個(gè)int數(shù)字來(lái)存儲(chǔ),相關(guān)代碼如下:

/*** Record the id of each edge, used in the process of counting the amount of* different graph.*/private static Map<String, Integer> edgeIds = new HashMap<>();// edge id map.edgeIds.put("1#2", 0);edgeIds.put("1#6", 1);edgeIds.put("1#5", 2);edgeIds.put("1#8", 3);edgeIds.put("1#4", 4);edgeIds.put("2#3", 5);edgeIds.put("2#6", 6);edgeIds.put("2#9", 7);edgeIds.put("2#5", 8);edgeIds.put("2#7", 9);edgeIds.put("2#4", 10); edgeIds.put("3#6", 11);edgeIds.put("3#8", 12);edgeIds.put("3#5", 13);edgeIds.put("3#4", 14);edgeIds.put("4#5", 15);edgeIds.put("4#9", 16);edgeIds.put("4#8", 17);edgeIds.put("4#7", 18);edgeIds.put("5#6", 19);edgeIds.put("5#9", 20);edgeIds.put("5#8", 21);edgeIds.put("5#7", 22);edgeIds.put("6#9", 23);edgeIds.put("6#8", 24);edgeIds.put("6#7", 25);edgeIds.put("7#8", 26);edgeIds.put("8#9", 27); 這里通過(guò)map來(lái)存儲(chǔ)每一條邊的編號(hào)。
? ? 對(duì)于密碼,則可以對(duì)應(yīng)一組點(diǎn)的序列,根據(jù)這個(gè)序列將對(duì)應(yīng)點(diǎn)順次用邊連接就唯一地代表一個(gè)密碼序列,因此我們用字符串來(lái)表示一個(gè)密碼序列。需要注意的是,圖形和密碼序列之間并不是一一對(duì)應(yīng)的關(guān)系,在某些情況下,不同的密碼序列可以得到相同的圖形。比較容易想到的情況是,對(duì)于一個(gè)給定的圖形,交換首尾起點(diǎn)就可以得到2個(gè)不同的密碼序列,如下圖:

在代碼中,我們用Map來(lái)圖形和密碼的映射關(guān)系,如下:

/*** Record the relationship between graph and password.*/private static Map<Integer, Set<String>> relation = new HashMap<>();

·搜索計(jì)算

? ? 最后通過(guò)基于深度優(yōu)先搜索的方式遍歷的方式遍歷所有的密碼序列,對(duì)上文中的存儲(chǔ)圖形和密碼的map進(jìn)行填充,代碼如下: /*** Count the amount of different passwords.*/private static void compute() {StringBuilder path = new StringBuilder();for (int j = 0; j < 10; j++) {visited[j] = false;}for (int i = 1; i <= 9; i++) {path.setLength(0);path.append(i);visited[i] = true;compute(i, 1, 0, path);visited[i] = false;}}/*** Count the statistics about graph passwords. This function is used for* iterate in the function compute(void).* * @param vertex* The vertex to visited in current iterate.* @param num* The count of vertexes visited.* @param graph* The current graph.* @path The current password path.*/private static void compute(int vertex, int num, int graph,StringBuilder path) {if (check(num, graph, path)) {if (relation.containsKey(graph)) {Set<String> paths = relation.get(graph);paths.add(path.toString());} else {Set<String> paths = new HashSet<>();paths.add(path.toString());relation.put(graph, paths);}}for (int i = 1; i <= 9; i++) {if (visited[i] || !available[matrix[vertex][i]]) {continue; }int a = -1;int b = -1;int c = -1;if (matrix[vertex][i] == SKIP_STRAIGHT|| matrix[vertex][i] == SKIP_DECLINE) {a = vertex > i ? i : vertex;b = vertex > i ? vertex : i;c = conditions.get(a + "#" + b);if (!visited[c]) {continue;}}int oldGraph = graph;int edgeId = -1;if (c == -1) {a = vertex > i ? i : vertex;b = vertex > i ? vertex : i;edgeId = edgeIds.get(a + "#" + b);graph |= 1 << edgeId;} else {a = c < vertex ? c : vertex;b = c < vertex ? vertex : c;edgeId = edgeIds.get(a + "#" + b);graph |= 1 << edgeId;a = c < i ? c : i;b = c < i ? i : c;edgeId = edgeIds.get(a + "#" + b);graph |= 1 << edgeId;}visited[i] = true;path.append(i);compute(i, num + 1, graph, path);graph = oldGraph;path.deleteCharAt(path.length() - 1);visited[i] = false;}}? ?? 這里需要關(guān)注的是:首先在遍歷過(guò)程中遇到跳邊時(shí),需要判定中介點(diǎn)是否已經(jīng)被訪(fǎng)問(wèn),如果已被訪(fǎng)問(wèn),則此時(shí)跳邊可用,繼續(xù)向下一層搜索,否則跳邊不可用,另外,筆者在編寫(xiě)代碼過(guò)程中,加入了check函數(shù),用于判定當(dāng)前密碼序列是否合法,通過(guò)修改check函數(shù)的實(shí)現(xiàn),我們可以從不同的角度來(lái)獲取響應(yīng)的統(tǒng)計(jì)信息。 ? ??
? ? 以上為編碼實(shí)現(xiàn)的思路。

一些統(tǒng)計(jì)信息

? ? 最后,筆者給出一些通過(guò)運(yùn)行程序得到的一些統(tǒng)計(jì)信息,通過(guò)修改check函數(shù)的實(shí)現(xiàn),可以從不同的角度進(jìn)行數(shù)據(jù)統(tǒng)計(jì),以下只是筆者自己感興趣的方面。

·密碼總數(shù)和圖案總數(shù)

? ? 首先統(tǒng)計(jì)一下所有合法的密碼和圖形的種類(lèi)數(shù),通過(guò)統(tǒng)計(jì)代碼中的relation的不同的key值可以得到不同的圖案的種類(lèi)數(shù),而所有value值中的list的size值的總和就是不同的密碼數(shù),通過(guò)程序運(yùn)行可以得到:不同的密碼序列的數(shù)目是389112,而不同的圖案的數(shù)目是285612。

·關(guān)于圖案和密碼的對(duì)應(yīng)關(guān)系

? ? 前文中已經(jīng)說(shuō)明,對(duì)于某些圖案,可以有多個(gè)密碼序列和其對(duì)應(yīng)。比較容易想到的是,對(duì)于簡(jiǎn)單的密碼,只要將其反序就是一個(gè)新的密碼,但是這個(gè)新密碼和反序前的密碼繪制出的圖案是同一個(gè)圖案。那么對(duì)與285612個(gè)圖案中,單個(gè)圖案最多可以和多少個(gè)不同的密碼序列對(duì)應(yīng)?這個(gè)問(wèn)題可以通過(guò)統(tǒng)計(jì)relation總的所有value值的size大小來(lái)得到答案。通過(guò)運(yùn)行程序,可以發(fā)現(xiàn),這個(gè)問(wèn)題的答案是4,即一個(gè)圖案最多可以映射到4個(gè)不同的密碼序列。

? ? 令筆者感到驚訝的是,所有可以映射到4個(gè)密碼序列的圖案中,有一些圖案結(jié)構(gòu)非常簡(jiǎn)單,例如下面的例子:


通過(guò)程序統(tǒng)計(jì),可以知道:在285612個(gè)不同的圖案中:有195512個(gè)圖案只能映射到1種密碼序列;78008個(gè)圖案可以映射到2種密碼序列;10792個(gè)圖案可以映射到3種密碼序列;1304種圖案可以映射到4種密碼序列。

? ? 下面再給出一些例子:


·基于邊的類(lèi)型的統(tǒng)計(jì)信息

根據(jù)使用邊的類(lèi)型,可以得到如下的統(tǒng)計(jì)信息。

邊的類(lèi)型圖案數(shù)密碼數(shù)
直邊45度斜邊26度斜邊直跳邊斜跳邊
××××288576
×××10601864
×××508410096
×3377645912
××69940139880
××××48
×××816
×××19003800
××30405576
289612389112
可以看到使用的邊的種類(lèi)越多,密碼和圖案的變化數(shù)目也越多,另外還可以看到,當(dāng)不使用跳邊時(shí)密碼數(shù)和圖案數(shù)一定是2倍關(guān)系,而使用了跳邊后,這個(gè)數(shù)量關(guān)系將不再保證,這說(shuō)明引入跳邊會(huì)加大密碼的復(fù)雜度。這一點(diǎn)還會(huì)在下文中體現(xiàn)。

? ? 另外可以看到,即使不使用直邊,也可以構(gòu)造出5576種不同的密碼,這里給出幾個(gè)樣例如下:


但是斜邊的繪制難度比較大,特別是26度的斜邊,像筆者手指比較粗,手機(jī)屏幕有又比較小的情況,使用起來(lái)不是很方便^-^?

·基于密碼長(zhǎng)度的統(tǒng)計(jì)信息

? ? 接下來(lái)統(tǒng)計(jì)不同長(zhǎng)度的密碼的情況,由于繪圖規(guī)則中的定義,一個(gè)合法的密碼必須至少包含4個(gè)點(diǎn),因此我們統(tǒng)計(jì)4-9個(gè)點(diǎn)的密碼的情況,結(jié)果如下:

密碼長(zhǎng)度圖案?jìng)€(gè)數(shù)密碼個(gè)數(shù)
48081624
539647152
61594826016
74907672912
8103656140704
9112160140704

·關(guān)于跳邊和孤點(diǎn)

? ? 最后再單獨(dú)分析一下跳邊的情況。通過(guò)前文的分析也可以知道,當(dāng)密碼序列中包含跳邊時(shí),密碼的復(fù)雜程度將會(huì)大大提高,對(duì)于不包含跳邊的密碼序列,可以很直觀地根據(jù)圖形推測(cè)出密碼的序列,同時(shí)這樣的圖形對(duì)應(yīng)的密碼序列一定至少有2種,下面的幾個(gè)樣例:

? ??

以上的例子都可以直接根據(jù)圖形來(lái)推算出對(duì)應(yīng)的密碼序列。但是當(dāng)密碼中包含跳邊時(shí),生成的圖案的復(fù)雜度將會(huì)大大提升,根據(jù)圖形推測(cè)密碼序列的難度也響應(yīng)增大,因?yàn)閳D形中將包含更多的“岔路”和“思路”,進(jìn)而密碼的安全性也在一定程度上可以提高,看下面的幾個(gè)例子:? ? 這里比較值得關(guān)注的是圖形中的“孤點(diǎn)”,所謂的“孤點(diǎn)”就是在圖形中只和1條邊相連的點(diǎn),這里在判定孤點(diǎn)時(shí)不計(jì)入跳邊,因?yàn)槊恳粭l跳邊都可以轉(zhuǎn)換為2條非跳邊。對(duì)于上面的樣例第1個(gè)圖形中的點(diǎn)1、點(diǎn)6和點(diǎn)8是孤點(diǎn),第3個(gè)圖形中的點(diǎn)7和點(diǎn)9也是孤點(diǎn),而最后一個(gè)圖形中,只有點(diǎn)9是孤點(diǎn)。

? ? 對(duì)于不包含跳邊的密碼序列,對(duì)應(yīng)的圖形一定只有2個(gè)孤點(diǎn),就是起點(diǎn)和終點(diǎn),而對(duì)于包含跳邊的密碼序列,孤點(diǎn)的個(gè)數(shù)則不一定為2個(gè),因此在根據(jù)圖形確定密碼序列時(shí),確定起點(diǎn)和終點(diǎn)也有一定的難度,密碼也就更安全一些。通過(guò)程序計(jì)算,我們可以知道,所有389112個(gè)密碼序列種包含跳邊的密碼共有249232個(gè),圖形則有223804個(gè)。通過(guò)統(tǒng)計(jì)每一個(gè)圖案孤點(diǎn)的個(gè)數(shù),可以發(fā)現(xiàn):在所有包含跳邊的密碼對(duì)應(yīng)的圖像中,包含最多孤點(diǎn)的圖案包含的孤點(diǎn)個(gè)數(shù)為4。在223804個(gè)圖案中,有52168個(gè)圖案有1個(gè)孤點(diǎn),108616個(gè)圖案有2個(gè)孤點(diǎn),57124個(gè)圖案有3個(gè)孤點(diǎn),1896個(gè)圖案有4個(gè)孤點(diǎn)。對(duì)于這四種情況,這里僅列舉一個(gè)樣例如下:

最后,需要說(shuō)明一點(diǎn):如果密碼設(shè)置得太復(fù)雜,在記憶和解鎖繪圖時(shí)也會(huì)很不方便,因此,根據(jù)自己的實(shí)際需求設(shè)置合適的密碼即可。

總結(jié)

以上是生活随笔為你收集整理的编程探究智能手机的图案解锁的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。

如果覺(jué)得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。