1 1.1 cgd # Towers of Hanoi in sed. 2 1.1 cgd # 3 1.2 cgd # from: @(#)hanoi.sed 8.1 (Berkeley) 6/6/93 4 1.3 tls # $NetBSD: hanoi.sed,v 1.3 1997/01/09 20:21:35 tls Exp $ 5 1.1 cgd # 6 1.1 cgd # 7 1.1 cgd # Ex: 8 1.1 cgd # Run "sed -f hanoi.sed", and enter: 9 1.1 cgd # 10 1.1 cgd # :abcd: : :<CR><CR> 11 1.1 cgd # 12 1.1 cgd # note -- TWO carriage returns, a peculiarity of sed), this will output the 13 1.1 cgd # sequence of states involved in moving 4 rings, the largest called "a" and 14 1.1 cgd # the smallest called "d", from the first to the second of three towers, so 15 1.1 cgd # that the rings on any tower at any time are in descending order of size. 16 1.1 cgd # You can start with a different arrangement and a different number of rings, 17 1.1 cgd # say :ce:b:ax: and it will give the shortest procedure for moving them all 18 1.1 cgd # to the middle tower. The rules are: the names of the rings must all be 19 1.1 cgd # lower-case letters, they must be input within 3 fields (representing the 20 1.1 cgd # towers) and delimited by 4 colons, such that the letters within each field 21 1.1 cgd # are in alphabetical order (i.e. rings are in descending order of size). 22 1.1 cgd # 23 1.1 cgd # For the benefit of anyone who wants to figure out the script, an "internal" 24 1.1 cgd # line of the form 25 1.1 cgd # b:0abx:1a2b3 :2 :3x2 26 1.1 cgd # has the following meaning: the material after the three markers :1, :2, 27 1.1 cgd # and :3 represents the three towers; in this case the current set-up is 28 1.1 cgd # ":ab : :x :". The numbers after a, b and x in these fields indicate 29 1.1 cgd # that the next time it gets a chance, it will move a to tower 2, move b 30 1.1 cgd # to tower 3, and move x to tower 2. The string after :0 just keeps track 31 1.1 cgd # of the alphabetical order of the names of the rings. The b at the 32 1.1 cgd # beginning means that it is now dealing with ring b (either about to move 33 1.1 cgd # it, or re-evaluating where it should next be moved to). 34 1.1 cgd # 35 1.1 cgd # Although this version is "limited" to 26 rings because of the size of the 36 1.1 cgd # alphabet, one could write a script using the same idea in which the rings 37 1.1 cgd # were represented by arbitrary [strings][within][brackets], and in place of 38 1.1 cgd # the built-in line of the script giving the order of the letters of the 39 1.1 cgd # alphabet, it would accept from the user a line giving the ordering to be 40 1.1 cgd # assumed, e.g. [ucbvax][decvax][hplabs][foo][bar]. 41 1.1 cgd # 42 1.1 cgd # George Bergman 43 1.1 cgd # Math, UC Berkeley 94720 USA 44 1.1 cgd 45 1.1 cgd # cleaning, diagnostics 46 1.1 cgd s/ *//g 47 1.1 cgd /^$/d 48 1.1 cgd /[^a-z:]/{a\ 49 1.1 cgd Illegal characters: use only a-z and ":". Try again. 50 1.1 cgd d 51 1.1 cgd } 52 1.1 cgd /^:[a-z]*:[a-z]*:[a-z]*:$/!{a\ 53 1.1 cgd Incorrect format: use\ 54 1.1 cgd \ : string1 : string2 : string3 :<CR><CR>\ 55 1.1 cgd Try again. 56 1.1 cgd d 57 1.1 cgd } 58 1.1 cgd /\([a-z]\).*\1/{a\ 59 1.1 cgd Repeated letters not allowed. Try again. 60 1.1 cgd d 61 1.1 cgd } 62 1.1 cgd # initial formatting 63 1.1 cgd h 64 1.1 cgd s/[a-z]/ /g 65 1.1 cgd G 66 1.1 cgd s/^:\( *\):\( *\):\( *\):\n:\([a-z]*\):\([a-z]*\):\([a-z]*\):$/:1\4\2\3:2\5\1\3:3\6\1\2:0/ 67 1.1 cgd s/[a-z]/&2/g 68 1.1 cgd s/^/abcdefghijklmnopqrstuvwxyz/ 69 1.1 cgd :a 70 1.1 cgd s/^\(.\).*\1.*/&\1/ 71 1.1 cgd s/.// 72 1.1 cgd /^[^:]/ba 73 1.1 cgd s/\([^0]*\)\(:0.*\)/\2\1:/ 74 1.1 cgd s/^[^0]*0\(.\)/\1&/ 75 1.1 cgd :b 76 1.1 cgd # outputting current state without markers 77 1.1 cgd h 78 1.1 cgd s/.*:1/:/ 79 1.1 cgd s/[123]//gp 80 1.1 cgd g 81 1.1 cgd :c 82 1.1 cgd # establishing destinations 83 1.1 cgd /^\(.\).*\1:1/td 84 1.1 cgd /^\(.\).*:1[^:]*\11/s/^\(.\)\(.*\1\([a-z]\).*\)\3./\3\2\31/ 85 1.1 cgd /^\(.\).*:1[^:]*\12/s/^\(.\)\(.*\1\([a-z]\).*\)\3./\3\2\33/ 86 1.1 cgd /^\(.\).*:1[^:]*\13/s/^\(.\)\(.*\1\([a-z]\).*\)\3./\3\2\32/ 87 1.1 cgd /^\(.\).*:2[^:]*\11/s/^\(.\)\(.*\1\([a-z]\).*\)\3./\3\2\33/ 88 1.1 cgd /^\(.\).*:2[^:]*\12/s/^\(.\)\(.*\1\([a-z]\).*\)\3./\3\2\32/ 89 1.1 cgd /^\(.\).*:2[^:]*\13/s/^\(.\)\(.*\1\([a-z]\).*\)\3./\3\2\31/ 90 1.1 cgd /^\(.\).*:3[^:]*\11/s/^\(.\)\(.*\1\([a-z]\).*\)\3./\3\2\32/ 91 1.1 cgd /^\(.\).*:3[^:]*\12/s/^\(.\)\(.*\1\([a-z]\).*\)\3./\3\2\31/ 92 1.1 cgd /^\(.\).*:3[^:]*\13/s/^\(.\)\(.*\1\([a-z]\).*\)\3./\3\2\33/ 93 1.1 cgd bc 94 1.1 cgd # iterate back to find smallest out-of-place ring 95 1.1 cgd :d 96 1.1 cgd s/^\(.\)\(:0[^:]*\([^:]\)\1.*:\([123]\)[^:]*\1\)\4/\3\2\4/ 97 1.1 cgd td 98 1.1 cgd # move said ring (right, resp. left) 99 1.1 cgd s/^\(.\)\(.*\)\1\([23]\)\(.*:\3[^ ]*\) /\1\2 \4\1\3/ 100 1.1 cgd s/^\(.\)\(.*:\([12]\)[^ ]*\) \(.*\)\1\3/\1\2\1\3\4 / 101 1.1 cgd tb 102 1.1 cgd s/.*/Done! Try another, or end with ^D./p 103 1.1 cgd d 104