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

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

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

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

概述

? ? 圖案解鎖是現(xiàn)今智能手機比較常見的解鎖方式,用戶通過在3×3的點陣中繪制圖案來設置密碼,解鎖時,也通過實時繪制圖案來實現(xiàn)解鎖驗證。例如,下圖就是幾個解鎖的圖案示例:

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

繪圖規(guī)則

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

(1) 繪制的圖案是一條經(jīng)過若干個點的折線軌跡,至少要經(jīng)過4個點。

(2) 點陣中每個點只能經(jīng)過1次,軌跡中也一定沒有回路。

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

此時,軌跡:2->1->3->5是正確的,當從點1到達點3時,點2已經(jīng)被經(jīng)過,因此可以從點1到達點3,而軌跡1->3->2->5則是錯誤的,因為從點1到達點3是,點2未被經(jīng)過,不能從點1到達點3,如下圖:


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

編程分析

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

·邊的分類

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

下圖描述了4種類型的邊的情況:


在Java代碼中,我們用整型常量代表每一種邊的類型,同時用鄰接矩陣的方式表示圖中任意兩點的邊,代碼如下:

/*** Edge types.*/private static final int NONE = 0, // 無邊 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列記錄了點i到點j之間的邊的類型,由于數(shù)組下標從0開始,而我們的編號為1-9,因此在鄰接矩陣中有冗余的第0行和第0列,編號為0的點不存在,因此和其他點的邊也不存在,記為NONE,另外,同一個點之間也沒有邊,因此第i行第i列的元素總是NONE。

·跳邊的規(guī)則

? ? 根據(jù)前文中對于跳邊的描述,只有中介點被經(jīng)過時,跳邊才可用,我們需要在代碼中將這些規(guī)則記錄下來,這里采用Map容器來存儲,其中key值為跳邊的端點,value值為中介點,為了便于表示,這里將key值轉(zhuǎn)換為字符串,格式為"v1#v2",其中v1和v2是端點的編號,代碼實現(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);

·圖和密碼的表示和存儲

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

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

/*** 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); 這里通過map來存儲每一條邊的編號。
? ? 對于密碼,則可以對應一組點的序列,根據(jù)這個序列將對應點順次用邊連接就唯一地代表一個密碼序列,因此我們用字符串來表示一個密碼序列。需要注意的是,圖形和密碼序列之間并不是一一對應的關系,在某些情況下,不同的密碼序列可以得到相同的圖形。比較容易想到的情況是,對于一個給定的圖形,交換首尾起點就可以得到2個不同的密碼序列,如下圖:

在代碼中,我們用Map來圖形和密碼的映射關系,如下:

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

·搜索計算

? ? 最后通過基于深度優(yōu)先搜索的方式遍歷的方式遍歷所有的密碼序列,對上文中的存儲圖形和密碼的map進行填充,代碼如下: /*** 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;}}? ?? 這里需要關注的是:首先在遍歷過程中遇到跳邊時,需要判定中介點是否已經(jīng)被訪問,如果已被訪問,則此時跳邊可用,繼續(xù)向下一層搜索,否則跳邊不可用,另外,筆者在編寫代碼過程中,加入了check函數(shù),用于判定當前密碼序列是否合法,通過修改check函數(shù)的實現(xiàn),我們可以從不同的角度來獲取響應的統(tǒng)計信息。 ? ??
? ? 以上為編碼實現(xiàn)的思路。

一些統(tǒng)計信息

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

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

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

·關于圖案和密碼的對應關系

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

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


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

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


·基于邊的類型的統(tǒng)計信息

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

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

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


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

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

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

密碼長度圖案個數(shù)密碼個數(shù)
48081624
539647152
61594826016
74907672912
8103656140704
9112160140704

·關于跳邊和孤點

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

? ??

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

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

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

總結

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

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