| Bytes | Lang | Time | Link |
|---|---|---|---|
| 129 | Tcl | 170525T230255Z | sergiol |
| 252 | Python 3 | 170615T151136Z | ATMunn |
| 056 | q/kdb+ | 170528T192539Z | mkst |
| 087 | Vim | 170601T003316Z | BlackCap |
| 129 | PHP | 170526T103748Z | M.E |
| 164 | JavaScript ES6 | 170525T200141Z | Justin M |
| 216 | ColdFusion | 170526T210451Z | Shawn |
| 030 | Japt | 170525T202750Z | Luke |
| 077 | PowerShell 3.0+ | 170526T032102Z | briantis |
| 6665 | Bash | 170526T145141Z | marcosm |
| 091 | Python 2 | 170525T174629Z | Martmist |
| nan | This is an adaptation of Martmists' answer | 170525T205249Z | dain |
| 071 | Mathematica | 170526T042651Z | Ian Mill |
| 178 | Mathematica | 170525T172947Z | ZaMoC |
| 022 | Jelly | 170525T210109Z | Jonathan |
| 083 | Ruby | 170525T201718Z | daniero |
Tcl, 129 bytes
Not a winner for sure, but I think it can be a golfed a little more.
time {set p "";time {set p [string tot [lindex $d [expr int(rand()*[llength $d])]]]$p} 4;puts $p\ [expr 5.7004*[string le $p]]} 5
Python 3, 252 bytes
This is my first ever code golf challenge I've done! I know there are other Python answers on here (that are probably better than mine) but this looked fun, and so I wanted to try it anyways. Here's the golfed version:
import random, math
with open("d") as f: d=f.read()
l=d.split()
for a in range(5):
u=[]
p=""
for b in range(4):
w=random.choice([w for w in l if not w in u and len(w)>=4])
u.append(w)
w=w.title()
p+=w
print("%s %s"%(p,math.log2(52)*len(p)))
I would post a Try it Online! link, but that doesn't support multiple files. So here's a repl.it link: https://repl.it/InIl/0
Also, here's the ungolfed version:
import random
import math
with open("d") as f:
dictionary = f.read() #this is the dictionary text file, simply saved as "d" as to use as few bytes as possible
words = dictionary.split() #here we turn that dictionary string into a list
for a in range(5): #here we iterate through 5 passwords
used_words = []
password = ""
for b in range(4): #here we iterate through the 4 words in each password
word = ""
word = random.choice([word for word in words if not word in used_words and len(word) >= 4]) #Thanks to blackadder1337 from #python on freenode IRC for helping me with this.
used_words.append(word)
word = word.title()
password = password + word
print("%s %s"%(password, math.log2(52) * len(password)))
Like I said, this is my first time code gofling, so I'm sure this could be improved a lot.
q/kdb+, 76 74 65 56 bytes
Solution:
{(x;5.70044*(#)x)}(,/)@[;0;upper]each -4?" "vs(*)(0:)`:w
Example:
q){(x;5.70044*(#)x)}(,/)@[;0;upper]each -4?" "vs(*)(0:)`:w
"RulingOverheadSaddensPriest"
153.9119
Explanation:
Read in the word list, break apart on " ", pick 4 random words from this list, uppercase first letter of each word, then join together. Feed this into a lambda function which returns the password and the calculated 'entropy':
`:w / the wordlist is a file called 'w'
(0:) / read in the file list (\n separated list)
(*) / take first (and only) item in the list
" "vs / split this on " "
-4? / take 4 random items from this list, neg means 'dont put back'
@[; ; ] / apply a function to variable at indices (variable is implicit)
upper / uppercase (the function being applied)
0 / index 0, the first character
each / each of the 4 random items
(,/) / 'raze' (flatten lists)
{ } / anonymous lambda function
(x; ) / a 2-item list, x is first item
(#)x / count x, return the length of the list
5.70044* / multiply by 5.70044
Notes:
I caved in and used 5.70044 instead of 2 xlog 52 xexp...
Vim, 87 keystrokes
qq:r!echo "$RANDOM"l<CR>D:w o|e w<CR>@"ev4bd:w|bp<CR>p0~wX~wX~wX~Y:.!wc -c<CR>A*5.7003<Esc>:.!bc<CR>PJq4@q
Assumes that the dictionary is in a file named w. Will always use 4 consecutive words
Explanation:
qq Start recording a macro named 'q'
:r!echo "$RANDOM"l<CR> Append the result of the shell command `echo "$RANDOM"l`
D Delete what you just appended
:w o| Save the buffer to the file 'o' and ..
e w<CR> Open the file 'w'
@" Execute the text we deleted as a normal-mode command
This will move the cursor a random number of characters
to the right
e Go to the end of the next word
v4bd Delete 4 words backwards
:w| Save the file and ..
bp<CR> Open the last buffer (the 'o' file)
p Paste the 4 words we deleted
0 Move the cursor to the beginning of the line
~wX~wX~wX~ Remove the spaces between the words and capitalize
Y Copy current line
:.!wc -c<CR> Pipe the current line through 'wc -c'
A*5.7003<Esc> Append "*5.7003" to the end of the line
:.!bc<CR> Pipe the current line through 'bc'
P Paste the password above the current line
J Join with line bellow
q Stop recording the 'q' macro
4@q Run the 'q' macro 4 times
PHP, 136 129 bytes
-7 bytes, thanks Jörg
for(shuffle($a);$i++<5;){for($s='',$c=0;$c<4;)strlen($w=$a[$k++])<4?:$s.=ucfirst($w).!++$c;echo$s.' '.log(52, 2)*strlen($s)."
";}
JavaScript (ES6), 164 bytes
d=>{for(i=5;i--;)console.log(p="....".replace(/./g,_=>(w=d.splice(Math.random()*d.length|0,1)[0])[0].toUpperCase()+w.slice(1)),(Math.log2(52)*p.length).toFixed(1))}
Assumes the dictionary is passed to the function as an array.
Test Snippet
ColdFusion 216 bytes
p={};z=arrayLen(c);for(x=0;x<5;x++){pw="";r={};while(structCount(r)<4){n=RandRange(1,z);r.append({"#c[n]#":true});}for(w in structKeyList(r)){pw&=REReplace(w,"\b(\w)","\u\1","All");};p.append({"#pw#":57*len(pw)/10})}
This works in ColdFusion 11+ and Lucee 4.5+
To run it: https://trycf.com/gist/ff14e2b27d66f28ff69ab90365361b12/acf11?theme=monokai
The TryCF link has less-golf-ish but the same code.
I didn't really expect to have a competitive golfing answer; I just wanted to see what it would take to complete this challenge in ColdFusion. Especially since there isn't much CF in these answers. :-) After the setup, it was surprisingly shorter than I expected.
My first attempt was a little shorter until I remembered that the same word can't be used more than once. Even though it's highly unlikely that the randomizer would pick the same index more than once, I dump the indexes into the keys of a structure, which will prevent duplication. Then I use that list of keys to build my final password string. I also used the math trick to find entropy.
PowerShell (3.0+), 77 bytes
1..5|%{($p=-join($d|random -c 4|%{culture|% te*|% tot* $_}));57*$p.Length/10}
Using Jonathan Allan's 57*len/10 trick.
$d contains the dictionary as an array of words. If you're playing at home and want to fill $d:
$d=-split(irm pastebin.com/raw/eMRSQ4u2)
Using a golfed version of (Get-Culture).TextInfo.ToTitleCase() to capitalize the first letter; I don't think there's a shorter way to do that in PowerShell.
The rest is pretty straightforward I think.
The TIO link has the whole dictionary; disable the cache and go nuts!
Bash, 66 65 bytes
for w in `shuf -n4 -`;{((l+=${#w}));printf ${w^};};bc<<<$l*5.7004
Dictionary is recived by STDIN. Shuffles all words in dictionary and outputs first 4.
For each word, adds up its length in var l, and echoes the word capitalized. In the end calls bc to do the math.
Awk solution, 112 bytes, four passwords:
shuf -n16 -|xargs -n4|awk '{for(i=1;i<5;i++)printf toupper(substr($i,1,1))substr($i,2);print(length($0)-3)*5.7}'
Python 2, 102 101 97 91 bytes
from random import*
exec"x=''.join(x.title()for x in sample(f,4));print(x,57*len(x)/10);"*5
Assumes the dictionary as a list named f.
Can be tested by saving the file as dict.txt and calling
f = open('dict.txt').readlines()
(This is an adaptation of Martmists' answer, but I don't have the rep to comment)
Python, 88 86 bytes
g={*f}
exec('x="".join(g.pop().title()for i in "a"*4);print(x,len(x)*5.700439718);'*5)
By exploiting how set is nondeterministic, you can avoid having to import any randomness libraries.
Mathematica, 71 Bytes
Assuming the dictionary is already loaded into an array called d.
Table[{#,Log[2,52]StringLength[#]}&[""<>Capitalize@d~RandomSample~4],5]
Explaination:
Capitalize@d - Capitalize all the dictionary
~RandomSample~4 - make an array with 4 values. By default values can not repeat.
""<> - Concatenate with empty string to turn array into single string.
{#,Log[2,52]StringLength[#]}&[ ] - Put current string next to log(2,52) times length of current string
Table[ ,5] - Repeat this 5 times.
Mathematica, 178 bytes
t=1;l=Length;While[t<6,s=RandomChoice[Import["https://pastebin.com/raw/eMRSQ4u2"],4];c=Capitalize/@s;f=Flatten@Characters[c];Print[StringJoin[c]," ",Log[2,l@Union@f]*l@f//N];t++]
copy and paste using ctrl-v and press shift+enter to run
Mathematica, 136 bytes
assuming that m is the dictionary the code is
m=ImportString[Import["C:\a.txt"]]
.
t=1;l=Length;While[t<6,s=RandomChoice[m,4];c=Capitalize/@s;f=Flatten@Characters[c];Print[StringJoin[c]," ",Log[2,l@Union@f]*l@f//N];t++]
Jelly, 22 bytes
Ẋḣ4ŒtFµL×57÷⁵⁸,K
çЀ5Y
A monadic link taking a list of list of characters, the parsed dictionary (as allowed in chat).
Try it online! (Click "Arguments" to hide the dictionary and reduce the need to scroll.)
How?
Since the dictionary only contains valid words (4characters or more, only [a-z]), there is no need to check this condition.
Since all the words in the dictionary have lengths in [4-8] the possible password lengths are in [16,32], and the possible entropies will never round differently to one decimal place than by replacing log(52,2) with 5.7. The only problem is that using a floating point value of 5.7 will give floating point rounding errors for lengths 18, 26, and 31. However multiplying by 57 and then dividing by 10 using ×57÷⁵ avoids this (while still being a byte shorter than printing the full floating point precision value using ×52l2¤).
çЀ5Y - Main link: list of list of characters (the parsed dictionary)
5 - literal 5
Ѐ - map across the implicit range [1,2,3,4,5]:
ç - last link (1) as a dyad
Y - join with newlines
- implicit print
Ẋḣ4ŒtFµL×57÷⁵⁸,K - Link 1, get password and entropy: list of lists of characters, number
Ẋ - shuffle the list of lists (shuffle all the words)
ḣ4 - head to 4 (the first four words)
Œt - title case (make the first letter of each uppercase)
F - flatten into one list of characters
µ - monadic chain separation, call that p
L - length of p
57 - 57
× - multiply
⁵ - 10
÷ - divide -> entropy to 1 decimal place
⁸ - link's left argument, p
, - pair -> [p, entropy]
K - join with (a) space(s)
Ruby, 89 83 bytes
d.select!{|w|w[3]}
5.times{p w=d.sample(4).map(&:capitalize)*'',5.700439718*w.size}
Assumes that the passwords are stored in the variable d. You can add this line before the code:
d=$<.map(&:chomp)
and call the script for instance like this:
$ ruby generate_passwords.rb < dictionary_file.txt
Sample output:
"MarginStarvedOnusInsulted"
142.51099295
"KitchenMiseryLurkJoints"
131.110113514
"InducesNotablePitfallsPrecede"
165.312751822
"FarmersAbortFutileWrapper"
142.51099295
"RoutesBishopGlowFaithful"
136.81055323200002
KitchenMiseryLurkJoints... wow.
-6 bytes from Ajedi32