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
\ \ \ &
\ \ \
\ \ \
\ \ \
\ \ \
\ \ \
\ \ \
\ \ \
\ \ \
\ \ \
\ \ \
\ \ \
\ \ \
\ \ \
\ \ \
\ \ \
\ \ \
\ \ \
\ \ \
\ \ \
\ \ &
\ \
\ \
\ \
\ \
\ \
\ \
\ \
\ \
\ \
\ \
\ \
\ \
\ \
\ \
\ \
\ \
\ \
\ \
\ \
\ @
\
\
\
\
\
\
\
\
\
\
\
\
\
\
\
\
\
\
\
\
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@ @@@@@@@@@@@@
@ @@@@@@@@ @@@@@@@
@ @ @@@ @@@ @@@@@@@
@ @ @@ @@@@ @@@@@@@
@ @@ @@ @@@ @@@@@@@
@ @ @@@ @@@@ @@@@@@@
@ @@ @@ @@@ @@@@@@@
@ @ @@ @@@@ @@@@@@@
@ @ @@@ @@@ @@@@@@@
@ @@ @@ @@@@
@ @ @@ @@@
@ @@ @@@ @@@@
@ @ @@ @@@
@ @ @@ @@@@
@ @@ @@@ @@@
@ @ @@ @@@@
@ @@ @@ @@@
@ @ @@@ @@@@
@ @ @@ @@@
@ @@ @@
@ @ @@@
@ @@ @@
@ @ @@
@ @ @@@
@ @@ @@
@ @ @@
@ @@ @@@
@ @ @@
@ @ @@
@ @@
@ @
@ @@
@ @
@ @
@ @@
@ @
@ @@
@ @
@ @
@ @@
@ @
@ @@
@ @
@ @
@ @@
@ @
@ @@
@ @
@ @
@
@
@
@
@
@
@
@
@
@
@
@
@
@
@
@
@
@
@
@
@
@
@
@
@
@
@
@
@
@
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@ @
@ @
@ @
@ @
@ @
@ @
@ @
@ @
@ @
@ @
@ @
@ @
@ @
@ @
@ @
@ @
@ @
@ @
@ @
@ @
@ @
@ @
@ @
@ @
@ @
@ @
@ @
@ @
@ @
@ @
@ @
@ @
@ @
@ @
@ @
@ @
@ @
@ @
@ @
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~|
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
|~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|~~~~~~~~~~~~~~~~~~~