Updates to 2018/ferguson
Format changes in the README.md. Update the test.sh and test-strings.txt files: modify the goodbye message in the script (for fun) and add some fun strings for it to search out.
This commit is contained in:
1 parent
2661548b08
commit
c7fc0959b3
3 files changed
+127
-119
No files matched your search
+118
-118
@@ -103,7 +103,7 @@ more thorough than this.
|
||||
program; if you're familiar with genetic algorithms there won't be any problem
|
||||
following this section but it might be of some value to read anyway. There is a
|
||||
randomised mode that doesn't use a genetic algorithm; it can be triggered a
|
||||
number of ways but the **`-m`** option enables it specially (I discuss this
|
||||
number of ways but the `-m` option enables it specially (I discuss this
|
||||
thoroughly in **[Hints](#hints)**).
|
||||
|
||||
**[Hints](#hints):** Perhaps the longest part of this document because in it I
|
||||
@@ -116,16 +116,16 @@ don't need this unless there is something specific you're after.
|
||||
**[Obfuscation](#obfuscation):** Some of the techniques that might not be used.
|
||||
|
||||
**[How to build](#build):** Here I describe briefly
|
||||
[the constants that can be redefined](#constants) **`S`** and **`N`**: the
|
||||
maximum size of the chromosome (target string; the maximum length is **`S - 1`**
|
||||
[the constants that can be redefined](#constants) `S` and `N`: the
|
||||
maximum size of the chromosome (target string; the maximum length is `S - 1`
|
||||
but it must be >= the default 38) and the number of offspring, respectively. I
|
||||
also give [example compiler invocations](#compiling), [portability
|
||||
notes](#portability), an [more portability notes](#bugs) and a [note on
|
||||
rpm.md](#rpm).
|
||||
|
||||
On the subject of **`S`** and **`N`**: As the judges' suggested runs imply you
|
||||
can change the target string at runtime; **`make test`** runs a script
|
||||
*`test.sh`* which reads from the file *`test-strings.txt`*, running the program
|
||||
On the subject of `S` and `N`: As the judges' suggested runs imply you
|
||||
can change the target string at runtime; `make test` runs a script
|
||||
`test.sh` which reads from the file `test-strings.txt`, running the program
|
||||
for each string in the file, waiting approximately two seconds before
|
||||
continuing. I explain how to pass options to the script in part of
|
||||
**[Hints](#test)**.
|
||||
@@ -162,8 +162,8 @@ He refers to the [Infinite Monkey Theorem][] (Wikipedia). As he points out the
|
||||
operative phrase is *given enough time*; but even if it's extremely unlikely
|
||||
*technically the probability is greater than 0*. He simplified it for the
|
||||
monkey; I thought the monkey had it too easy: unlike his limited keyboard I have
|
||||
(besides space) every character in the ASCII range **`0<=126`** that
|
||||
**`isprint()`** returns non-zero except that only capital letters are included;
|
||||
(besides space) every character in the ASCII range `0<=126` that
|
||||
`isprint()` returns non-zero except that only capital letters are included;
|
||||
the file [prog.alt.c](prog.alt.c) has a slightly smaller keyboard. There are some
|
||||
additional features I have added (including two Easter eggs); amongst others:
|
||||
ability to change the target string and maximum length. See\
|
||||
@@ -171,8 +171,8 @@ ability to change the target string and maximum length. See\
|
||||
more details.
|
||||
|
||||
In its simplest invocation this program will work its way (using a genetic
|
||||
algorithm) towards the solution of the string **`METHINKS IT IS LIKE A WEASEL`**
|
||||
(note that I use **`toupper()`** so it doesn't matter what case the input is the
|
||||
algorithm) towards the solution of the string `METHINKS IT IS LIKE A WEASEL`
|
||||
(note that I use `toupper()` so it doesn't matter what case the input is the
|
||||
comparison and output will always be capitalised).
|
||||
|
||||
[Infinite Monkey Theorem]: https://en.wikipedia.org/wiki/Infinite_monkey_theorem
|
||||
@@ -201,7 +201,7 @@ try and show the way they work) for those interested I will cite the summary:
|
||||
**SPOILER WARNING: Some of the below might help you follow the code more
|
||||
easily.**
|
||||
|
||||
For each *generation* there is a total of **`N`** *offspring*; generation 0 is
|
||||
For each *generation* there is a total of `N` *offspring*; generation 0 is
|
||||
the pseudo-randomly initialised array *without parents.* Each offspring has its
|
||||
own *chromosome* to be compared to the *target string* and a *fitness score*;
|
||||
the higher the fitness score the more likely it will be a *parent of the next
|
||||
@@ -220,11 +220,11 @@ every character will be assigned a value*). Before mutation the offspring
|
||||
chromosome will be printed; after mutation it will show what it was mutated to
|
||||
(on the same output line). After the new generation has been sequenced the loop
|
||||
goes back to the top and it starts all over until the maximum number of
|
||||
generations **`SIZE_MAX - 1`** is reached or the target chromosome has been
|
||||
generations `SIZE_MAX - 1` is reached or the target chromosome has been
|
||||
found.
|
||||
|
||||
Note that the generation is checked *before the scoring takes place* by a prefix
|
||||
increment equality check; when the generation is **`SIZE_MAX - 1`** the fitness
|
||||
increment equality check; when the generation is `SIZE_MAX - 1` the fitness
|
||||
test loop will not be entered; instead the outer loop will end after printing:
|
||||
|
||||
> Too many attempts, blaming the monkey Eric even if he isn't typing or doesn't exist. Bye.
|
||||
@@ -236,7 +236,7 @@ exist. The second to last example limitation example note (it's improved in the
|
||||
final but this is relevant) they give is:
|
||||
|
||||
> The judges might not have a pet fish named Eric, so might want to state:
|
||||
>\
|
||||
>
|
||||
> This entry factors integers between 1 and 2305567963945518424753102147331756070.
|
||||
> Attempting to factor anything else will cause the program to insult your
|
||||
> pet fish Eric, or in the case that you lack such a pet, will insult the
|
||||
@@ -248,7 +248,7 @@ After the final message they ask:
|
||||
|
||||
The answer is this: **it is the primorial prime of 97:** the product of all
|
||||
prime numbers less than or equal to N; **and the primorial prime of `N == 97` is
|
||||
`2305567963945518424753102147331756070`**. There is no reference to this number
|
||||
`2305567963945518424753102147331756070`. There is no reference to this number
|
||||
in my entry but it's nonetheless possible to **change the default target to it
|
||||
without modifying the source code**; there are two hints in this very
|
||||
paragraph; the first sentence in fact: the answer to the judges' question and
|
||||
@@ -261,12 +261,12 @@ second time for the same entry.
|
||||
|
||||
### On <del>user</del> monkey errors
|
||||
|
||||
If the generation reaches **`SIZE_MAX - 1`** I consider it a monkey (or if you
|
||||
If the generation reaches `SIZE_MAX - 1` I consider it a monkey (or if you
|
||||
insist: user) error; if the user insists on being so petulant enough as to try
|
||||
such a ridiculous set of parameters in an attempt to make it be no more
|
||||
successful than a monkey typing *then it shouldn't be any more successful than a
|
||||
monkey; if it by chance reaches the target it's because a monkey could too!*
|
||||
Either way unless the number reaches **`SIZE_MAX - 1`** the monkey Eric won't be
|
||||
Either way unless the number reaches `SIZE_MAX - 1` the monkey Eric won't be
|
||||
blamed. It should be noted that depending on the parameters (size of chromosome,
|
||||
number of offspring, the string itself) the program could take quite a lot of
|
||||
system resources; and whether the OS kills it, Eric the monkey falls asleep or
|
||||
@@ -296,8 +296,8 @@ Skip to [Options](#options).
|
||||
|
||||
The keyboard, as noted, has more than just the alphabet and space. To be
|
||||
precise the following characters are acceptable; it equates to this in C (note
|
||||
it includes a literal space **`' '`** but it doesn't include other
|
||||
**`isspace()`** characters) and this is why some of the characters are escaped:
|
||||
it includes a literal space `' '` but it doesn't include other
|
||||
`isspace()` characters) and this is why some of the characters are escaped:
|
||||
|
||||
const char keyboard[]=" !\"#$<%:>&'()*+,-./0123456789;=?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`{|}~";
|
||||
|
||||
@@ -316,7 +316,7 @@ Skip to [Spoilers](#spoiler).
|
||||
|
||||
There are a number of options you can pass to the program besides the target
|
||||
string; some I will document here (the summary being in the man page). You can
|
||||
join options but there is a caveat with spaces and **`-r`** option as well as
|
||||
join options but there is a caveat with spaces and `-r` option as well as
|
||||
the target string (see below).
|
||||
|
||||
**Enable quiet output:**
|
||||
@@ -332,7 +332,7 @@ output) and the final answer.
|
||||
|
||||
-r<num>
|
||||
|
||||
Please note that there cannot be a space between the **`-r`** and the number.
|
||||
Please note that there cannot be a space between the `-r` and the number.
|
||||
This is to simplify the parsing of options. As for combining options you can do
|
||||
any of the following (amongst others):
|
||||
|
||||
@@ -342,9 +342,9 @@ any of the following (amongst others):
|
||||
-q -r5
|
||||
|
||||
The third invocation will set quiet output and have no valid value to parse for
|
||||
the mutation rate and **`strtol()`** in this case returns 0. **`strtol()`** can
|
||||
the mutation rate and `strtol()` in this case returns 0. `strtol()` can
|
||||
legitimately return 0 but in no instance is it valid input in this program: the
|
||||
valid mutation rate is **`>= 1 && <= 100`**.
|
||||
valid mutation rate is `>= 1 && <= 100`.
|
||||
|
||||
When the mutation rate is out of range it does something interesting: take a
|
||||
look at the output and compare it to the output when the range is valid. Can you
|
||||
@@ -371,12 +371,12 @@ decent parameters - come to an answer here but if necessary kill the program.
|
||||
offspring output. If you still don't see what it is and want to know see
|
||||
**[Spoilers](#spoiler)** below.
|
||||
|
||||
Finally any argument that doesn't start with a **`-`** passed into the program
|
||||
will become the target string. The same rule applies to the number for **`-r`**:
|
||||
Finally any argument that doesn't start with a `-` passed into the program
|
||||
will become the target string. The same rule applies to the number for `-r`:
|
||||
it must be a single parameter which means you'll need to quote the string if it
|
||||
has more than one word (that is it contains spaces) or anything else interpreted
|
||||
specially by your shell e.g. parentheses. For instance if you just want to find
|
||||
**`METHINKS`** you could do one of:
|
||||
`METHINKS` you could do one of:
|
||||
|
||||
```sh
|
||||
./weasel METHINKS
|
||||
@@ -384,7 +384,7 @@ specially by your shell e.g. parentheses. For instance if you just want to find
|
||||
./weasel 'METHINKS'
|
||||
```
|
||||
|
||||
If you wanted **`YOU ARE A MONKEY`**:
|
||||
If you wanted `YOU ARE A MONKEY`:
|
||||
|
||||
```sh
|
||||
./weasel "YOU ARE A MONKEY"
|
||||
@@ -398,12 +398,12 @@ If you do one of:
|
||||
./weasel METHINKS IT IS A MONKEY
|
||||
```
|
||||
\
|
||||
It will search for **`MONKEY`** in both cases; in other words it's the last one.
|
||||
If the string is too long given the value of **`S`** (see\
|
||||
It will search for `MONKEY` in both cases; in other words it's the last one.
|
||||
If the string is too long given the value of `S` (see\
|
||||
**[How to build](#build)**) it will be truncated.
|
||||
|
||||
If you actually do want to search for a string starting with a **`-`** you must
|
||||
disable further parsing of options by using the **`-`** option itself; for
|
||||
If you actually do want to search for a string starting with a `-` you must
|
||||
disable further parsing of options by using the `-` option itself; for
|
||||
example if you were to do any of:
|
||||
|
||||
```sh
|
||||
@@ -412,14 +412,14 @@ example if you were to do any of:
|
||||
./weasel -q -- -test
|
||||
```
|
||||
|
||||
The target string will be: **`-TEST`**. This means though that here:
|
||||
The target string will be: `-TEST`. This means though that here:
|
||||
|
||||
```sh
|
||||
./weasel -q -- -test -r5
|
||||
```
|
||||
|
||||
The string to be searched would actually be **`-r5`** and the mutation rate
|
||||
will remain the default because after the **`-`** option is seen it will no
|
||||
The string to be searched would actually be `-r5` and the mutation rate
|
||||
will remain the default because after the `-` option is seen it will no
|
||||
longer parse additional options: only target strings if anything left on the
|
||||
command line. Because of the joining of arguments this means that the first two
|
||||
examples of the last set of three above are equivalent i.e. the following two
|
||||
@@ -437,8 +437,8 @@ As for the caveat I referenced what does the following do?
|
||||
In fact it will set quiet output and set the target string to be '5'. So the
|
||||
mutation rate will be out of range, thus enabling that Easter egg, but it will
|
||||
likely come to an answer fairly quickly because it's just a single character. A
|
||||
note on the parsing of the **`-`** option; if the program is currently parsing
|
||||
**`argv[N]`**, for example, and it encounters a **`--`** then depending on where
|
||||
note on the parsing of the `-` option; if the program is currently parsing
|
||||
`argv[N]`, for example, and it encounters a `--` then depending on where
|
||||
the other options are in the command line it might still parse the options. Thus
|
||||
you have:
|
||||
|
||||
@@ -466,11 +466,11 @@ If you were instead to do one of (for example):
|
||||
./weasel -q -q- -r
|
||||
```
|
||||
|
||||
Then it *would* set quiet output then see the **`--`** (the **`-`** option
|
||||
itself) and then the target string would *literally* be set to **`-r`** because
|
||||
it no longer cares about the **`-`** for option parsing. In other words options
|
||||
are only parsed if the first character is **`-`** and if the parser hasn't seen
|
||||
the **`-`** - *in an earlier element of `argv`. This is not a bug!*
|
||||
Then it *would* set quiet output then see the `--` (the `-` option
|
||||
itself) and then the target string would *literally* be set to `-r` because
|
||||
it no longer cares about the `-` for option parsing. In other words options
|
||||
are only parsed if the first character is `-` and if the parser hasn't seen
|
||||
the `-` - *in an earlier element of `argv`. This is not a bug!*
|
||||
|
||||
### <a name="spoiler">Spoilers</a>
|
||||
|
||||
@@ -485,20 +485,20 @@ select characters for every character in the target string; that is to say if
|
||||
the string is of length 28 (the default) then all 28 characters in each
|
||||
offspring of each generation will be assigned a pseudo-randomly positioned
|
||||
character in the keyboard. If you want to enable this specially you can use the
|
||||
**`-m`** option (*-m for monkey*).
|
||||
`-m` option (*-m for monkey*).
|
||||
|
||||
### <a name="invocations">Example Invocations</a>
|
||||
|
||||
Skip to [Input Error Example](#error).
|
||||
|
||||
The following examples are used to demonstrate better the command line parsing.
|
||||
In order to do that though I had to first document the **`-m`** option because
|
||||
In order to do that though I had to first document the `-m` option because
|
||||
if the mutation rate is out of range monkey mode is activated (that's the first
|
||||
Easter egg). But what happens if you later set a valid mutation rate? Should
|
||||
monkey mode be disabled? If yes how do we know if monkey mode was specially
|
||||
requested? There are at least two ways to go about it: I took the monkey safe
|
||||
('fool safe') method; *if you explicitly request monkey mode you cannot disable
|
||||
it in the same invocation of `weasel`*!
|
||||
it in the same invocation of `weasel`!
|
||||
|
||||
```sh
|
||||
$ ./weasel -qr101r5r101r1r test
|
||||
@@ -514,51 +514,51 @@ Generation 16844 Offspring 22: TEST
|
||||
|
||||
So in this case I joined the options in the following order:
|
||||
|
||||
1. **`-q`**
|
||||
1. `-q`
|
||||
|
||||
Quiet output.
|
||||
|
||||
|
||||
2. **`-r101`**
|
||||
2. `-r101`
|
||||
|
||||
Mutation rate 101 (out of range).
|
||||
|
||||
|
||||
3. **`-r5`**
|
||||
3. `-r5`
|
||||
|
||||
Mutation rate of 5 but note that during parsing I only print invalid mutation
|
||||
rate (only after parsing do I print the final mutation rate whatever it ends up
|
||||
being); so while it appears there is a bug, showing mutation rate out of range
|
||||
three times, this is expected (given the next one, **`-r101`**). This means here
|
||||
three times, this is expected (given the next one, `-r101`). This means here
|
||||
the typewriter was taken from Eric the monkey.
|
||||
|
||||
|
||||
4. **`-r101`**
|
||||
4. `-r101`
|
||||
|
||||
Mutation rate to 101: this too is out of range (this is the second mutation rate
|
||||
out of range message). The typewriter returns to Eric.
|
||||
|
||||
|
||||
5. **`-r1`**
|
||||
5. `-r1`
|
||||
|
||||
|
||||
Set mutation rate to 1. Take that typewriter away!
|
||||
|
||||
|
||||
6. **`-r`**
|
||||
6. `-r`
|
||||
|
||||
Set mutation rate to 0; when there are no valid characters passed to
|
||||
**`strtol()`** it should return 0: this is the third message about being out of
|
||||
range. Note here that **`rand()`** returns an **`int`** and **`strtol()`**
|
||||
returns a **`long`** but I compare the return value of **`rand()`** to the
|
||||
`strtol()` it should return 0: this is the third message about being out of
|
||||
range. Note here that `rand()` returns an `int` and `strtol()`
|
||||
returns a `long` but I compare the return value of `rand()` to the
|
||||
mutation rate; if there are any systems where the widths differ this *shouldn't
|
||||
matter* because of truncation but I do in any case specifically check for **`R <
|
||||
0 || R > 100`**. Either way the invalid range returns the typewriter to Eric.
|
||||
matter* because of truncation but I do in any case specifically check for `R <
|
||||
0 || R > 100`. Either way the invalid range returns the typewriter to Eric.
|
||||
|
||||
|
||||
7. **`test`**
|
||||
7. `test`
|
||||
|
||||
Finally I requested it find the string **`test`** (will search for **`TEST`**).
|
||||
Finally I requested it find the string `test` (will search for `TEST`).
|
||||
|
||||
Given that it was a short string it did find the answer relatively quickly, even
|
||||
in monkey mode.
|
||||
@@ -575,7 +575,7 @@ Generation 109 Offspring 13: TEST
|
||||
```
|
||||
|
||||
In this case I also enabled quiet mode but I didn't join the options; the
|
||||
**`-r101`** reports that it's out of range and sets monkey mode. I then specify
|
||||
`-r101` reports that it's out of range and sets monkey mode. I then specify
|
||||
the target string and then set a valid mutation rate. This disabled monkey mode
|
||||
which means that it'll use the genetic algorithm.
|
||||
|
||||
@@ -595,7 +595,7 @@ Here I also requested quiet output and then *explicitly requested that Eric the
|
||||
monkey types.* After this I set the mutation rate to be 101 which would have
|
||||
set monkey mode (*in this case only temporarily as I later set it to a valid
|
||||
number*) but since I have also requested monkey mode that won't matter. Then I
|
||||
set the string to **`test`** and then set a valid mutation rate of 5. Now note
|
||||
set the string to `test` and then set a valid mutation rate of 5. Now note
|
||||
that it is actually set to 5 but also note that monkey mode remains active: it
|
||||
also took a lot longer to come to a conclusion for even four characters. This
|
||||
example does demonstrate one other thing in a subtle way though.
|
||||
@@ -616,10 +616,10 @@ Whereas with quiet output:
|
||||
|
||||
Of course it isn't only down to the printing but the point is it slows it down
|
||||
significantly. Adding an option to print every X lines would go over the limit
|
||||
(**`iocccsize -i`** reports 2052!).
|
||||
(`iocccsize -i` reports 2052!).
|
||||
|
||||
Finally I'll show a default example in normal output (I omit many lines showing
|
||||
instead **[...]**). Note that the real/user/sys times are from the **`time`**
|
||||
instead **[...]**). Note that the real/user/sys times are from the `time`
|
||||
bash shell built-in utility: that isn't output from my entry.
|
||||
|
||||
|
||||
@@ -650,9 +650,9 @@ Keep in mind the way I display the generations and the fact that generation 0
|
||||
has no parents; it is generation 1 that starts working towards the goal. You'll
|
||||
see also **(mutation)** at the end of the line at this point (if you enable
|
||||
monkey mode you'll find that it shows something else). The lines that only have
|
||||
`**` are separators: you won't see this between generation 0 and 1 but you will
|
||||
`` are separators: you won't see this between generation 0 and 1 but you will
|
||||
between future generations - as well as the final answer (if the answer is in
|
||||
generation 0 you won't see the `**`).
|
||||
generation 0 you won't see the ``).
|
||||
|
||||
<a name="test"></a>
|
||||
One final thing to consider is that **the program doesn't directly read from a
|
||||
@@ -666,17 +666,17 @@ people. Take the following invocations:
|
||||
(5) $ < test-strings.txt ./weasel
|
||||
(6) $ cat | ./weasel
|
||||
|
||||
Only the first invocation of **`./weasel`** will search for **`TEST`** because
|
||||
the string **`test`** was explicitly passed to the program (If the file *`test`*
|
||||
wasn't found by that path it would still have searched for **`TEST`**).
|
||||
Only the first invocation of `./weasel` will search for `TEST` because
|
||||
the string `test` was explicitly passed to the program (If the file `test`
|
||||
wasn't found by that path it would still have searched for `TEST`).
|
||||
|
||||
The second invocation will search for the default string if there is a file or
|
||||
directory called *`test`*; else you will get an error about no such file or
|
||||
directory called `test`; else you will get an error about no such file or
|
||||
directory (unless your shell for some reason doesn't consider it an error; bash
|
||||
most certainly does consider it an error and halts).
|
||||
|
||||
The third invocation would if there exists a file *`test`* cat that file and
|
||||
pipe the output to **`./weasel`**; *however it will search for the default
|
||||
The third invocation would if there exists a file `test` cat that file and
|
||||
pipe the output to `./weasel`; *however it will search for the default
|
||||
string.* If there is no such file to cat then an error will be reported but
|
||||
without quiet mode you'd probably not even see the error.
|
||||
|
||||
@@ -684,15 +684,15 @@ The fourth invocation will also search for the default string unless the file
|
||||
doesn't exist in which case you'd get an error like in the second invocation.
|
||||
|
||||
The fifth invocation will actually search for the default string even with the
|
||||
file *`test-strings.txt`* existing. As far as I am aware it's equivalent to the
|
||||
file `test-strings.txt` existing. As far as I am aware it's equivalent to the
|
||||
third invocation except that the file exists in this case.
|
||||
|
||||
The final invocation will search for the default and then read from *`stdin`*;
|
||||
The final invocation will search for the default and then read from `stdin`;
|
||||
it won't do anything with it however.
|
||||
|
||||
What this amounts to is *if you want input from a file you have to read from the
|
||||
file and pass each string to the program itself*. I've included a script
|
||||
*`test.sh`* and a file of sample input *`test-strings.txt`* that you can play
|
||||
`test.sh` and a file of sample input `test-strings.txt` that you can play
|
||||
with.
|
||||
|
||||
|
||||
@@ -711,7 +711,7 @@ chmod +x test.sh
|
||||
|
||||
The script will first try compiling the program (if necessary) and if it fails
|
||||
for any reason it will exit; else it will read each line in the file
|
||||
*`test-strings.txt`* (if the file doesn't exist or can't be read the script will
|
||||
`test-strings.txt` (if the file doesn't exist or can't be read the script will
|
||||
exit with return status of 1) and pass it to the program. After finding the
|
||||
string it'll sleep approximately 2 seconds and then read the next string
|
||||
(passing it to the program, continuing until all the strings have been read and
|
||||
@@ -724,21 +724,21 @@ stops when there are no more strings in the file - so if you try:
|
||||
./test.sh -q test
|
||||
```
|
||||
|
||||
The final string **`test`** won't be searched for; it will however run the program
|
||||
The final string `test` won't be searched for; it will however run the program
|
||||
in all invocations with quiet output enabled. The following are some notes about
|
||||
how the shell and the program interact with each other:
|
||||
|
||||
Because the script quotes the strings that it reads from the file if you were to
|
||||
put in the file: **`-q STRING`** quiet mode would be enabled; however the
|
||||
put in the file: `-q STRING` quiet mode would be enabled; however the
|
||||
default string would be searched for. If the quotes were removed from the script
|
||||
it would print the final word specified. To be specific with the quotes: if in
|
||||
the file you had the line **`-q STRING -m TEST`** it would enable quiet output
|
||||
the file you had the line `-q STRING -m TEST` it would enable quiet output
|
||||
and monkey typewriter mode; but it would search for the default string. Without
|
||||
the quotes on the other hand it would enable quiet output, monkey typewriter and
|
||||
search for **`TEST`**. In other words **if you want to pass options to the
|
||||
search for `TEST`. In other words **if you want to pass options to the
|
||||
script you will have to directly pass the options to the script** like the above
|
||||
example shows (but the strings will still only be read from the
|
||||
*`test-strings.txt`* file).
|
||||
`test-strings.txt` file).
|
||||
|
||||
### <a name="error">Input Error Example</a>
|
||||
|
||||
@@ -747,10 +747,10 @@ Skip to [Obfuscation](#obfuscation).
|
||||
There is a type of input error, as I said, that might appear to be a bug. What
|
||||
actually is going on though is due to a technicality on how spaces are printed
|
||||
and the fact the program does not accept spaces other than a literal space\
|
||||
**` `**; when a character in the string to be found isn't in the keyboard the
|
||||
` `; when a character in the string to be found isn't in the keyboard the
|
||||
program prints an error message and then exits (returning 1). But since the
|
||||
keyboard doesn't have **`'\n'`** if you were to type a **`'`** and send a
|
||||
**`'\n'`** before the closing **`'`** you might see something like:
|
||||
keyboard doesn't have `'\n'` if you were to type a `'` and send a
|
||||
`'\n'` before the closing `'` you might see something like:
|
||||
|
||||
```sh
|
||||
$ ./weasel '!!
|
||||
@@ -760,16 +760,16 @@ $ ./weasel '!!
|
||||
' not in keyboard " !"#$<%:>&'()*+,-./0123456789;=?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`{|}~"
|
||||
```
|
||||
|
||||
I showed that **`'`** is in the keyboard already; however the user sent a
|
||||
**`\n`** (hence the secondary prompt **`>`** on line two) before literally typing the
|
||||
closing **`'`** (also line two). But in order to make it clear what character is invalid I
|
||||
surround the character with **`'`**s so what you actually see after typing the
|
||||
closing **`'`** and hitting Enter (or however you send the **`'\n'`**) there is
|
||||
the third blank line; *but then the program prints* **`'`** followed by the
|
||||
invalid character (**`'\n'`** itself which means another line break) and then
|
||||
finally the closing **`'`**. Specifically **`isspace()` characters aren't
|
||||
I showed that `'` is in the keyboard already; however the user sent a
|
||||
`\n` (hence the secondary prompt `>` on line two) before literally typing the
|
||||
closing `'` (also line two). But in order to make it clear what character is invalid I
|
||||
surround the character with `'`s so what you actually see after typing the
|
||||
closing `'` and hitting Enter (or however you send the `'\n'`) there is
|
||||
the third blank line; *but then the program prints* `'` followed by the
|
||||
invalid character (`'\n'` itself which means another line break) and then
|
||||
finally the closing `'`. Specifically `isspace()` characters aren't
|
||||
distinctly seen like a letter, digit or symbol is: `isprint('\n') == 0 &&
|
||||
isspace('\n') == 1`**. You can add these characters but the output will be
|
||||
isspace('\n') == 1`. You can add these characters but the output will be
|
||||
rather confusing and hard to read.
|
||||
|
||||
## **4. <a name="obfuscation">Obfuscation</a>**
|
||||
@@ -780,10 +780,10 @@ Skip to [Beauty](#beauty).
|
||||
|
||||
The following might be some of the techniques used in this entry:
|
||||
|
||||
1. Helpful and descriptive names for all variables and constants (like **`S`**)
|
||||
1. Helpful and descriptive names for all variables and constants (like `S`)
|
||||
as well as some C keywords.
|
||||
|
||||
2. The way **`main()`** is declared is:
|
||||
2. The way `main()` is declared is:
|
||||
|
||||
```c
|
||||
/* Special C main() handler (encapsulation): */
|
||||
@@ -798,13 +798,13 @@ encapsulation and executing code is it actually nothing? And if it's nothing why
|
||||
is it there? If it is something what is it doing? Could it be both? Or maybe it
|
||||
really isn't nothing or nothing? :)
|
||||
|
||||
3. A special C parser called **`H()`**. It might help to observe that there
|
||||
3. A special C parser called `H()`. It might help to observe that there
|
||||
might be recursive calls and much of the program might use it. Or so it seems.
|
||||
Then again it might not help to not notice it.
|
||||
|
||||
4. Digraphs. In their simplest form it's probably not a big deal but consider:
|
||||
some source code formatters don't like them at all (neither, incidentally, does
|
||||
**`splint`**, which completely baulks). There also is a trick; if you try
|
||||
`splint`, which completely baulks). There also is a trick; if you try
|
||||
translating them then depending upon how you do it there can be functional
|
||||
changes in the program!
|
||||
|
||||
@@ -854,31 +854,31 @@ be made clear in the comments! :)*
|
||||
|
||||
Skip to [Compilation](#compiling).
|
||||
|
||||
These two **`#define`**d constants can be redefined at compilation to modify the
|
||||
These two `#define`d constants can be redefined at compilation to modify the
|
||||
behaviour of the program in a number of ways (see the
|
||||
**[Compilation](#compiling)** subsection for example invocations). Both are
|
||||
capped to be no greater than **`SIZE_MAX - 1`**. This is handled by the C
|
||||
capped to be no greater than `SIZE_MAX - 1`. This is handled by the C
|
||||
preprocessor.
|
||||
|
||||
**`S`**
|
||||
`S`
|
||||
|
||||
This determines the maximum size of the target string but it **must be at least
|
||||
38**; this is because **`38 >= 29`** and because **`strlen("METHINKS IT IS LIKE
|
||||
A WEASEL") == 28`** (which is the default target string - it would hardly be an
|
||||
38**; this is because `38 >= 29` and because `strlen("METHINKS IT IS LIKE
|
||||
A WEASEL") == 28` (which is the default target string - it would hardly be an
|
||||
implementation of the Weasel program otherwise).
|
||||
|
||||
There is obviously a reason **`38`** is the chosen size but the only hints I
|
||||
There is obviously a reason `38` is the chosen size but the only hints I
|
||||
provide are those in **[How it works](#how)** and specifically an Easter egg I
|
||||
referenced there (it's *not the only Easter egg* but it's the only Easter egg I
|
||||
won't spoil; yes this ironically and amusingly means I've left a rotten egg
|
||||
somewhere!).
|
||||
|
||||
**`N`**
|
||||
`N`
|
||||
|
||||
This is the number of offspring per generation. Anything less than 4 will be set
|
||||
to 3 (that's not a typo!) and this is part of an Easter egg.
|
||||
|
||||
Be aware that depending on the size of **`S`** and **`N`** (individually and
|
||||
Be aware that depending on the size of `S` and `N` (individually and
|
||||
together) the program will use varying amounts of memory and the larger the
|
||||
values the more memory it'll require.
|
||||
|
||||
@@ -892,23 +892,23 @@ The following options **must always be passed to the compiler:**
|
||||
-DQ='typedef' -D'g(o)'='goto o;' -D'w(x)'="x:" -D'H(main)'='r(main)'
|
||||
```
|
||||
|
||||
If you want to increase the number of offspring to **`50`** and the size of the
|
||||
chromosome to **`75`** you would pass to the compiler:
|
||||
If you want to increase the number of offspring to `50` and the size of the
|
||||
chromosome to `75` you would pass to the compiler:
|
||||
|
||||
```sh
|
||||
-DQ='typedef' -D'g(o)'='goto o;' -D'w(x)'="x:" -D'H(main)'='r(main)' -DN=50 -DS=75
|
||||
```
|
||||
|
||||
If you wanted to change **`N`** to **`3`**:
|
||||
If you wanted to change `N` to `3`:
|
||||
|
||||
```sh
|
||||
-DQ='typedef' -D'g(o)'='goto o;' -D'w(x)'="x:" -D'H(main)'='r(main)' -DN=3
|
||||
```
|
||||
|
||||
Remember that it cannot be less than **`3`**; *more correctly if it's less than
|
||||
4 it's redefined to 3* so you could have passed in **`-DN=2`** and have the same
|
||||
result. Remember too that **`S`** cannot be less than **`38`**. Both **`S`** and
|
||||
**`N`** are capped at **`SIZE_MAX - 1`**.
|
||||
Remember that it cannot be less than `3`; *more correctly if it's less than
|
||||
4 it's redefined to 3* so you could have passed in `-DN=2` and have the same
|
||||
result. Remember too that `S` cannot be less than `38`. Both `S` and
|
||||
`N` are capped at `SIZE_MAX - 1`.
|
||||
|
||||
### <a name="portability">Portability</a>
|
||||
|
||||
@@ -917,7 +917,7 @@ Skip to [An aside on bugs](#bugs).
|
||||
This entry requires at least C99 even if you translate digraphs. The program
|
||||
doesn't require third-party libraries and should work on any Unix based system.
|
||||
It works on both 64-bit and 32-bit (but inevitably some data type sizes will be
|
||||
smaller and this I believe includes **`SIZE_MAX`**). I don't think Windows gcc
|
||||
smaller and this I believe includes `SIZE_MAX`). I don't think Windows gcc
|
||||
ports would have many issues (if any) either but I have no way to test this.
|
||||
Originally I tested it on the below systems.
|
||||
|
||||
@@ -982,12 +982,12 @@ Skip to [Installing](#rpm).
|
||||
|
||||
Any undocumented bugs are the result of insolent monkeys tampering with any
|
||||
number of things. That includes but is not limited to running the program on a
|
||||
non-ASCII system; non little-endian; meddling with **`S`** or **`N`** too much,
|
||||
changing the references to **`SIZE_MAX`** to be larger than **`SIZE_MAX`** or a
|
||||
signed value (**`size_t`** is unsigned) or too small of a value; changing data
|
||||
non-ASCII system; non little-endian; meddling with `S` or `N` too much,
|
||||
changing the references to `SIZE_MAX` to be larger than `SIZE_MAX` or a
|
||||
signed value (`size_t` is unsigned) or too small of a value; changing data
|
||||
types or variables; expecting really long strings - including but not limited to
|
||||
the complete works of Shakespeare (hint: **`isprint('\n') == 0`** so it won't
|
||||
ever find any string with **`'\n'`**) - to be found by the program in a quick
|
||||
the complete works of Shakespeare (hint: `isprint('\n') == 0` so it won't
|
||||
ever find any string with `'\n'`) - to be found by the program in a quick
|
||||
and easy fashion if ever; or any other meddling including being petulant and/or
|
||||
unreasonable monkeys. I will say though that there is at least one place I see
|
||||
after having won that could be slightly more efficient (can you find it?); I am
|
||||
@@ -1142,7 +1142,7 @@ for(;P("\n"),R=;P("|"))for(e=C;e=P("_"+(*u++/
|
||||
8)%2))P("|"+(*u/4)%2);
|
||||
```
|
||||
\
|
||||
How is **`R=;`** valid? Since I don't have the context maybe there is something
|
||||
How is `R=;` valid? Since I don't have the context maybe there is something
|
||||
I'm missing but either way it's a funny piece. It could also be for irony itself
|
||||
(actually I had previously thought of somehow implementing something like that
|
||||
for the contest but decided for the message by itself in the end). I would
|
||||
@@ -1174,7 +1174,7 @@ so happy to have had you in my life.
|
||||
But I want to also dedicate it to (and thank) my dear friend [Martijn
|
||||
Schoemaker](https://www.ficture.nl) whom provided me with the spark a very long
|
||||
time ago (and whom has stood by me and helped me in more ways than he can know -
|
||||
**`#including C`**); if it wasn't for you Martijn I wouldn't have been able to
|
||||
`#including C`); if it wasn't for you Martijn I wouldn't have been able to
|
||||
win so consider this a recursive thank you thank you! :)
|
||||
|
||||
I would also like to give thanks and much love to my dear friend Vicky Wilmore
|
||||
|
||||
@@ -1,9 +1,17 @@
|
||||
YOU ARE LIKE A WEASEL
|
||||
YOU SMELL LIKE A WEASEL
|
||||
I SMELL LIKE A WEASEL
|
||||
YOU ARE A WEASEL
|
||||
I AM THE WEASEL
|
||||
I AM THE WALRUS
|
||||
YOU ARE THE WALRUS
|
||||
YOU ARE THE WEASEL
|
||||
PAULINE HANSEN ACTS LIKE A WEASEL
|
||||
METHINKS IT IS LIKE A WEASEL
|
||||
MONKEY SEE, MONKEY DO!
|
||||
STOP MONKEYING ABOUT!
|
||||
WHAT DO YOU MEAN I'M A MONKEY?!
|
||||
PROBLEM BETWEEN KEYBOARD AND CHAIR
|
||||
MY PRECIOUS. YES, MY PRECIOUS.
|
||||
MY PRECIOUS! O MY PRECIOUS!
|
||||
IOCCC BEST USE OF WEASEL WORDS
|
||||
@@ -8,4 +8,4 @@ while read -r f; do
|
||||
# NOTE: ./weasel $* $f would just be the final word
|
||||
sleep 2
|
||||
done < test-strings.txt || exit 1
|
||||
echo "All done. Goodbye."
|
||||
echo "All done. Goodbye, you old monkeying weasel!"
|
||||
Reference in new issue
Block a user