Implement graphical display w/stepped timing

master
sigonasr2 4 years ago
parent 7dc2eec7ba
commit e3643f43fd
  1. 1
      base64/delete.png.64
  2. 1
      base64/pause.png.64
  3. 1
      base64/play.png.64
  4. 1
      base64/reset.png.64
  5. 1
      base64/rotation_clockwise.png.64
  6. 1
      base64/rotation_counterclockwise.png.64
  7. 1
      convertAll.sh
  8. 5
      convertto64.sh
  9. BIN
      delete.png
  10. BIN
      delete_cursor.png
  11. 191
      dot.svg
  12. 539
      game.js
  13. 12
      game.test.js
  14. 14
      image_data.js
  15. BIN
      pause.png
  16. BIN
      play.png
  17. BIN
      reset.png
  18. BIN
      rotation_clockwise.png
  19. BIN
      rotation_counterclockwise.png

@ -0,0 +1 @@
iVBORw0KGgoAAAANSUhEUgAAABUAAAAgCAYAAAD9oDOIAAAACXBIWXMAAADGAAAAxgGwdJvFAAAAGXRFWHRTb2Z0d2FyZQB3d3cuaW5rc2NhcGUub3Jnm+48GgAAA0BJREFUSIntlV9oW1Ucxz/n3DviTYO9NrFlTToQ2j5YyqIIa1YK4theSsEw5gJ9EP9QweoQFCllreCGdb5UfEspWEFwIAPtQx+a0ILifKjo8uBmpY6aVEi70lwTcps/N/f4sC5aUBJkj/2+HDi/3/nw/Z0fv3MEgILLwBWrre2VL65e/U7TtLvA++VyeebNS5ds4HugDQgLKNBA+sH6ITDiKxQ+8dn2I7bPlxVCBD0ezxPAL8DTwLPNAAEkgAAHeFGAd+D6dU0IEdzc3MSfyVx0pZz+9fTpn+fi8aFmgAB6PB4/AbwcV+qlcCIhTt24wWe2zcfr69z1+9kLBsU3o6P9SqnfmoVKKeXjwHuFQuHElWKRtWPHGL99m49qNR67d49Pz5zB1XWUUs/Nzc29oJQSDaGapqWVUramaSRWVhitVmkF3gAmlOLdhQWWlpaQUj6qlLoohFANodVq9XMhhLelpYWBgQEcoHYQNAHDMIhEIriumwdea6Z83XGcVzVN+1oI8VRnRwcfABngW2ASKEYimKaJlPKHsbGx3Wagcnx8PGPb9iCgnl9f5xTwumHwthD8DryTSkGpRK1We7KZ+wSoJ305OVmLXrsmfzp7lh+jUSzLorK8zOWVFW6dO8fa+fNF4A+lVEkI4bquW5FS2kAe+FMptV8vH0CBJ7ewgHX8OLdGRgBobW2FCxe4U61ycnmZdH9/S7anpxdAKYUQAqX+7pnrukgpFSDEAXTWlfKtryYmyAaDpNNpVldXsSyLno4O4jdvUq7VOAkUhcAwDHRdx+/3EwgECAaDDA0N4fP5Dpcfj8czQAggm82SzWbZ3d0ln8+zv7+P4ziUy+U60DAMTNMkEAgQCoUwTfOB2/rsA2xvbW2FUqkUfX199Pb2Eg6HGzbFcRw2NjZIJBJ0dnYyODh4f/YfqFwus7i4SDKZxOv1AjA7O8v09DTJZBKAvb09pqammJmZud8UXWd+fp5kMkmpVAI4DP035XI5tre3yeVydWc7OztYlvWfZxpC/4+OoEfQI+gR9KHpn480gUCAWCxGe3t7fW94eBjbtunq6gLA5/MRi8XweDz1nGg0SqVSobu7Gzj8nawBzzwMp38BxWJHOyltKE0AAAAASUVORK5CYII=

@ -0,0 +1 @@
iVBORw0KGgoAAAANSUhEUgAAABIAAAAbCAYAAABxwd+fAAAACXBIWXMAAADGAAAAxgGwdJvFAAAAGXRFWHRTb2Z0d2FyZQB3d3cuaW5rc2NhcGUub3Jnm+48GgAAALxJREFUOI3t1TGKwzAQQNE/JoXQGQTGpbFP5HJhXfsoKo0XUupCSWpj0BmMKk8KJ2QXglnYcvXLQfNQNzKO40VEWl5tIvLZ9/2ZN03T9KGqX0DxnKnq9SQi7bquLMuCMYaqqgqgeYc8aoBinmdSSpRlibW2LQBijHjvCSEc7P8shID3nhgjfP/eX8tQhjKUoQz9Q+gE4JxjGAaMMb9e7LqOlBLOuR1S1au1tq3r+vlmA24Hxg3YHocU2C/tHUseO6D31KjVAAAAAElFTkSuQmCC

@ -0,0 +1 @@
iVBORw0KGgoAAAANSUhEUgAAABkAAAAgCAYAAADnnNMGAAAACXBIWXMAAACbAAAAmwEPcaP1AAAAGXRFWHRTb2Z0d2FyZQB3d3cuaW5rc2NhcGUub3Jnm+48GgAAAj9JREFUSIm11rtrFVkcB/DPmdwbbx7GRK+IQbbQVQwIK0RIYSciguBa6RaKCxa+UCu1EDvZXaxstBAr8Q/QwifIrgirLrusq2ChyD6qKCJ41U2MuXMsJiM+gibm5FtNcc7vM2f48ZsDD3ASVdOYiCi4jgXTh8yrRi2hKXiKddODrOyMdtSj2ZUmchxDLRWQvX2aV2V7PbO8PWCf4HcsS4tAa+DbWWzsYUbWJ/gDBz9aNyWkTF+NnfXMV61V/IQr6E2LQFcLW+cEa7vIrBLcxfq0CAQMdLCtHvRUunEWx9GWDinTWy0+30BHwC7BbfSnRaASWNvFph5q2deCmziElnRImaU1ds/NLKlVcERwA4vTItCR8V0PG7qphH7BHexLi5T5po1dczMLWlsVU+IS5qdFoLuF7+dkVs8ks2bsVO+1+tSRssrKzrLVZ+McTqMzHVKmt8qOemZFO2wR/IWBtAhUA+tm0d9OtBAXKsmRR6+52Ij+HQmCh6Ld6ZDhnF9e8NvLiGEcFf2IV1NHIu4McbmRG8oDzuAABsslU0P+GeHis9zj0Wxsnu3Brx8u+zKk0eTq8+IEwRMcFp1S/Lo/yuSQ0citl1x7kRuNOU6IDqPxqW0TR+4Pc6GRe9bM8DP24t5Etn4eGRxryf9GguBvxSA8P+GX+yQylHNt/JacDDA+kuPP/7n6vGkozxQtuR+PJlt8fGT8lrzxpcXfTbSsLeqrFXfizCA2K64RyVJeuEfwg7HxnDbBA8VVZ1H64kXeAM9RoeriawdYAAAAAElFTkSuQmCC

@ -0,0 +1 @@
iVBORw0KGgoAAAANSUhEUgAAAB4AAAAgCAYAAAAFQMh/AAAACXBIWXMAAACIAAAAiAHr3JJSAAAAGXRFWHRTb2Z0d2FyZQB3d3cuaW5rc2NhcGUub3Jnm+48GgAAAltJREFUSImt18tvTVEUx/HP1WiiRNVE1YCItJWiBiIxMRADA21MxCPxiAQTI/+AgUc8ykRUhH9AJQy8JiVmJhJpQkSISBRtJQZarRZlsM9N9729r3N7f8ka3HPWWt+799l7rb1Jpzrsw0MMYQrv0IO1KXNVrM14jX9FbApnUV9L6JEkcTFobE+xqBbQkxUCY+vH/FJJ68pAD6IXmejZXzzBLdzBABrRHPmsxlI8KjusAurEuNyR3Ed7Ad8MDmEsz78rLXQJ3kcJJnGsgritGI3ivmBxGvC9KHgc21PE7pU76guVBu6KgqawMwU0q74oxwRaygU04GMUdKAKqAQ0EeW5VC7gXOR8o0poVtejXD/QFL+Mt9MqXMNvvBK+1Z+UsGWJNeETtiXQX8IMjCTvUi24StSJb8oXmBO1BhOaxdcS0MvFAjvQOkd4u7CH86EPFKmWzcKqHkr+wFzUhs8R9AUWFnJcgOeR4zDWzRHeisHEVhRymIe7Zk/NMNbXAF509q4UgGZtBBvmCC+ooyWgWfuOTbWEZrDSzErrFho/MyVzMPn9U5j6NGrAM6wROtwWYfHOUpNQabIj7U0JytfNKNeZcs49kfMEllcJPRzl+SDsmpJqEWprNuh2FdBuoeZnc1TcWi/KXVx7UkB3yG2JfSliNcoteaPCsaaUMkLxj0f6VhWdqEvuqMeE75Yp4Nsh3C7y/auufFfN3tMDwoHhOE4JB/i/eT7T2F8tlHAo7y8AL2XTatRvG/C4QuikcAmomepxWun700tsrCU0VhvO441QvweFM/huocNVrP+6PgXaCh5PhAAAAABJRU5ErkJggg==

@ -0,0 +1 @@
iVBORw0KGgoAAAANSUhEUgAAACAAAAAYCAYAAACbU/80AAAACXBIWXMAAADbAAAA2wHwUOacAAAAGXRFWHRTb2Z0d2FyZQB3d3cuaW5rc2NhcGUub3Jnm+48GgAAAXRJREFUSInF1r9OFFEUgPHfriawu1ESCdgZGkIhWkJhYYQHoLDRxNLwACQklDwAFQ3lJhI6okJB3AcwsbIhtFpBhf8SIya6QHF3ks3A7t47MnKSU8095/vmzp0zw9XHMm7FLq6WIPAIb2MlyhCAObyJkShLAOaxg5HrEoAneI3bvRZUCjSt4SEmMYV7wlYPda5NYyxX8w5P8asAD4ziJbbxHWcFcg/1VPA4VvGlIDSfLTRi4S9wfEXgJIkhvCoB3J27wnm5EDXh/S0TnuXOZRIb/wme5VY3/BlO/6HZET7jR8TaNjYxkcEb+JQI/IYmFnC360bWB9R9wOP81i8lgP92IOP5JgMEDrGIG/mCCvYj4T+FidYv8gInWMOdXgWzkfA2ng+A5wV2cX9QwUqkQDMCngkcCGcjKjYj4CfCRycmZjAcC4f3EQLbKQ1ToqrrXewTrbIEiBscD65T4I/EZ5oSN/FRGCr1DrAi/OFkA+MrfpclcA5HFShV5l7kTwAAAABJRU5ErkJggg==

@ -0,0 +1 @@
iVBORw0KGgoAAAANSUhEUgAAACAAAAAYCAYAAACbU/80AAAACXBIWXMAAADbAAAA2wHwUOacAAAAGXRFWHRTb2Z0d2FyZQB3d3cuaW5rc2NhcGUub3Jnm+48GgAAAXRJREFUSInF1r1LHFEUxuEnLgRdVoJpFKuktg02KdJaCEkhWKRTsLXSvyGFlaZWRNJEAhqCWlslnUhsNCSk0CKLSAh+gR8pZhfGDZs5szrrCweGO+fe98c9nMshrm5M5cgPqSOYV8Z7PL9rgKj5Gq6x0m7zCjZq5m0HqGA9ZV4IwIMm62V8wFDDehVfcYpz/MFP7GIP27V/t1K65nnjCMsYw+NWzDvxqUXzxjjEG/Tfh3k6qhjPMu/CxwLM0zGPh83MVws2r8dy7aZv6F2bzOsx1wjwBEu4DGz+jR84uAXAFUYaIeAFPmdsnk3l9+EVFiTtlwfim6Td/1EJE9gPAKTVi7fBW6zHZJOzkDwiM5JXLQJQ1yiOgwBbGWeBATfbMwsAXkvqHIF4FoGAl9gJAsBiEGA6CkDSv4PB3Kc4CwAs5gHIq5UAwGapQIBHGM7IKUVnwlb0JZBTKdBfGRf+X4KjZhPRXek7emrfl5IJ6loyiZ3g119x6S+ogBYJVgAAAABJRU5ErkJggg==

@ -0,0 +1 @@
find *.png -type f -exec ./convertto64.sh {} +

@ -0,0 +1,5 @@
rm *.64
for i in "$@"; do
echo "Converting $i to base 64."
base64 $i > $i.64
done

Binary file not shown.

After

Width:  |  Height:  |  Size: 947 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.7 KiB

@ -26,11 +26,11 @@
borderopacity="1.0" borderopacity="1.0"
inkscape:pageopacity="0.0" inkscape:pageopacity="0.0"
inkscape:pageshadow="2" inkscape:pageshadow="2"
inkscape:zoom="1.4" inkscape:zoom="0.49497475"
inkscape:cx="566.11657" inkscape:cx="343.44105"
inkscape:cy="502.60366" inkscape:cy="757.79528"
inkscape:document-units="mm" inkscape:document-units="mm"
inkscape:current-layer="layer2" inkscape:current-layer="layer8"
inkscape:document-rotation="0" inkscape:document-rotation="0"
showgrid="false" showgrid="false"
inkscape:window-width="1274" inkscape:window-width="1274"
@ -54,7 +54,7 @@
inkscape:groupmode="layer" inkscape:groupmode="layer"
id="layer2" id="layer2"
inkscape:label="Writer" inkscape:label="Writer"
style="display:inline"> style="display:none">
<rect <rect
style="fill:#206476;fill-opacity:1;fill-rule:evenodd;stroke:#bcbcbc;stroke-width:0.964999;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" style="fill:#206476;fill-opacity:1;fill-rule:evenodd;stroke:#bcbcbc;stroke-width:0.964999;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
id="rect1010" id="rect1010"
@ -81,11 +81,11 @@
inkscape:export-xdpi="4.0677924" inkscape:export-xdpi="4.0677924"
id="path855" id="path855"
d="M 205.79753,128.82391 128.28937,52.919367 v 30.991347 l 45.65739,45.657396 z" d="M 205.79753,128.82391 128.28937,52.919367 v 30.991347 l 45.65739,45.657396 z"
style="fill:#206476;stroke:#999999;stroke-width:0.264583px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;fill-opacity:1" /> style="fill:#206476;fill-opacity:1;stroke:#999999;stroke-width:0.264583px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" />
<path <path
inkscape:export-ydpi="4.0677924" inkscape:export-ydpi="4.0677924"
inkscape:export-xdpi="4.0677924" inkscape:export-xdpi="4.0677924"
style="display:inline;fill:#206476;stroke:#878787;stroke-width:0.26766px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;fill-opacity:1" style="display:inline;fill:#206476;fill-opacity:1;stroke:#878787;stroke-width:0.26766px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
d="m 205.79753,174.08732 -77.50816,77.68058 v -31.71649 l 45.65739,-46.7257 z" d="m 205.79753,174.08732 -77.50816,77.68058 v -31.71649 l 45.65739,-46.7257 z"
id="path855-9" /> id="path855-9" />
</g> </g>
@ -93,7 +93,7 @@
inkscape:label="Dot" inkscape:label="Dot"
inkscape:groupmode="layer" inkscape:groupmode="layer"
id="layer1" id="layer1"
style="display:inline"> style="display:none">
<circle <circle
style="fill:#a1a1a1;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:10;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" style="fill:#a1a1a1;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:10;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
id="path889" id="path889"
@ -101,6 +101,181 @@
cy="149.80829" cy="149.80829"
r="34.773811" /> r="34.773811" />
</g> </g>
<g
style="display:none"
inkscape:groupmode="layer"
id="layer4"
inkscape:label="RotationArrow">
<path
id="path833"
d="m 147.52602,202.47906 c 0,0 -12.47322,-85.42262 91.8482,-83.91071 V 95.222397 l 52.87237,52.872393 -52.31353,30.20324 v -25.33384 c 0,0 -50.82967,-4.9137 -52.71955,50.27084 z"
style="fill:#000000;fill-opacity:1;stroke:#000000;stroke-width:0.264583px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" />
<path
style="fill:#000000;fill-opacity:1;stroke:#000000;stroke-width:0.264583px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
d="m 114.32893,201.40998 c 0,0 12.47322,-85.42262 -91.848203,-83.91071 V 94.153323 l -52.872366,52.872387 52.313526,30.20324 v -25.33384 c 0,0 50.82967,-4.9137 52.71955,50.27084 z"
id="path833-7" />
</g>
<g
style="display:none"
inkscape:label="TrashCan"
id="layer5"
inkscape:groupmode="layer">
<g
inkscape:export-ydpi="5.0500002"
inkscape:export-xdpi="5.0500002"
id="g1508">
<rect
y="113.17126"
x="70.054749"
height="106.90781"
width="88.198944"
id="rect833"
style="fill:#000000;fill-rule:evenodd;stroke:#999999;stroke-width:7.99999" />
<ellipse
ry="8.2853546"
rx="43.030392"
cy="121.45661"
cx="113.08513"
id="path835"
style="fill:#000000;fill-rule:evenodd;stroke:#999999;stroke-width:7.99999" />
<rect
y="134.5528"
x="87.694542"
height="82.051743"
width="4.8108511"
id="rect837"
style="fill:#000000;fill-rule:evenodd;stroke:#999999;stroke-width:7.99999" />
<rect
y="134.5528"
x="112.81787"
height="82.853554"
width="3.7417734"
id="rect839"
style="fill:#000000;fill-rule:evenodd;stroke:#999999;stroke-width:7.99999" />
<rect
y="132.41466"
x="135.00124"
height="84.991714"
width="3.2072344"
id="rect841"
style="fill:#000000;fill-rule:evenodd;stroke:#999999;stroke-width:7.99999" />
<path
inkscape:transform-center-y="0.39874364"
inkscape:transform-center-x="2.0302258"
d="m 105.60406,77.501785 -2.33317,15.193188 3.85009,14.468957 -15.17057,2.47597 -12.571053,8.13281 -7.042753,-13.66295 -11.619429,-9.442609 10.81791,-10.920141 5.389851,-13.968659 13.728589,6.913934 z"
inkscape:randomized="0"
inkscape:rounded="0"
inkscape:flatsided="false"
sodipodi:arg2="-0.039341711"
sodipodi:arg1="-0.67941381"
sodipodi:r2="17.335001"
sodipodi:r1="25.2651"
sodipodi:cy="93.376785"
sodipodi:cx="85.949303"
sodipodi:sides="5"
id="path845"
style="fill:#000000;fill-rule:evenodd;stroke:#999999;stroke-width:7.99999"
sodipodi:type="star" />
<path
transform="rotate(26.564727,96.570001,105.51357)"
sodipodi:type="star"
style="fill:#000000;fill-rule:evenodd;stroke:#999999;stroke-width:7.99999"
id="path845-0"
sodipodi:sides="5"
sodipodi:cx="81.64286"
sodipodi:cy="99.407738"
sodipodi:r1="25.2651"
sodipodi:r2="17.335001"
sodipodi:arg1="-0.67941381"
sodipodi:arg2="-0.039341711"
inkscape:flatsided="false"
inkscape:rounded="0"
inkscape:randomized="0"
d="m 101.29762,83.532737 -2.333172,15.193188 3.850092,14.468955 -15.170572,2.47597 -12.571053,8.13281 -7.042754,-13.66295 -11.619428,-9.44261 10.817909,-10.920138 5.389851,-13.968659 13.72859,6.913934 z"
inkscape:transform-center-x="-0.76690555"
inkscape:transform-center-y="-1.6715653" />
<text
id="text864"
y="122.5257"
x="57.499897"
style="font-style:normal;font-weight:normal;font-size:84.1219px;line-height:1.25;font-family:sans-serif;fill:#ff0000;fill-opacity:1;stroke:none;stroke-width:0.4929"
xml:space="preserve"><tspan
style="font-size:84.1219px;fill:#ff0000;fill-opacity:1;stroke-width:0.4929"
y="122.5257"
x="57.499897"
id="tspan862"
sodipodi:role="line">X</tspan></text>
</g>
</g>
<g
style="display:none"
inkscape:label="PlayArrow"
id="layer6"
inkscape:groupmode="layer">
<path
inkscape:export-ydpi="3.9423411"
inkscape:export-xdpi="3.9423411"
style="fill:#007f19;fill-opacity:1;stroke:#000000;stroke-width:10;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
d="M 37.868598,36.470018 V 232.64584 L 190.42945,144.56479 c 0,0 -151.491774,-103.81846 -152.560852,-108.094772 z"
id="path1510" />
</g>
<g
inkscape:label="Pause"
id="layer8"
inkscape:groupmode="layer">
<rect
y="87.475571"
x="64.679222"
height="126.87458"
width="18.708866"
id="rect1576"
style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#999999;stroke-width:8.58558;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none" />
<rect
style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#999999;stroke-width:8.58558;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none"
id="rect1576-6"
width="18.708866"
height="126.87458"
x="125.88395"
y="87.475571" />
</g>
<g
style="display:none"
inkscape:label="Reset"
id="layer7"
inkscape:groupmode="layer">
<g
inkscape:export-ydpi="3.4793682"
inkscape:export-xdpi="3.4793682"
id="g1573">
<g
id="g1544"
style="fill:#000000;fill-opacity:1">
<path
id="path1538"
d="m 14.741071,126.62202 h 21.166665 c 0,0 76.351194,-123.9761867 126.244044,-0.37798 25.32441,0 25.32441,0 25.32441,0 0,0 -67.27976,-195.035712 -172.735119,0.37798 z"
style="fill:#000000;fill-opacity:1;stroke:#000000;stroke-width:0.264583px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" />
<path
sodipodi:nodetypes="ccccc"
id="path1540"
d="m 162.15178,126.24404 h -27.44794 l 41.64763,41.64763 35.4576,-41.69421 -24.33288,0.0466"
style="fill:#000000;fill-opacity:1;stroke:#000000;stroke-width:0.264583px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" />
</g>
<g
style="fill:#000000;fill-opacity:1"
id="g1544-5"
transform="rotate(180,104.01125,156.34664)">
<path
style="fill:#000000;fill-opacity:1;stroke:#000000;stroke-width:0.264583px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
d="m 14.741071,126.62202 h 21.166665 c 0,0 76.351194,-123.9761867 126.244044,-0.37798 25.32441,0 25.32441,0 25.32441,0 0,0 -67.27976,-195.035712 -172.735119,0.37798 z"
id="path1538-8" />
<path
style="fill:#000000;fill-opacity:1;stroke:#000000;stroke-width:0.264583px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
d="m 162.15178,126.24404 h -27.44794 l 41.64763,41.64763 35.4576,-41.69421 -24.33288,0.0466"
id="path1540-0"
sodipodi:nodetypes="ccccc" />
</g>
</g>
</g>
<g <g
style="display:none" style="display:none"
inkscape:groupmode="layer" inkscape:groupmode="layer"

Before

Width:  |  Height:  |  Size: 3.9 KiB

After

Width:  |  Height:  |  Size: 11 KiB

@ -4,6 +4,7 @@ const RUNNING = 1;
const REVIEWING = 2; const REVIEWING = 2;
const TESTING = 3; const TESTING = 3;
const FINISH = 4; const FINISH = 4;
const PAUSED = 5;
const UP = 0; const UP = 0;
const RIGHT = 1; const RIGHT = 1;
@ -15,9 +16,9 @@ const BLUE = "B";
const GREEN = "G"; const GREEN = "G";
const YELLOW = "Y"; const YELLOW = "Y";
const PURPLE = "P"; const PURPLE = "P";
const PINK = "PI"; const PINK = "p";
const BLACK = "BL"; const BLACK = "b";
const GRAY = "GR"; const GRAY = "g";
const ALIVE = 0; const ALIVE = 0;
const DEAD = 1; const DEAD = 1;
@ -29,6 +30,7 @@ var BOT_DIR = RIGHT
var BOT_STATE = ALIVE var BOT_STATE = ALIVE
var BOT_TAPE = "RB" var BOT_TAPE = "RB"
var BOT_QUEUE = [] var BOT_QUEUE = []
var DELETEMODE = false
var BELTDOWN = {type:"BELT",direction:DOWN/*,direction2 - defines a secondary direction. For two belts at once.*/} var BELTDOWN = {type:"BELT",direction:DOWN/*,direction2 - defines a secondary direction. For two belts at once.*/}
var BELTRIGHT = {type:"BELT",direction:RIGHT} var BELTRIGHT = {type:"BELT",direction:RIGHT}
@ -38,10 +40,10 @@ var BRANCHDOWN = {type:"BRANCH",direction:DOWN,color1:RED,color2:BLUE} //color 1
var BRANCHLEFT = {type:"BRANCH",direction:LEFT,color1:RED,color2:BLUE} var BRANCHLEFT = {type:"BRANCH",direction:LEFT,color1:RED,color2:BLUE}
var BRANCHRIGHT = {type:"BRANCH",direction:RIGHT,color1:RED,color2:BLUE} var BRANCHRIGHT = {type:"BRANCH",direction:RIGHT,color1:RED,color2:BLUE}
var BRANCHUP = {type:"BRANCH",direction:UP,color1:RED,color2:BLUE} var BRANCHUP = {type:"BRANCH",direction:UP,color1:RED,color2:BLUE}
var WRITERDOWN = {type:"WRITER",direction:DOWN,color:RED/*overwrite - if turned on, the writer overwrites the current tape position instead of appending.*/} var WRITERDOWN = {type:"WRITER",direction:DOWN,color1:RED/*overwrite - if turned on, the writer overwrites the current tape position instead of appending.*/}
var WRITERLEFT = {type:"WRITER",direction:LEFT,color:RED} var WRITERLEFT = {type:"WRITER",direction:LEFT,color1:RED}
var WRITERRIGHT = {type:"WRITER",direction:RIGHT,color:RED} var WRITERRIGHT = {type:"WRITER",direction:RIGHT,color1:RED}
var WRITERUP = {type:"WRITER",direction:UP,color:RED} var WRITERUP = {type:"WRITER",direction:UP,color1:RED}
var DEF_BRANCHUP_RB = {img:IMAGE_BRANCH,color1:RED,color2:BLUE,type:"BRANCH"} var DEF_BRANCHUP_RB = {img:IMAGE_BRANCH,color1:RED,color2:BLUE,type:"BRANCH"}
var DEF_BRANCHUP_BR = {img:IMAGE_BRANCH,color1:BLUE,color2:RED,type:"BRANCH"} var DEF_BRANCHUP_BR = {img:IMAGE_BRANCH,color1:BLUE,color2:RED,type:"BRANCH"}
@ -72,6 +74,8 @@ var LAST_MOUSE_Y=0;
var ITEM_DIRECTION=RIGHT; var ITEM_DIRECTION=RIGHT;
var dashOffset=0
var SUBMENU = { var SUBMENU = {
visible:false, visible:false,
width:0, width:0,
@ -82,20 +86,102 @@ var SUBMENU = {
var BUTTON_SELECTED = undefined var BUTTON_SELECTED = undefined
var ITEM_SELECTED = undefined var ITEM_SELECTED = undefined
var KEY_ROTATION_RIGHT = ["d","l","6","ArrowRight"]
var KEY_ROTATION_LEFT = ["a","h","4","ArrowLeft"]
var KEY_ROTATION_UP = ["w","k","8","ArrowUp"]
var KEY_ROTATION_DOWN = ["s","j","2","ArrowDown"]
var CONVEYOR_BUILD_BUTTON = {img:IMAGE_CONVEYOR,x:-1,y:-1,w:-1,h:-1,lastselected:DEF_CONVEYOR} var CONVEYOR_BUILD_BUTTON = {img:IMAGE_CONVEYOR,x:-1,y:-1,w:-1,h:-1,lastselected:DEF_CONVEYOR}
var BRANCH_BUILD_BUTTON = {img:IMAGE_BRANCH,x:-1,y:-1,w:-1,h:-1,submenu_buttons:[DEF_BRANCHUP_RB,DEF_BRANCHUP_BR,DEF_BRANCHUP_GY,DEF_BRANCHUP_YG,DEF_BRANCHUP_PPI,DEF_BRANCHUP_PIP,DEF_BRANCHUP_BLGR,DEF_BRANCHUP_GRBL],lastselected:undefined} var BRANCH_BUILD_BUTTON = {img:IMAGE_BRANCH,x:-1,y:-1,w:-1,h:-1,submenu_buttons:[DEF_BRANCHUP_RB,DEF_BRANCHUP_BR,DEF_BRANCHUP_GY,DEF_BRANCHUP_YG,DEF_BRANCHUP_PPI,DEF_BRANCHUP_PIP,DEF_BRANCHUP_BLGR,DEF_BRANCHUP_GRBL],lastselected:undefined}
var WRITER_BUILD_BUTTON = {img:IMAGE_WRITER,x:-1,y:-1,w:-1,h:-1,submenu_buttons:[DEF_WRITERRIGHT_R,DEF_WRITERRIGHT_B,DEF_WRITERRIGHT_G,DEF_WRITERRIGHT_Y,DEF_WRITERRIGHT_P,DEF_WRITERRIGHT_PI,DEF_WRITERRIGHT_BL,DEF_WRITERRIGHT_GR],lastselected:undefined} var WRITER_BUILD_BUTTON = {img:IMAGE_WRITER,x:-1,y:-1,w:-1,h:-1,submenu_buttons:[DEF_WRITERRIGHT_R,DEF_WRITERRIGHT_B,DEF_WRITERRIGHT_G,DEF_WRITERRIGHT_Y,DEF_WRITERRIGHT_P,DEF_WRITERRIGHT_PI,DEF_WRITERRIGHT_BL,DEF_WRITERRIGHT_GR],lastselected:undefined}
var ROTATE_CLOCKWISE_BUTTON = {img:IMAGE_ROTATE_CLOCKWISE,x:-1,y:-1,w:-1,h:-1,cb:rotateClockwise
}
var ROTATE_COUNTERCLOCKWISE_BUTTON = {img:IMAGE_ROTATE_COUNTERCLOCKWISE,x:-1,y:-1,w:-1,h:-1,cb:rotateCounterClockwise
}
var WRITER_BUILD_BUTTON = {img:IMAGE_WRITER,x:-1,y:-1,w:-1,h:-1,submenu_buttons:[DEF_WRITERRIGHT_R,DEF_WRITERRIGHT_B,DEF_WRITERRIGHT_G,DEF_WRITERRIGHT_Y,DEF_WRITERRIGHT_P,DEF_WRITERRIGHT_PI,DEF_WRITERRIGHT_BL,DEF_WRITERRIGHT_GR],lastselected:undefined}
var PLAY_BUTTON = {img:IMAGE_PLAY,x:-1,y:-1,w:-1,h:-1,cb:runGameSimulation
}
var PAUSE_BUTTON = {img:IMAGE_PAUSE,x:-1,y:-1,w:-1,h:-1,cb:pauseGameSimulation
}
var RESET_BUTTON = {img:IMAGE_RESET,x:-1,y:-1,w:-1,h:-1,cb:resetSimulation
}
var DELETE_BUTTON = {img:IMAGE_DELETE,x:-1,y:-1,w:-1,h:-1,cb:toggleDeleteMode
}
var MENU = { var MENU = {
visible:true, visible:true,
buttons:[CONVEYOR_BUILD_BUTTON,BRANCH_BUILD_BUTTON,WRITER_BUILD_BUTTON] buttons:[CONVEYOR_BUILD_BUTTON,BRANCH_BUILD_BUTTON,WRITER_BUILD_BUTTON,ROTATE_COUNTERCLOCKWISE_BUTTON,ROTATE_CLOCKWISE_BUTTON,DELETE_BUTTON,PLAY_BUTTON,RESET_BUTTON]
}
function runGameSimulation(){
gameState=TESTING
generateBotQueue()
//console.log(BOT_QUEUE)
if (BOT_QUEUE.length>0) {
BOT_TAPE=BOT_QUEUE[0]
} else {
BOT_TAPE="BR"
}
BOT_STATE=ALIVE
gameState=WAITING
BOT_X=gameStage.start.x
BOT_Y=gameStage.start.y
BOT_DIR=RIGHT
gameState=RUNNING
for (var i=0;i<MENU.buttons.length;i++) {
if (MENU.buttons[i].img===IMAGE_PLAY) {
MENU.buttons[i]=PAUSE_BUTTON
break;
}
}
}
function endARound() {
for (var i=0;i<MENU.buttons.length;i++) {
if (MENU.buttons[i].img===IMAGE_PAUSE) {
MENU.buttons[i]=PLAY_BUTTON
break;
}
}
}
function pauseGameSimulation(){
gameState=PAUSED
endARound()
}
function resetSimulation(){
BOT_STATE=ALIVE
gameState=WAITING
BOT_X=gameStage.start.x
BOT_Y=gameStage.start.y
BOT_DIR=RIGHT
endARound()
}
function toggleDeleteMode(){
DELETEMODE=!DELETEMODE
if (DELETEMODE) {
ITEM_SELECTED=undefined
document.body.style.cursor="url('delete_cursor.png') 8 8,auto"
} else {
document.body.style.cursor="url('cursor.png') 8 8,auto"
}
}
function rotateClockwise() {
ITEM_DIRECTION=(ITEM_DIRECTION+1)%4
}
function rotateCounterClockwise() {
ITEM_DIRECTION=(ITEM_DIRECTION-1);
if(ITEM_DIRECTION<0){ITEM_DIRECTION=3}
} }
var lastGameUpdate = 0; var lastGameUpdate = 0;
var gameSpeed = 1000/1; var gameSpeed = 1000/1;
var gameState=RUNNING; var gameState=WAITING;
var gameStage=0; var gameStage=0;
var LEVEL0 = [ var LEVEL0 = [
@ -140,6 +226,9 @@ var STAGE2 = {
level:createGrid(5,5,4,2), level:createGrid(5,5,4,2),
start:{x:0,y:2}, start:{x:0,y:2},
accept:(tape)=>{ accept:(tape)=>{
if (tape.length===0) {
return false;
}
for (var i=0;i<tape.length;i++) { for (var i=0;i<tape.length;i++) {
if (tape[i]!=="B") { if (tape[i]!=="B") {
return false; return false;
@ -149,7 +238,7 @@ var STAGE2 = {
} }
} }
var gameGrid= [] var gameGrid = []
function createGrid(width=5,height=5,exitX=4,exitY=2) { function createGrid(width=5,height=5,exitX=4,exitY=2) {
var grid = [] var grid = []
@ -177,6 +266,7 @@ function resetGame() {
} }
function generateBotQueue() { function generateBotQueue() {
BOT_QUEUE=[]
if (gameState===TESTING) { if (gameState===TESTING) {
//Iterate up to...15 RED/BLUE combinations. //Iterate up to...15 RED/BLUE combinations.
var MAX_VALUE=1000 var MAX_VALUE=1000
@ -210,7 +300,6 @@ function getSimulatedBotResult(tape) {
var iterations=0 var iterations=0
while (iterations<MAX_ITERATIONS) { while (iterations<MAX_ITERATIONS) {
runBot(true) runBot(true)
//renderGame()
if (gameState===REVIEWING) { if (gameState===REVIEWING) {
//console.log("Rejected") //console.log("Rejected")
return false return false
@ -239,6 +328,19 @@ function ConvertNumberToTape(val) {
return tape; return tape;
} }
function setNextSquare(offsetX,offsetY) {
if (gameGrid[BOT_Y+offsetY]!==undefined) {
var nextSquare = gameGrid[BOT_Y+offsetY][BOT_X+offsetX];
BOT_X+=offsetX
BOT_Y+=offsetY
return nextSquare
} else {
gameState = REVIEWING
BOT_STATE = DEAD
return undefined
}
}
function runBot(testing) { function runBot(testing) {
//console.log(new Date().getTime()) //console.log(new Date().getTime())
if (lastGameUpdate<new Date().getTime()||testing) { if (lastGameUpdate<new Date().getTime()||testing) {
@ -247,27 +349,35 @@ function runBot(testing) {
var nextSquare = {} var nextSquare = {}
switch (BOT_DIR) { switch (BOT_DIR) {
case UP:{ case UP:{
nextSquare = gameGrid[--BOT_Y][BOT_X]; nextSquare = setNextSquare(0,-1)
BOT_DIR=(nextSquare.direction2 && if (nextSquare!==undefined) {
(nextSquare.direction2===UP||nextSquare.direction2===DOWN))?nextSquare.direction2:nextSquare.direction BOT_DIR=(nextSquare.direction2 &&
(nextSquare.direction2===UP||nextSquare.direction2===DOWN))?nextSquare.direction2:nextSquare.direction
}
}break; }break;
case LEFT:{ case LEFT:{
nextSquare = gameGrid[BOT_Y][--BOT_X]; nextSquare = setNextSquare(-1,0)
BOT_DIR=(nextSquare.direction2 && if (nextSquare!==undefined) {
(nextSquare.direction2===RIGHT||nextSquare.direction2===LEFT))?nextSquare.direction2:nextSquare.direction BOT_DIR=(nextSquare.direction2 &&
(nextSquare.direction2===RIGHT||nextSquare.direction2===LEFT))?nextSquare.direction2:nextSquare.direction
}
}break; }break;
case RIGHT:{ case RIGHT:{
nextSquare = gameGrid[BOT_Y][++BOT_X]; nextSquare = setNextSquare(1,0);
BOT_DIR=(nextSquare.direction2 && if (nextSquare!==undefined) {
(nextSquare.direction2===RIGHT||nextSquare.direction2===LEFT))?nextSquare.direction2:nextSquare.direction BOT_DIR=(nextSquare.direction2 &&
(nextSquare.direction2===RIGHT||nextSquare.direction2===LEFT))?nextSquare.direction2:nextSquare.direction
}
}break; }break;
case DOWN:{ case DOWN:{
nextSquare = gameGrid[++BOT_Y][BOT_X]; nextSquare = setNextSquare(0,1)
BOT_DIR=(nextSquare.direction2 && if (nextSquare!==undefined) {
(nextSquare.direction2===UP||nextSquare.direction2===DOWN))?nextSquare.direction2:nextSquare.direction BOT_DIR=(nextSquare.direction2 &&
(nextSquare.direction2===UP||nextSquare.direction2===DOWN))?nextSquare.direction2:nextSquare.direction
}
}break; }break;
} }
if (nextSquare.direction!==undefined||nextSquare.type==="EXIT") { if (nextSquare!==undefined&&(nextSquare.direction!==undefined||nextSquare.type==="EXIT")) {
switch (nextSquare.type) { switch (nextSquare.type) {
case "BRANCH":{ case "BRANCH":{
//console.log("Branch found") //console.log("Branch found")
@ -286,9 +396,9 @@ function runBot(testing) {
}break; }break;
case "WRITER":{ case "WRITER":{
if (nextSquare.overwrite) { if (nextSquare.overwrite) {
OverwriteTape(nextSquare.color) OverwriteTape(nextSquare.color1)
} else { } else {
AppendTape(nextSquare.color) AppendTape(nextSquare.color1)
} }
BOT_DIR = nextSquare.direction BOT_DIR = nextSquare.direction
}break; }break;
@ -301,8 +411,8 @@ function runBot(testing) {
} else { } else {
gameState = REVIEWING gameState = REVIEWING
BOT_STATE = DEAD BOT_STATE = DEAD
endARound()
} }
//if (!testing){renderGame()}
} }
} }
@ -330,7 +440,32 @@ function setupGame() {
canvas.addEventListener("touchmove",updateMouse) canvas.addEventListener("touchmove",updateMouse)
canvas.addEventListener("touchstart",clickEvent) canvas.addEventListener("touchstart",clickEvent)
canvas.addEventListener("touchend",releaseEvent) canvas.addEventListener("touchend",releaseEvent)
//gameGrid = [...createGrid(5,5)] document.addEventListener("keydown",keydownEvent)
loadStage(STAGE2)
}
function CheckKeys(e,keys) {
for (var key of keys) {
if (key===e.key) {
return true
}
}
return false
}
function keydownEvent(e) {
if (CheckKeys(e,KEY_ROTATION_RIGHT)) {
ITEM_DIRECTION=RIGHT
}
if (CheckKeys(e,KEY_ROTATION_LEFT)) {
ITEM_DIRECTION=LEFT
}
if (CheckKeys(e,KEY_ROTATION_UP)) {
ITEM_DIRECTION=UP
}
if (CheckKeys(e,KEY_ROTATION_DOWN)) {
ITEM_DIRECTION=DOWN
}
} }
function mouseOverButton(canvas,e,button) { function mouseOverButton(canvas,e,button) {
@ -345,35 +480,49 @@ function clickEvent(e) {
if (MENU.visible) { if (MENU.visible) {
for (var button of MENU.buttons) { for (var button of MENU.buttons) {
if (mouseOverButton(canvas,e,button)) { if (mouseOverButton(canvas,e,button)) {
if (button.submenu_buttons&&button.submenu_buttons.length>0) { if (button.cb!==undefined) {
BUTTON_SELECTED=button; button.cb()
SUBMENU.visible=true; return;
SUBMENU.buttons=[] } else {
var index = 0; DELETEMODE=false
for (var button2 of BUTTON_SELECTED.submenu_buttons) { document.body.style.cursor="url('cursor.png') 8 8,auto"
var buttonX = ((index%3)*48)+16 if (button.submenu_buttons&&button.submenu_buttons.length>0) {
var buttonY = canvas.height*0.8-(Math.floor(index/3)*48)-40 BUTTON_SELECTED=button;
SUBMENU.buttons.push({def:button2,img:button2.img,x:buttonX,y:buttonY,w:32,h:32}) SUBMENU.visible=true;
index++; SUBMENU.buttons=[]
var index = 0;
for (var button2 of BUTTON_SELECTED.submenu_buttons) {
var buttonX = ((index%3)*48)+16
var buttonY = canvas.height*0.8-(Math.floor(index/3)*48)-40
SUBMENU.buttons.push({def:button2,img:button2.img,x:buttonX,y:buttonY,w:32,h:32})
index++;
}
} }
ITEM_SELECTED=button.lastselected
//console.log(button)
return
} }
ITEM_SELECTED=button.lastselected
//console.log(button)
return
} }
} }
} }
//console.log(getGridCoords(getMousePos(e))) //console.log(getGridCoords(getMousePos(e)))
if (ITEM_SELECTED!==undefined) { if (ITEM_SELECTED!==undefined||DELETEMODE) {
var clickCoords = getGridCoords(getMousePos(e)) var clickCoords = getGridCoords(getMousePos(e))
if (clickCoords.x>=0&&clickCoords.y>=0&&clickCoords.y<gameGrid.length&&clickCoords.x<gameGrid[clickCoords.y].length) { if (clickCoords.x>=0&&clickCoords.y>=0&&clickCoords.y<gameGrid.length&&clickCoords.x<gameGrid[clickCoords.y].length) {
placeObject(clickCoords,ITEM_SELECTED) if (DELETEMODE) {
deleteObject(clickCoords)
} else {
placeObject(clickCoords,ITEM_SELECTED)
}
//console.log(gameGrid) //console.log(gameGrid)
} }
} }
} }
function deleteObject(coords,def) {
gameGrid[coords.y][coords.x]={}
}
function placeObject(coords,def) { function placeObject(coords,def) {
var newObj={...def,direction:ITEM_DIRECTION} var newObj={...def,direction:ITEM_DIRECTION}
gameGrid[coords.y][coords.x]=newObj gameGrid[coords.y][coords.x]=newObj
@ -395,6 +544,7 @@ function releaseEvent(e) {
return return
} }
} }
SUBMENU.visible=false
} }
} }
@ -421,6 +571,7 @@ function deepCopy(arr) {
} }
function step() { function step() {
dashOffset+=0.3
if (gameState===RUNNING) { if (gameState===RUNNING) {
runBot() runBot()
} }
@ -450,26 +601,31 @@ function getMousePos(e) {
} }
function renderGame(ctx) { function renderGame(ctx) {
var displayGrid = [] ctx.lineWidth=1
for (var y=0;y<=gameGrid.length;y++) { ctx.strokeStyle="#000000"
ctx.setLineDash([])
for (var y=0;y<=gameGrid.length+1;y++) {
ctx.moveTo(GRID_X, GRID_Y+GRID_H*y); ctx.moveTo(GRID_X, GRID_Y+GRID_H*y);
ctx.lineTo(GRID_X+GRID_W*gameGrid.length, GRID_Y+GRID_H*y); ctx.lineTo(GRID_X+GRID_W*(gameGrid.length+1), GRID_Y+GRID_H*y);
} }
for (var x=0;x<=gameGrid.length;x++) { for (var x=0;x<=gameGrid.length+1;x++) {
ctx.moveTo(GRID_X+GRID_W*x, GRID_Y); ctx.moveTo(GRID_X+GRID_W*x, GRID_Y);
ctx.lineTo(GRID_X+GRID_W*x, GRID_Y+GRID_H*gameGrid.length); ctx.lineTo(GRID_X+GRID_W*x, GRID_Y+GRID_H*(gameGrid.length+1));
} }
ctx.fillStyle="#000000"
ctx.stroke(); ctx.stroke();
for (var y=0;y<gameGrid.length;y++) { for (var y=0;y<gameGrid.length;y++) {
for (var x=0;x<gameGrid[y].length;x++) { for (var x=0;x<gameGrid[y].length;x++) {
if (gameGrid[y][x].img!==undefined) { if (gameGrid[y][x].img!==undefined) {
RenderIcon(GRID_X+GRID_W*x+16,GRID_Y+GRID_H*y+16,ctx,gameGrid[y][x],gameGrid[y][x].direction) RenderIcon(GRID_X+GRID_W*x+16,GRID_Y+GRID_H*y+16,ctx,gameGrid[y][x],gameGrid[y][x].direction,undefined,{x:x,y:y})
}
if (BOT_X!==undefined) {
drawImage(
GRID_X+GRID_W*BOT_X+16+GRID_W/2,
GRID_Y+GRID_H*BOT_Y+16+GRID_H/2,
IMAGE_BOT,ctx,0*90)
} }
} }
} }
/*console.log("Tape: "+BOT_TAPE)
console.log(displayGrid)*/
} }
function colorToHex(r,g,b) { function colorToHex(r,g,b) {
@ -528,48 +684,267 @@ function draw() {
renderGame(ctx) renderGame(ctx)
if (ITEM_SELECTED) { if (ITEM_SELECTED) {
RenderIcon(LAST_MOUSE_X-16,LAST_MOUSE_Y-16,ctx,ITEM_SELECTED,0) RenderIcon(LAST_MOUSE_X-16,LAST_MOUSE_Y-16,ctx,ITEM_SELECTED,ITEM_DIRECTION)
} }
//drawImage(0,0,IMAGE_CONVEYOR,ctx,0) //drawImage(0,0,IMAGE_CONVEYOR,ctx,0)
//drawImage(LAST_MOUSE_X,LAST_MOUSE_Y,IMAGE_ARROW,ctx,0) //drawImage(LAST_MOUSE_X,LAST_MOUSE_Y,IMAGE_ARROW,ctx,0)
RenderSubmenu(ctx) RenderSubmenu(ctx)
RenderMenu(ctx) RenderMenu(ctx)
RenderGameInfo(ctx)
}
}
function RenderGameInfo(ctx) {
if (MENU.visible) {
ctx.fillStyle="#20424a"
ctx.fillRect(canvas.width*0.75,0,canvas.width,canvas.height*0.8)
RenderTape(canvas.width*0.75+8,8,canvas.width*0.25-16,ctx)
} }
} }
function RenderIcon(x,y,ctx,icon_definition,rot=0,background=undefined) { function RenderTape(x,y,width,ctx) {
var xOffset=0
var yOffset=0
for (var i=0;i<BOT_TAPE.length;i++) {
switch (BOT_TAPE[i]) {
case RED:{
drawImage(x+xOffset+16,y+yOffset+16,IMAGE_DOT_R,ctx,0)
}break;
case BLUE:{
drawImage(x+xOffset+16,y+yOffset+16,IMAGE_DOT_B,ctx,0)
}break;
case GREEN:{
drawImage(x+xOffset+16,y+yOffset+16,IMAGE_DOT_G,ctx,0)
}break;
case YELLOW:{
drawImage(x+xOffset+16,y+yOffset+16,IMAGE_DOT_Y,ctx,0)
}break;
case PURPLE:{
drawImage(x+xOffset+16,y+yOffset+16,IMAGE_DOT_P,ctx,0)
}break;
case PINK:{
drawImage(x+xOffset+16,y+yOffset+16,IMAGE_DOT_PI,ctx,0)
}break;
case BLACK:{
drawImage(x+xOffset+16,y+yOffset+16,IMAGE_DOT_BL,ctx,0)
}break;
case GRAY:{
drawImage(x+xOffset+16,y+yOffset+16,IMAGE_DOT_GR,ctx,0)
}break;
}
xOffset+=24;
if (xOffset>width-24) {
xOffset=0;
yOffset+=24;
}
}
}
function createVerticalGradient(x,y,up,ctx) {
var gradient = ctx.createLinearGradient(x, y+32*((up)?1:0), x, y+32*((up)?0:1));
gradient.addColorStop(0,"rgb(124,162,157)")
gradient.addColorStop(0.31,"black")
gradient.addColorStop(0.6,"rgb(124,162,157)")
gradient.addColorStop(0.61,"black")
gradient.addColorStop(0.9,"rgb(124,162,157)")
gradient.addColorStop(0.91,"white")
gradient.addColorStop(1,"white")
return gradient
}
function createHorizontalGradient(x,y,right,ctx) {
var gradient = ctx.createLinearGradient(x+32*((right)?0:1), y, x+32*((right)?1:0), y);
gradient.addColorStop(0,"rgb(124,162,157)")
gradient.addColorStop(0.31,"black")
gradient.addColorStop(0.6,"rgb(124,162,157)")
gradient.addColorStop(0.61,"black")
gradient.addColorStop(0.9,"rgb(124,162,157)")
gradient.addColorStop(0.91,"white")
gradient.addColorStop(1,"white")
return gradient
}
function DrawSingleConveyor(x,y,dir,ctx) {
ctx.lineWidth = 16;
ctx.lineCap = "square"
ctx.strokeStyle="rgb(124,162,157)"
ctx.setLineDash([])
if (dir===LEFT||dir===RIGHT) {
ctx.beginPath()
ctx.moveTo(x+8,y+16)
ctx.lineTo(x+24,y+16)
ctx.stroke()
ctx.setLineDash([5,5])
ctx.lineDashOffset = -dashOffset*((dir===LEFT)?-1:1);
ctx.strokeStyle=createHorizontalGradient(x,y,dir===RIGHT,ctx)
ctx.lineWidth = 3.5;
ctx.beginPath()
ctx.moveTo(x+2,y+16)
ctx.lineTo(x+30,y+16)
ctx.stroke()
} else {
ctx.beginPath()
ctx.moveTo(x+16,y+8)
ctx.lineTo(x+16,y+24)
ctx.stroke()
ctx.strokeStyle="rgb(34,62,57)"
ctx.setLineDash([5,5])
ctx.lineDashOffset = -dashOffset*((dir===DOWN)?1:-1);
ctx.strokeStyle=createVerticalGradient(x,y,dir===UP,ctx)
ctx.lineWidth = 3.5;
ctx.beginPath()
ctx.moveTo(x+16,y+2)
ctx.lineTo(x+16,y+30)
ctx.stroke()
}
}
function GetOppositeDirection(dir) {
switch (dir) {
case UP:{return DOWN}
case DOWN:{return UP}
case LEFT:{return RIGHT}
case RIGHT:{return LEFT}
}
}
function DrawConnectedConveyor(x,y,ctx,connections,dir,pass=0) {
ctx.lineWidth = 15;
ctx.lineCap = "round"
ctx.strokeStyle="rgb(124,162,157)"
switch (Object.keys(connections).length) {
case 0:{
DrawSingleConveyor(x,y,dir,ctx)
}break;
default:{
ctx.lineWidth = 15;
ctx.lineCap = "square"
ctx.strokeStyle="rgb(124,162,157)"
ctx.setLineDash([])
ctx.beginPath()
ctx.moveTo(x+16,y+16)
var endingPoint={x:0,y:0}
switch (dir) {
case UP:{startingPoint={x:0,y:-12};endingPoint={x:0,y:-14}}break;
case DOWN:{startingPoint={x:0,y:12};endingPoint={x:0,y:14}}break;
case RIGHT:{startingPoint={x:12,y:0};endingPoint={x:14,y:0}}break;
case LEFT:{startingPoint={x:-12,y:0};endingPoint={x:-14,y:0}}break;
}
ctx.moveTo(x+16+startingPoint.x,y+16+startingPoint.y)
ctx.lineTo(x+16+endingPoint.x,y+16+endingPoint.y)
if (pass===0) {ctx.stroke();}
for (var connection of Object.keys(connections)) {
var startingPoint={x:x,y:y}
switch (Number(connection)) {
case UP:{startingPoint={x:x+16,y:y+8}}break;
case DOWN:{startingPoint={x:x+16,y:y+24}}break;
case RIGHT:{startingPoint={x:x+24,y:y+16}}break;
case LEFT:{startingPoint={x:x+8,y:y+16}}break;
}
ctx.lineWidth = 16;
ctx.lineCap = "square"
ctx.strokeStyle="rgb(124,162,157)"
ctx.setLineDash([])
ctx.beginPath()
ctx.moveTo(startingPoint.x,startingPoint.y)
ctx.lineTo(x+16,y+16)
if (pass===0) {ctx.stroke()}
ctx.setLineDash([5,5])
ctx.lineDashOffset = -dashOffset*1;
if (Number(connection)===RIGHT||Number(connection)===LEFT) {
ctx.strokeStyle=createHorizontalGradient(x,y,Number(connection)===LEFT,ctx)
} else {
ctx.strokeStyle=createVerticalGradient(x,y,Number(connection)===UP,ctx)
}
ctx.lineWidth = 3.5;
ctx.beginPath()
startingPoint={x:x,y:y}
switch (Number(connection)) {
case UP:{startingPoint={x:x+16,y:y+2}}break;
case DOWN:{startingPoint={x:x+16,y:y+30}}break;
case RIGHT:{startingPoint={x:x+30,y:y+16}}break;
case LEFT:{startingPoint={x:x+2,y:y+16}}break;
}
ctx.moveTo(startingPoint.x,startingPoint.y)
ctx.lineTo(x+16,y+16)
if (pass===1) {ctx.stroke()}
}
if (dir===RIGHT||dir===LEFT) {
ctx.strokeStyle=createHorizontalGradient(x,y,dir===LEFT,ctx)
} else {
ctx.strokeStyle=createVerticalGradient(x,y,dir===UP,ctx)
}
ctx.setLineDash([5,5])
ctx.lineWidth = 3.5;
ctx.beginPath()
switch (dir) {
case UP:{startingPoint={x:0,y:-14}}break;
case DOWN:{startingPoint={x:0,y:14}}break;
case RIGHT:{startingPoint={x:14,y:0}}break;
case LEFT:{startingPoint={x:-14,y:0}}break;
}
ctx.moveTo(x+16,y+16)
ctx.lineTo(x+16+startingPoint.x,y+16+startingPoint.y)
if (pass===1) {ctx.stroke();}
}break;
}
}
function RenderConveyor(x,y,ctx,icon_definition,dir=0,background=undefined,grid=undefined) {
if (grid===undefined) {
DrawSingleConveyor(x,y,dir,ctx)
} else {
var connections = {}
if (grid.x>0) {if (gameGrid[grid.y][grid.x-1].direction===RIGHT){connections[LEFT]=true}}
if (grid.x<gameGrid[grid.y].length-1) {if (gameGrid[grid.y][grid.x+1].direction===LEFT){connections[RIGHT]=true}}
if (grid.y>0) {if (gameGrid[grid.y-1][grid.x].direction===DOWN){connections[UP]=true}}
if (grid.y<gameGrid.length-1) {if (gameGrid[grid.y+1][grid.x].direction===UP){connections[DOWN]=true}}
//console.log("Connections: "+JSON.stringify(connections))
DrawConnectedConveyor(x,y,ctx,connections,dir)
DrawConnectedConveyor(x,y,ctx,connections,dir,1)
}
}
function RenderIcon(x,y,ctx,icon_definition,dir=0,background=undefined,renderToGrid=undefined) {
if (background!==undefined) { if (background!==undefined) {
ctx.fillStyle=background ctx.fillStyle=background
ctx.fillRect(x,y,32,32) ctx.fillRect(x,y,32,32)
} }
if (icon_definition.img===IMAGE_BRANCH) { if (icon_definition.img===IMAGE_CONVEYOR) {
drawImage( RenderConveyor(x,y,ctx,icon_definition,dir,background,renderToGrid)
x+16,
y+16,
icon_definition.img,ctx,rot+90)
} else { } else {
drawImage( if (icon_definition.img===IMAGE_BRANCH) {
x+16,
y+16,
icon_definition.img,ctx,rot)
}
switch (icon_definition.img) {
case IMAGE_BRANCH:{
drawImage(
x+16,
y+16,
GetArrowImage(icon_definition.color1),ctx,rot+270)
drawImage( drawImage(
x+16, x+16,
y+16, y+16,
GetArrowImage(icon_definition.color2),ctx,rot+90) icon_definition.img,ctx,dir*90)
}break; } else {
case IMAGE_WRITER:{
drawImage( drawImage(
x+16, x+16,
y+16, y+16,
GetDotImage(icon_definition.color1),ctx,rot) icon_definition.img,ctx,dir*90-90)
}break; }
switch (icon_definition.img) {
case IMAGE_BRANCH:{
drawImage(
x+16,
y+16,
GetArrowImage(icon_definition.color1),ctx,dir*90+0)
drawImage(
x+16,
y+16,
GetArrowImage(icon_definition.color2),ctx,dir*90+180)
}break;
case IMAGE_WRITER:{
drawImage(
x+16,
y+16,
GetDotImage(icon_definition.color1),ctx,dir*90-90)
}break;
}
} }
} }
@ -641,7 +1016,7 @@ function RenderSubmenu(ctx) {
for (var button of BUTTON_SELECTED.submenu_buttons) { for (var button of BUTTON_SELECTED.submenu_buttons) {
var buttonX = ((index%3)*48)+16 var buttonX = ((index%3)*48)+16
var buttonY = canvas.height*0.8-(Math.floor(index/3)*48)-40 var buttonY = canvas.height*0.8-(Math.floor(index/3)*48)-40
RenderIcon(buttonX,buttonY,ctx,button,0,(LAST_MOUSE_X>=buttonX&&LAST_MOUSE_X<=buttonX+32&&LAST_MOUSE_Y>=buttonY&&LAST_MOUSE_Y<=buttonY+32)?"#555555":"#b5b5b5") RenderIcon(buttonX,buttonY,ctx,button,ITEM_DIRECTION,(LAST_MOUSE_X>=buttonX&&LAST_MOUSE_X<=buttonX+32&&LAST_MOUSE_Y>=buttonY&&LAST_MOUSE_Y<=buttonY+32)?"#555555":"#b5b5b5")
index++; index++;
} }
} }
@ -655,9 +1030,9 @@ function RenderMenu(ctx) {
var buttonY = canvas.height*0.8+16 var buttonY = canvas.height*0.8+16
for (var button of MENU.buttons) { for (var button of MENU.buttons) {
if (button.lastselected) { if (button.lastselected) {
RenderIcon(buttonX,buttonY,ctx,button.lastselected,0,"#b5b5b5") RenderIcon(buttonX,buttonY,ctx,button.lastselected,(button.cb===undefined)?ITEM_DIRECTION:0,"#b5b5b5")
} else { } else {
AddButton(button.img,buttonX,buttonY,ctx,button,0) AddButton(button.img,buttonX,buttonY,ctx,button,(button.cb===undefined)?ITEM_DIRECTION:0)
} }
button.x=buttonX button.x=buttonX
button.y=buttonY button.y=buttonY
@ -668,10 +1043,14 @@ function RenderMenu(ctx) {
} }
} }
function AddButton(img,x,y,ctx,button,rot=0) { function AddButton(img,x,y,ctx,button,dir=0) {
ctx.fillStyle="#b5b5b5" ctx.fillStyle="#b5b5b5"
ctx.fillRect(x,y,32,32) ctx.fillRect(x,y,32,32)
drawImage(x+16,y+16,img,ctx,rot) if (img===IMAGE_WRITER) {
drawImage(x+16,y+16,img,ctx,dir*90-90)
} else {
drawImage(x+16,y+16,img,ctx,dir*90)
}
} }
function ConsumeTape() { function ConsumeTape() {

@ -442,9 +442,9 @@ function runTests() {
.it("Run a TESTING state to see if an acceptable player-built level has no bots in queue.",()=>{ .it("Run a TESTING state to see if an acceptable player-built level has no bots in queue.",()=>{
loadStage(STAGE2) loadStage(STAGE2)
gameGrid=[ gameGrid=[
[{},{},{},{},{},], [{},{...BELTRIGHT},{...BELTRIGHT},{...BELTDOWN},{},],
[{},{...BELTDOWN},{},{},{},], [{...BELTRIGHT},{...BRANCHUP},{},{...BELTDOWN},{},],
[{},{...BRANCHRIGHT},{...BELTRIGHT},{...BELTRIGHT},{type:"EXIT"},], [{},{...BRANCHRIGHT},{},{...BELTRIGHT},{type:"EXIT"},],
[{},{},{},{},{},], [{},{},{},{},{},],
[{},{},{},{},{},], [{},{},{},{},{},],
] ]
@ -469,13 +469,15 @@ function runTests() {
console.log("ALL TESTS: "+totalTestsPassed+" passed, "+(totalTests-totalTestsPassed)+" failed, "+totalTests+" total") console.log("ALL TESTS: "+totalTestsPassed+" passed, "+(totalTests-totalTestsPassed)+" failed, "+totalTests+" total")
if (testsPass===undefined) { if (testsPass===undefined) {
testsPass=true testsPass=true
} }
resetGame();
} }
function runGame() { function runGame() {
resetGame();
setupGame(); setupGame();
loadLevel(LEVEL2,0,2) //loadLevel(LEVEL2,0,2)
setInterval(()=>{ setInterval(()=>{
step() step()
draw() draw()

@ -41,4 +41,16 @@ IMAGE_DOT_P.src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8
const IMAGE_DOT_R = new Image(); const IMAGE_DOT_R = new Image();
IMAGE_DOT_R.src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAE4XpUWHRSYXcgcHJvZmlsZSB0eXBlIGV4aWYAAHja3VdZsuQoDPznFHMEJAGC47BGzA3m+JMsdtd7XfWW7v6YmCJssMCSUIqUy/R//h7mL/yYvDPOawwpBIufSy5xxiDa/UvrTtat+3mw1+CN3NwTDJGgl/2o+azPkPsfL1w2qLyVm3hmOB5Fl+ajUKZlxqA9Ogk5bzm5oyj1PQgp6qOrhXdfz8LlyrmC3Mr2u3g2jwKniFLzMCTMXUjsuru9RvaVcUXcReY6gmxKxKDzEo4nCMib7d0BtI8BehPka2TeR/8evQs+5yOXd7EMJ0YYPJ0g/zz4K8QPhuX2iN9NiNWftnOuMVoco+/dZRcQ0XAyagWbLjVYWBByWa8FNMXlMdbVElq02VZA3my1Ba1SIgYqw5CjRpkG9dVXqnDRcWdFz1xZliyKcuIqEyc3Gw1WSdKAIEvlbgCjE759oWU3LXuVIiw3wlImKJtQv2zmo8nvNDNGnSEiG+9YwS+eKQo3JnLzjlUAhMbBza8AX+3Abx/yB6kKBP0Kc8QGsy1bRfH0I7dk4SxY59HvI0RG21GAEMG2hzMkQMAGEk+BrDIrEeIYAVCG5yyOCxAg77nBSXYigY1y5Gkb7yittew58BSDmwAEDpAosEmSAZZzHvmjLiKHshfvvPfBq4/GJ5+DBBd8CEHDJLmsok69BlWNmjRHiS76GKLGGFPMiZOAA30KSVNMKeXMJsNQhq6M9RmSwkWKK76EoiWWVHJF+lRXfQ1Va6yp5sZNGmiihaYtttRyJ9PBFN1130PXHnvqeSDXhgw3/AhDRxxp5Bu1g+pP7Ruo0UGNF1Jznd6oQWpULxU06cRPzIAYOwLiOhFAQvPEzEZyjidyEzObGIfCM5z0ExvTaCIGCF0n9oNu7H4g9yXcjI9fwo0/Q85M6P4EcgbQ/YzbE9TarHN1IbZP4YypFZy+YWvmaDLSXRIIBw95lrdf7M3vKvjPKlLkkfPke0usrmCIr5NaEV4mnKE1NyRq6bMIr9mSNXVaY7w/82hKo3GqqYbzigsa+Z5sQiO1ODEBJNUhP1/7ZZ5OFLmsI4dzPWZSpFFQdOxl1mpyl2/mGrzqFWm3NzxSL9TdeUS+aefqw/HXsHi7xqikL3oaxz+U1l7OQ4evvWZ1x3kDyu5g8eWA/W5PtR+wsLXlr1z+Ru2zSq1YDRDDKy8lx72nZEezcXhT9rOV8nu5ZB4Eg93Wmt2QilO85D1Jt+6VkuGPJ6Y7h48V1/PZjtohv+LT8zzqfocADDFcHOy31V7iAB+93BpI5yRDl4FSuzeYyH6WY4+9+WgBmHkOhOs4cJVGMrg/wdJsMNvYkcUBHc3hj8R6cu7riWU+yTjag9rAqPTgVHvvlLkzrIUT4ISFARmXznug/fbZKbILtQ8XHDPpOpwiDd+MKWyjGfCgkG/y/yj/kWMPSZdq769Mmc+dfmekHiSQ8XUIiuc+DMYNVPUv8cdFRCjHvVZkxpnsmpic+XrKvaW7w+/4mM9Vk21ms2YOacR607N8SM/P2Nibi44T6Bhlw2+eAq3ik+E77GYWvW12u0g01Tds/AUyvo/Is+jic+OUNQQXoQgnuKgpw7m7CKLM4f/uUUSptrMnwpelXvoaExjuR53jNGYonwbS/JnK//9RNPAFl1Cm/wWAC/7YOIDL2QAAAYVpQ0NQSUNDIHByb2ZpbGUAAHicfZE9SMNAHMVfW6VFKoJWKKKQoTpZEBVxlCoWwUJpK7TqYHLpFzRpSFJcHAXXgoMfi1UHF2ddHVwFQfADxMnRSdFFSvxfUmgR48FxP97de9y9A7yNClOMrglAUU09FY8J2dyq4H9FACMYRD/CIjO0RHoxA9fxdQ8PX++iPMv93J+jV84bDPAIxHNM003iDeKZTVPjvE8cYiVRJj4nHtfpgsSPXJccfuNctNnLM0N6JjVPHCIWih0sdTAr6QrxNHFEVlTK92YdljlvcVYqNda6J39hMK+upLlOcxhxLCGBJARIqKGMCkxEaVVJMZCi/ZiLf8j2J8klkasMRo4FVKFAtP3gf/C7W6MwNekkBWNA94tlfYwC/l2gWbes72PLap4AvmfgSm37qw1g9pP0eluLHAF928DFdVuT9oDLHSD8pIm6aEs+mt5CAXg/o2/KAQO3QM+a01trH6cPQIa6Wr4BDg6BsSJlr7u8O9DZ279nWv39AIRqcq4xcIF/AAAABmJLR0QAfwCJAJMFIy6QAAAACXBIWXMAAADGAAAAxgGwdJvFAAAAB3RJTUUH5AgeAwM5t9n9ywAAAXlJREFUOMuV0zFrk1EYBeDnu4FkEIxQ/LK1DsaKtDjo9o1p/4OIhKLVqriI/yJLXLRUKgT9EQ5pxuwOrdhYi+jkINIiFALJdfBLGyXVeKbD5Zz3vnDek0j9iUWsooYL+dsnbGET2+PiZGxACU9xD8FkDLCBx+gbE5bwBvf1s9A8mvFjjrhUF5fqDmZpHs3Qzwp4mGuL4xs8xwOhJl7sUF2Z/H+vJflYY9iBZ3iUSC3irX4W4kL3dHOOuNsS3mUUuwNcDbiD0By8/6cZkvkVjbgHBawGLMPdy99Mi7Xq1xFdDpiFM9X61APOXjrWzgVE/4vhsWUY8AUOe6+m9h/uvR7RzwFt2Oydn3rAxofKiLYTqYU8xsLwSlcyP0WMOxmlkxi38UKxK+zXxN3W3837NUpdWMcOKVJFqY5UdC6LjXIlHlwX4816jDduxe/XxEa5EpWzKBWltnLPb2Uqoom1/EhOK9M6nozKlEyo8wJu5wc2Xuc2Xv5a+wQ/AUYZdXRwlyyeAAAAAElFTkSuQmCC" IMAGE_DOT_R.src="data:image/png;base64,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"
const IMAGE_DOT_Y = new Image(); const IMAGE_DOT_Y = new Image();
IMAGE_DOT_Y.src="data:image/png;base64,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" IMAGE_DOT_Y.src="data:image/png;base64,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"
const IMAGE_ROTATE_CLOCKWISE = new Image();
IMAGE_ROTATE_CLOCKWISE.src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAYCAYAAACbU/80AAAACXBIWXMAAADbAAAA2wHwUOacAAAAGXRFWHRTb2Z0d2FyZQB3d3cuaW5rc2NhcGUub3Jnm+48GgAAAXRJREFUSInF1r9OFFEUgPHfriawu1ESCdgZGkIhWkJhYYQHoLDRxNLwACQklDwAFQ3lJhI6okJB3AcwsbIhtFpBhf8SIya6QHF3ks3A7t47MnKSU8095/vmzp0zw9XHMm7FLq6WIPAIb2MlyhCAObyJkShLAOaxg5HrEoAneI3bvRZUCjSt4SEmMYV7wlYPda5NYyxX8w5P8asAD4ziJbbxHWcFcg/1VPA4VvGlIDSfLTRi4S9wfEXgJIkhvCoB3J27wnm5EDXh/S0TnuXOZRIb/wme5VY3/BlO/6HZET7jR8TaNjYxkcEb+JQI/IYmFnC360bWB9R9wOP81i8lgP92IOP5JgMEDrGIG/mCCvYj4T+FidYv8gInWMOdXgWzkfA2ng+A5wV2cX9QwUqkQDMCngkcCGcjKjYj4CfCRycmZjAcC4f3EQLbKQ1ToqrrXewTrbIEiBscD65T4I/EZ5oSN/FRGCr1DrAi/OFkA+MrfpclcA5HFShV5l7kTwAAAABJRU5ErkJggg=="
const IMAGE_ROTATE_COUNTERCLOCKWISE = new Image();
IMAGE_ROTATE_COUNTERCLOCKWISE.src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAYCAYAAACbU/80AAAACXBIWXMAAADbAAAA2wHwUOacAAAAGXRFWHRTb2Z0d2FyZQB3d3cuaW5rc2NhcGUub3Jnm+48GgAAAXRJREFUSInF1r1LHFEUxuEnLgRdVoJpFKuktg02KdJaCEkhWKRTsLXSvyGFlaZWRNJEAhqCWlslnUhsNCSk0CKLSAh+gR8pZhfGDZs5szrrCweGO+fe98c9nMshrm5M5cgPqSOYV8Z7PL9rgKj5Gq6x0m7zCjZq5m0HqGA9ZV4IwIMm62V8wFDDehVfcYpz/MFP7GIP27V/t1K65nnjCMsYw+NWzDvxqUXzxjjEG/Tfh3k6qhjPMu/CxwLM0zGPh83MVws2r8dy7aZv6F2bzOsx1wjwBEu4DGz+jR84uAXAFUYaIeAFPmdsnk3l9+EVFiTtlwfim6Td/1EJE9gPAKTVi7fBW6zHZJOzkDwiM5JXLQJQ1yiOgwBbGWeBATfbMwsAXkvqHIF4FoGAl9gJAsBiEGA6CkDSv4PB3Kc4CwAs5gHIq5UAwGapQIBHGM7IKUVnwlb0JZBTKdBfGRf+X4KjZhPRXek7emrfl5IJ6loyiZ3g119x6S+ogBYJVgAAAABJRU5ErkJggg=="
const IMAGE_DELETE = new Image();
IMAGE_DELETE.src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABUAAAAgCAYAAAD9oDOIAAAACXBIWXMAAADGAAAAxgGwdJvFAAAAGXRFWHRTb2Z0d2FyZQB3d3cuaW5rc2NhcGUub3Jnm+48GgAAA0BJREFUSIntlV9oW1Ucxz/n3DviTYO9NrFlTToQ2j5YyqIIa1YK4theSsEw5gJ9EP9QweoQFCllreCGdb5UfEspWEFwIAPtQx+a0ILifKjo8uBmpY6aVEi70lwTcps/N/f4sC5aUBJkj/2+HDi/3/nw/Z0fv3MEgILLwBWrre2VL65e/U7TtLvA++VyeebNS5ds4HugDQgLKNBA+sH6ITDiKxQ+8dn2I7bPlxVCBD0ezxPAL8DTwLPNAAEkgAAHeFGAd+D6dU0IEdzc3MSfyVx0pZz+9fTpn+fi8aFmgAB6PB4/AbwcV+qlcCIhTt24wWe2zcfr69z1+9kLBsU3o6P9SqnfmoVKKeXjwHuFQuHElWKRtWPHGL99m49qNR67d49Pz5zB1XWUUs/Nzc29oJQSDaGapqWVUramaSRWVhitVmkF3gAmlOLdhQWWlpaQUj6qlLoohFANodVq9XMhhLelpYWBgQEcoHYQNAHDMIhEIriumwdea6Z83XGcVzVN+1oI8VRnRwcfABngW2ASKEYimKaJlPKHsbGx3Wagcnx8PGPb9iCgnl9f5xTwumHwthD8DryTSkGpRK1We7KZ+wSoJ305OVmLXrsmfzp7lh+jUSzLorK8zOWVFW6dO8fa+fNF4A+lVEkI4bquW5FS2kAe+FMptV8vH0CBJ7ewgHX8OLdGRgBobW2FCxe4U61ycnmZdH9/S7anpxdAKYUQAqX+7pnrukgpFSDEAXTWlfKtryYmyAaDpNNpVldXsSyLno4O4jdvUq7VOAkUhcAwDHRdx+/3EwgECAaDDA0N4fP5Dpcfj8czQAggm82SzWbZ3d0ln8+zv7+P4ziUy+U60DAMTNMkEAgQCoUwTfOB2/rsA2xvbW2FUqkUfX199Pb2Eg6HGzbFcRw2NjZIJBJ0dnYyODh4f/YfqFwus7i4SDKZxOv1AjA7O8v09DTJZBKAvb09pqammJmZud8UXWd+fp5kMkmpVAI4DP035XI5tre3yeVydWc7OztYlvWfZxpC/4+OoEfQI+gR9KHpn480gUCAWCxGe3t7fW94eBjbtunq6gLA5/MRi8XweDz1nGg0SqVSobu7Gzj8nawBzzwMp38BxWJHOyltKE0AAAAASUVORK5CYII="
const IMAGE_RESET = new Image();
IMAGE_RESET.src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAB4AAAAgCAYAAAAFQMh/AAAACXBIWXMAAACIAAAAiAHr3JJSAAAAGXRFWHRTb2Z0d2FyZQB3d3cuaW5rc2NhcGUub3Jnm+48GgAAAltJREFUSImt18tvTVEUx/HP1WiiRNVE1YCItJWiBiIxMRADA21MxCPxiAQTI/+AgUc8ykRUhH9AJQy8JiVmJhJpQkSISBRtJQZarRZlsM9N9729r3N7f8ka3HPWWt+799l7rb1Jpzrsw0MMYQrv0IO1KXNVrM14jX9FbApnUV9L6JEkcTFobE+xqBbQkxUCY+vH/FJJ68pAD6IXmejZXzzBLdzBABrRHPmsxlI8KjusAurEuNyR3Ed7Ad8MDmEsz78rLXQJ3kcJJnGsgritGI3ivmBxGvC9KHgc21PE7pU76guVBu6KgqawMwU0q74oxwRaygU04GMUdKAKqAQ0EeW5VC7gXOR8o0poVtejXD/QFL+Mt9MqXMNvvBK+1Z+UsGWJNeETtiXQX8IMjCTvUi24StSJb8oXmBO1BhOaxdcS0MvFAjvQOkd4u7CH86EPFKmWzcKqHkr+wFzUhs8R9AUWFnJcgOeR4zDWzRHeisHEVhRymIe7Zk/NMNbXAF509q4UgGZtBBvmCC+ooyWgWfuOTbWEZrDSzErrFho/MyVzMPn9U5j6NGrAM6wROtwWYfHOUpNQabIj7U0JytfNKNeZcs49kfMEllcJPRzl+SDsmpJqEWprNuh2FdBuoeZnc1TcWi/KXVx7UkB3yG2JfSliNcoteaPCsaaUMkLxj0f6VhWdqEvuqMeE75Yp4Nsh3C7y/auufFfN3tMDwoHhOE4JB/i/eT7T2F8tlHAo7y8AL2XTatRvG/C4QuikcAmomepxWun700tsrCU0VhvO441QvweFM/huocNVrP+6PgXaCh5PhAAAAABJRU5ErkJggg=="
const IMAGE_PLAY = new Image();
IMAGE_PLAY.src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABkAAAAgCAYAAADnnNMGAAAACXBIWXMAAACbAAAAmwEPcaP1AAAAGXRFWHRTb2Z0d2FyZQB3d3cuaW5rc2NhcGUub3Jnm+48GgAAAj9JREFUSIm11rtrFVkcB/DPmdwbbx7GRK+IQbbQVQwIK0RIYSciguBa6RaKCxa+UCu1EDvZXaxstBAr8Q/QwifIrgirLrusq2ChyD6qKCJ41U2MuXMsJiM+gibm5FtNcc7vM2f48ZsDD3ASVdOYiCi4jgXTh8yrRi2hKXiKddODrOyMdtSj2ZUmchxDLRWQvX2aV2V7PbO8PWCf4HcsS4tAa+DbWWzsYUbWJ/gDBz9aNyWkTF+NnfXMV61V/IQr6E2LQFcLW+cEa7vIrBLcxfq0CAQMdLCtHvRUunEWx9GWDinTWy0+30BHwC7BbfSnRaASWNvFph5q2deCmziElnRImaU1ds/NLKlVcERwA4vTItCR8V0PG7qphH7BHexLi5T5po1dczMLWlsVU+IS5qdFoLuF7+dkVs8ks2bsVO+1+tSRssrKzrLVZ+McTqMzHVKmt8qOemZFO2wR/IWBtAhUA+tm0d9OtBAXKsmRR6+52Ij+HQmCh6Ld6ZDhnF9e8NvLiGEcFf2IV1NHIu4McbmRG8oDzuAABsslU0P+GeHis9zj0Wxsnu3Brx8u+zKk0eTq8+IEwRMcFp1S/Lo/yuSQ0citl1x7kRuNOU6IDqPxqW0TR+4Pc6GRe9bM8DP24t5Etn4eGRxryf9GguBvxSA8P+GX+yQylHNt/JacDDA+kuPP/7n6vGkozxQtuR+PJlt8fGT8lrzxpcXfTbSsLeqrFXfizCA2K64RyVJeuEfwg7HxnDbBA8VVZ1H64kXeAM9RoeriawdYAAAAAElFTkSuQmCC"
const IMAGE_PAUSE = new Image();
IMAGE_PAUSE.src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABIAAAAbCAYAAABxwd+fAAAACXBIWXMAAADGAAAAxgGwdJvFAAAAGXRFWHRTb2Z0d2FyZQB3d3cuaW5rc2NhcGUub3Jnm+48GgAAALxJREFUOI3t1TGKwzAQQNE/JoXQGQTGpbFP5HJhXfsoKo0XUupCSWpj0BmMKk8KJ2QXglnYcvXLQfNQNzKO40VEWl5tIvLZ9/2ZN03T9KGqX0DxnKnq9SQi7bquLMuCMYaqqgqgeYc8aoBinmdSSpRlibW2LQBijHjvCSEc7P8shID3nhgjfP/eX8tQhjKUoQz9Q+gE4JxjGAaMMb9e7LqOlBLOuR1S1au1tq3r+vlmA24Hxg3YHocU2C/tHUseO6D31KjVAAAAAElFTkSuQmCC"

Binary file not shown.

After

Width:  |  Height:  |  Size: 303 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 690 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 718 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 487 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 487 B

Loading…
Cancel
Save