/* * AndroidPW.c: Compute the number of Android grid-path passwords. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * * Copyright (c) 2011 Paul E. McKenney, IBM Corporation. */ #include /* * Nodes numbered like a touch-tone phone, only starting with zero: * * 0 1 2 * 3 4 5 * 6 7 8 * * Rules governing paths: * Can move only in straight line segments from one node to another. * If the previous line segment arrived at a node, the next must leave it. * Cannot visit a node twice. * Cannot pass through a node without visiting unless already visited. * Example: 0->8 is allowed only if 4 already visited. * Otherwise, attemping 0->8 gets you 0->4->8. * A path must visit at least four nodes. (new) * */ /* * Key for connectmatrix[n][m]: * 0: Cannot go from n to m. * 1: Can always go from n to m if m unvisited. * -p: Can go from n to m is p has already been visited. * * Alternative approach: use bitmask, where bit i indicates that i must * already have been visited. Explicit check required to avoid n->n * line segments. Automate creation of the matrix, though! */ char connectmatrix[9][9] = { /* 0 1 2 3 4 5 6 7 8 */ /* -- -- -- -- -- -- -- -- -- */ /*0*/ { 0, 1, -1, 1, 1, 1, -3, 1, -4 }, /*1*/ { 1, 0, 1, 1, 1, 1, 1, -4, 1 }, /*2*/ { -1, 1, 0, 1, 1, 1, -4, 1, -5 }, /*3*/ { 1, 1, 1, 0, 1, -4, 1, 1, 1 }, /*4*/ { 1, 1, 1, 1, 0, 1, 1, 1, 1 }, /*5*/ { 1, 1, 1, -4, 1, 0, 1, 1, 1 }, /*6*/ { -3, 1, -4, 1, 1, 1, 0, 1, -7 }, /*7*/ { 1, -4, 1, 1, 1, 1, 1, 0, 1 }, /*8*/ { -4, 1, -5, 1, 1, 1, -7, 1, 0 }, }; /* Mapping vector to rotate a path 90 degrees counter-clockwise. */ char rotatevector[9] = { 6, 3, 0, 7, 4, 1, 8, 5, 2 }; /* * Does "path" already visit node "next"? */ int contains(char *path, int length, char next) { int i; for (i = 0; i < length; i++) if (path[i] == next) return 1; return 0; } /* * Rotate "path" 90 degrees counterclockwise in place, overwriting "path". */ void rotate(char *path, int length) { int i; for (i = 0; i < length; i++) path[i] = rotatevector[path[i]]; } /* * Print "path". If "rotationallowed", print the four rotations. */ void dumppath(char *path, int length, int rotationallowed) { int i; char rotpath[10]; for (i = 0; i < length; i++) { printf("%d ", path[i]); rotpath[i] = path[i]; } printf("\n"); if (rotationallowed) { rotate(rotpath, length); dumppath(rotpath, length, 0); rotate(rotpath, length); dumppath(rotpath, length, 0); rotate(rotpath, length); dumppath(rotpath, length, 0); } } /* * Recursively search the path space given an initial node. */ int trynext(char *path, int length, int rotationallowed) { int cur = path[length - 1]; int i; int step; int sum = length >= 4; if (contains(path, length - 1, cur)) return 0; if (length >= 4) dumppath(path, length, rotationallowed); for (i = 0; i <= 8; i++) { step = connectmatrix[cur][i]; if (step == 0) continue; if (step < 0 && !contains(path, length, -step)) continue; path[length] = i; sum += trynext(path, length + 1, rotationallowed); } return sum; } /* * Generate the initial node for trynext(). */ int startpath(int cur, int rotationallowed) { char path[10]; path[0] = cur; return trynext(path, 1, rotationallowed); } int main(int argc, char *argv[]) { int i; int j; int sum = 0; for (i = 0; i <= 8; i++) { if (connectmatrix[i][i] != 0) printf("Node %d fails to exclude itself.\n", i); if (connectmatrix[i][8 - i] != -4 && i != 4) printf("Node %d fails to consider center node.\n", i); for (j = 0; j < i; j++) { if (connectmatrix[i][j] != connectmatrix[j][i]) printf("Asymmetry: nodes %d and %d.\n", i, j); } } sum += 4 * startpath(0, 1); sum += 4 * startpath(1, 1); sum += startpath(4, 0); printf("Number of paths: %d\n", sum); }