ASCII rotation, merging and more
I spent some more time working on the ASCII generator.
Rotation
The primitive shapes are finally being rotated. In the previous post the shapes weren’t rotated yet, which resulted in poor images.
The WOW image from before:
WOW
'|||||||||||||||||||||||||||||||||||||||||||||||| '
| |
| |
| |
|||| |
| |'||| ' |
| | |||| |
| | |||| |
| | | ||| |
| | ||| |
| '||| ' |||| |
| ||| |
| ||| |
| |||| |
| ||| |
| ||| |
| |||| |
| ||| |
| ||||
||||
'|||||||||||||||||||||||||||||||||||||||||||||||| ' |||
|||
||||
|||
|||
Now renders like this:
WOW
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~|
| |
| |
| |
{~~~ |
| ~+~~~~| |
| | ~~~| |
| | {~~~ |
| | | ~~~ |
| | | ~~~ |
| |~~~~+ ~~~~ |
| ~~~ |
| ~~~ |
| ~~~~ |
| ~~~ |
| ~~~ |
| ~~~~ |
| ~~~ |
| ~~~|
| {~~~
|~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+ ~~~
~~~
~~~~
~~~
Merging
As you might have noted above, overlapping shapes are now being merged. Previously simply one of the overlapping shapes ‘won’ and was converted to a character.
Performance
The performance wasn’t that great. Since I plan on maybe running this on a weak web server I had to speed the algorithm up.
The biggest change here was the addition of a cache, so I won’t try to find the most similar character of the same shape multiple times.
This resulted in a huge speedup which should be more than enough (for now).
Similarity Rating
Since for every shape the most similar character is chosen, the result heavily depends on the similarity rating. The same rendering with different ways of calculating the rating:
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~|
| |
| |
| |
{~~~ |
| ~+~~~~| |
| | ~~~| |
| | {~~~ |
| | | ~~~ |
| | | ~~~ |
| |~~~~+ ~~~~ |
| ~~~ |
| ~~~ |
| ~~~~ |
| ~~~ |
| ~~~ |
| ~~~~ |
| ~~~ |
| ~~~|
| {~~~
|~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+ ~~~
~~~
~~~~
~~~
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~|
| |
| |
| |
|~~~ |
| ~~~~~~| |
| | ~~~| |
| | |~~~ |
| | | ~~~ |
| | | ~~~ |
| |~~~~+ ~~~~ |
| ~~~ |
| ~~~ |
| ~~~~ |
| ~~~ |
| ~~~ |
| ~~~~ |
| ~~~ |
| ~~~|
| |~~~
|~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+ ~~~
~~~
~~~~
~~~
~~~
.~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~|
| |
| |
| |
|~~~ |
| ~~~~~~| |
| | ~~~| |
| | |~~~ |
| | | ~~~ |
| | | ~~~ |
| '~~~~- ~~~~ |
| ~~~ |
| ~~~ |
| ~~~~ |
| ~~~ |
| ~~~ |
| ~~~~ |
| ~~~ |
| ~~~|
| |~~~
'~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~- ~~~
~~~
~~~~
~~~
~~~
' '
' '
' '
| '
' '
' ' ' '
' ' | '
' ' ' '
' ' ' '
' ' '
' '
' '
' '
' '
' '
' '
' '
' '
' |
'
There seem to be clear wrong settings, but no right one. I’ll basically have to fine tune the algorithm until im satisfied with it.
I also might have made it too dumb to improve performance. This might not be necessary anymore thanks to the caching.
BMP Debugging
Since I was only able to see the chosen characters, this made it rather hard to actually debug the generated shapes.
Therefore I added the ability to also render a BMP image. This way I was able to spot quite some bugs which would have been impossible to catch before.
Some shapes still don’t render perfectly, so there’s still room for improvement.
Generic Cache
For my work on the Haskell version of webgamers I wrote a generic Cache to avoid duplicate tile calculation.
It’s basically a map from key to value paired with a function which can calculate value from key.
data Cache a b = Cache
{ cacheF :: (a -> b)
, cacheM :: M.Map a b
, cacheS :: Int
}
On each request the Cache first checks whether it already holds the result. If so, it returns it. Otherwise it calls the function to calculate the result, stores it and returns it to the caller. It also has a max size which will cause it to clear once it is reached to prevent it from using too much memory.
For the generator I also defined a cachedMap which works just as map but will never do a calculation twice. (This is basically a foreach in imperative languages)
let normal = map f xs -- possibly many duplicate calculations
let withCache = cachedMap f xs -- no duplicate calculations, basically the same syntax
I might release the Cache on its own, since it’s generic and quite handy.
More Shapes
I added way more shapes than just Line and Box. The following code now produces the below image.
[ draw $ Line (0, 0) (80, 0)
, draw $ Line (0, 0) (80, 5)
, draw $ Line (0, 0) (80, 10)
, draw $ Line (0, 0) (80, 30)
, draw $ Line (0, 0) (80, 50)
, draw $ Line (0, 0) (80, 80)
, draw $ Line (0, 0) (50, 80)
, draw $ Line (0, 0) (30, 80)
, draw $ Line (0, 0) (10, 80)
, draw $ Line (0, 0) (5, 80)
, draw $ Box (30, 30) (60, 60)
, draw $ DArrow (0, 100) (40, 100)
, draw $ DArrow (0, 100) (40, 110)
, draw $ DArrow (0, 100) (40, 120)
, draw $ DArrow (0, 100) (40, 130)
, draw $ DArrow (0, 100) (40, 140)
, draw $ DArrow (0, 100) (40, 160)
, draw $ DArrow (0, 100) (40, 180)
, draw $ DArrow (0, 100) (40, 200)
, draw $ LineFilled (0, 220) (70, 220)
, draw $ LineFilled (0, 220) (70, 230)
, draw $ LineFilled (0, 220) (70, 240)
, draw $ LineFilled (0, 220) (70, 250)
, draw $ LineFilled (0, 220) (70, 270)
, draw $ LineFilled (0, 220) (70, 300)
, draw $ BoxFilled (30, 320) (60, 340)
, draw $ BoxThick (20, 370) (70, 410)
, draw $ Box (30, 440) (60, 500)
, draw $ CorneredLine (20, 510) (50, 520)
, draw $ CorneredLine (20, 540) (40, 590)
]
%w=~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
$x<<~~ ~~~~~~~~~~~~~~~~~~~~~~~~
j\x < ~~ ~~~~~~~~ ~~~~~~~~~~~~~~~~
|\ x << ~~~ ~~~~~~~~ ~~~~~~~~~~~~~~~~
|\\ x < ~~~ ~~~~~~~~ ~~~~~~~~~~~~~~~~
|\ \ x << ~~ ~~~~~~~~
| \\ x << ~~~ ~~~~~~~~
| \ \ x < ~~~ ~~~~~~~~
|| \ \ x << ~~ ~~~~~~~~
|| \ \ x < ~~~ ~~~~~~~~
|| \ \ x << ~~~
|| \ \ x << ~~
|| \ \ x < ~~~
|| \ \ x << ~~~
|| \ \ x < ~~
|| \ \ x << ~~~
|| \ \ x << ~~~
|| \ \ x < ~~
|| \ \ x << ~~~
|| \ \ x < ~~~
|| \ \ x << ~~
|| \ \ x << ~~~
|| \ \ x < ~~~
|| \ \ x << ~~
| | \ \ x < ~~~
| | \ \ x << ~~~
| | \ \ x << ~~
| | \ \ x < ~~~
| | \ \ x << ~~~
| | \ \ x < ~~
| | \ \ %~~~~~~~~~~~~~~~~~==~~~~~~~~~~|
| | \ \ |x << |
| | \ \ | x < |
| | \ \ | x << |
| | \ \ | x < |
| | \ \ | x << |
| | \ \ | x <<|
| | \ \ | x $
| | \ \ | x |<<
| | \ \ | x | <
| | \ \ | x | <<
| | \ \ | x | <<
| | \ \ | x | <
| | \ \ | x | <<
| | \ \ | x | <
| | \ \ | x | <<
| | \ \ | x | <<
| | \ \| x | <
| | \ $ x | <<
| | \ $ x | <
| | \ |\ x |
| | \ |\ x |
| | \ | \ x |
| | \ | \ x |
| | \ | \ x |
| | \ | \ x |
| | \ | \ x |
| | \ | \ x |
| | \ | \ x |
| | \ | \ x|
| | \ |~~~~~~%~~~~~~~~~~~~~~~~~~~~~~=
| | \ \ x
| | \ \ x
| | \ \ x
| | \ \ x
| | \ \ x
| | \ \ x
| | \ \ x
| | \ \ x
| | \ \ x
| | \ \ x
| | \ \ x
| | \ \ x
| | \ \ x
| | \ \ x
| | \ \ x
| | \ \ x
| | \ \ x
| | \ \ x
| | \ \ x
%w~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~e
\x<<~~~~
\\x<<< ~~~~
\\x<<<< ~~~~
\\ x < << ~~~~
\\ x < << ~~~~
\\\ x << << ~~~~
\\\ x < << ~~~~
\\\ x < << ~~~~
\\ \ x << << ~~~~
\\\ x < << w
\\ \ x < <<
\ \ \ x << <<
\\ \ x < <<
\ \ \ x < <<
\\ \ x << <<
\ \ \ x < <<
\ \ \ x < <<
\ \ \ x << <<
\ \ \ x < <<
\ \ \ x < w
\ \ \ x <<
\ \ \ x <
\ \ \ x <
\ \ \ x <<
\ \ \ x <
\ \ \ x <
\ \ \ x <<
\ \ \ x <
\ \ \ x <
\ \ \ x w
\ \ \ x
\ \ \ x
\ \ \ x
\ \ \ x
\ \ \ x
\ \ \ x
\ \ \ x
\ \ \ x
\ \ \ x
\ \ \ &
\ \ \
\ \ \
\ \ \
\ \ \
\ \ \
\ \ \
\ \ \
\ \ \
\ \ \
\ \ \
\ \ \
\ \ \
\ \ \
\ \ \
\ \ \
\ \ \
\ \ \
\ \ \
\ \ \
\ \ &
\ \
\ \
\ \
\ \
\ \
\ \
\ \
\ \
\ \
\ \
\ \
\ \
\ \
\ \
\ \
\ \
\ \
\ \
\ \
\ @
\
\
\
\
\
\
\
\
\
\
\
\
\
\
\
\
\
\
\
\
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@ @@@@@@@@@@@@
@ @@@@@@@@ @@@@@@@
@ @ @@@ @@@ @@@@@@@
@ @ @@ @@@@ @@@@@@@
@ @@ @@ @@@ @@@@@@@
@ @ @@@ @@@@ @@@@@@@
@ @@ @@ @@@ @@@@@@@
@ @ @@ @@@@ @@@@@@@
@ @ @@@ @@@ @@@@@@@
@ @@ @@ @@@@
@ @ @@ @@@
@ @@ @@@ @@@@
@ @ @@ @@@
@ @ @@ @@@@
@ @@ @@@ @@@
@ @ @@ @@@@
@ @@ @@ @@@
@ @ @@@ @@@@
@ @ @@ @@@
@ @@ @@
@ @ @@@
@ @@ @@
@ @ @@
@ @ @@@
@ @@ @@
@ @ @@
@ @@ @@@
@ @ @@
@ @ @@
@ @@
@ @
@ @@
@ @
@ @
@ @@
@ @
@ @@
@ @
@ @
@ @@
@ @
@ @@
@ @
@ @
@ @@
@ @
@ @@
@ @
@ @
@
@
@
@
@
@
@
@
@
@
@
@
@
@
@
@
@
@
@
@
@
@
@
@
@
@
@
@
@
@
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@ @
@ @
@ @
@ @
@ @
@ @
@ @
@ @
@ @
@ @
@ @
@ @
@ @
@ @
@ @
@ @
@ @
@ @
@ @
@ @
@ @
@ @
@ @
@ @
@ @
@ @
@ @
@ @
@ @
@ @
@ @
@ @
@ @
@ @
@ @
@ @
@ @
@ @
@ @
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~|
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
|~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|~~~~~~~~~~~~~~~~~~~