@quantum_jim/

QuantumProgrammingTutorial

Python

No description

fork
loading
Files
  • main.py
  • Engine.py
  • Levels.py
  • License

This Plugin Crashed!

Error: Error: must not create an existing file {"type":"CREATE_FILE","wid":"0.47053716702190473","path":"main.py","file":{"path":"main.py","content":{"asEncoding":{"base64":"IyAgQ3JlYXRlZCBieSBKYW1lcyBXb290dG9uCiMgIENvcHlyaWdodCDCqSAyMDE3IFVuaXZlcnNpdHkgb2YgQmFzZWwuIEFsbCByaWdodHMgcmVzZXJ2ZWQuCgppbXBvcnQgbWF0aAoKZGVmIENvbG91cmVkU3RyaW5nIChtZXNzYWdlLGNvbG91cikgOgogICMgIERFU0NSSVBUSU9OOgogICMgICAgICBQcmludHMgaW4gYSBjb2xvdXIgc3BlY2lmaWVkIGJ5IHRoZSBjb2xvdXIgaW4gWyJyIiwiYiIsInAiXSBhbmQgdGhlbiBzZXRzIHdoYXQgZm9sbG93cyBiYWNrIHRvIHdoaXRlCgogICMgZmlyc3QgdGhlIGNvbG91cgogIGNvbG91cmVkX21lc3NhZ2UgPSAiIgogIGlmIGNvbG91cj09InIiOiAjIHJlZAogICAgY29sb3VyZWRfbWVzc2FnZSArPSAiXHgxYlsxOzMxbSIKICBlbGlmIGNvbG91cj09ImciOiAjIGdyZWVuCiAgICBjb2xvdXJlZF9tZXNzYWdlICs9ICJceDFiWzE7MzJtIgogIGVsaWYgY29sb3VyPT0iYiI6ICMgYmx1ZQogICAgY29sb3VyZWRfbWVzc2FnZSArPSAiXHgxYlsxOzM0bSIgCiAgZWxpZiBjb2xvdXI9PSJwIjogIyBwdXJwbGUKICAgIGNvbG91cmVkX21lc3NhZ2UgKz0gIlx4MWJbMTszNW0iCiAgZWxzZTogIyBibGFjayAod2hpY2ggc2hvdWxkIGFjdHVhbGx5IGJlIHRoZSBkZWZhdWx0IHRleHQgY29sb3VyKQogICAgY29sb3VyZWRfbWVzc2FnZSArPSAiXHgxYlswbSIKICAKICAjIHRoZW4gdGhlIG1lc3NhZ2UKICBjb2xvdXJlZF9tZXNzYWdlICs9IG1lc3NhZ2UKCiAgIyBhbmQgYmFjayB0byBibGFjawogIGNvbG91cmVkX21lc3NhZ2UgKz0gIlx4MWJbMG0iCiAgCiAgcmV0dXJuIGNvbG91cmVkX21lc3NhZ2UKCmRlZiAgRXhwZWN0MlByb2IgKCBleHBlY3QgKSA6CiAgIyAgREVTQ1JJUFRJT046CiAgIyAgICAgIENvbnZlcnRzIGV4cGVjdGF0aW9uIHZhbHVlIHRvIGEgcHJvYmFiaWxpdHkgb2YgZ2V0dGluZyB0aGUgb3V0Y29tZSAxLgogIHJldHVybiAoMS1leHBlY3QpLzIKICAKZGVmIEV4cGVjdDJQb2xhciAoIGJveGVzICkgOgogICMgIERFU0NSSVBUSU9OOgogICMgICAgICBUYWtlcyB0aGUgY29udGVudHMgb2YgYW4gWCBhbmQgWiBib3ggYW5kIHR1cm5zIGl0IGludG8gcG9sYXIgY29vcmRpbmF0ZXMgZm9yIHRoZSBCbG9jaCBjaXJjbGUuCiAgIyAgSU5QVVQ6CiAgIyAgICAgIHtTdHJpbmc6IEZsb2F0fSAgICBib3hlcyAgICAgICBTaG91bGQgaGF2ZSBlbnRyaWVzIGZvciAiWCIgYW5kICJaIiwgd2hpY2ggc2VydmUgYXMgdGhlIGhvcml6b250YWwgYW5kIHZlcnRpY2FsIGJveGVzIHJlc3BlY3RpdmVseS4KICAjICBPVVRQVVQ6CiAgIyAgICAgIFtGbG9hdF0gICAgICAgICAgICBbIGRlZ3JlZXMsIHJhZGl1cyBdICAgICBkZWdyZWVzIGlzIGJldHdlZW4gMCBhbmQgMS4gSXQgaXMgdGhlIGFuZ2xlIGNsb2Nrd2lzZSBmcm9tIHRoZSB0b3AgYXMgYSBmcmFjdGlvbiBvZiAyKlBpLiBSYWRpdXMgaXMgaG93IGZhciBvdXQgdGhlIHBvaW50IGlzLiBXaWxsIGJlIDEgZm9yIHB1cmUgc3RhdGVzIGFuZCAwIGZvciBtYXhpbWFsbHkgbWl4ZWQuCiAKICByYWRpdXMgPSBtYXRoLnNxcnQoIGJveGVzWyJYIl0qKjIgKyBib3hlc1siWiJdKioyKQogIGRlZ3JlZXMgPSAwICMgZGVmYXVsdCB2YWx1ZSBvZiAwCiAgaWYgcmFkaXVzPjAuMDoKICAgIGRlZ3JlZXMgPSBtYXRoLmFjb3MoIC1ib3hlc1siWiJdIC8gcmFkaXVzICkgLyAoMiptYXRoLnBpKQogICAgaWYgYm94ZXNbIlgiXT49MC4wOgogICAgICBkZWdyZWVzID0gMSAtIGRlZ3JlZXMKCiAgICByZXR1cm4gWyBkZWdyZWVzLCByYWRpdXMgXQoKZGVmIFBvbGFyMkV4cGVjdCAoIHBvbGFyX2Nvb3JkcyApIDoKICAjICBERVNDUklQVElPTjoKICAjICAgICAgQXMgQm94ZXMyUG9sYXIsIGJ1dCB3aXRoIGlucHV0cyBhbmQgb3V0cHV0cyByZXZlcnNlZAogIGJveGVzID0ge30KICBib3hlc1siWCJdID0gLXBvbGFyX2Nvb3Jkc1sxXSAqIHNpbiggMiptYXRoLnBpKnBvbGFyX2Nvb3Jkc1swXSkKICBib3hlc1siWiJdID0gLXBvbGFyX2Nvb3Jkc1sxXSAqIGNvcyggMiptYXRoLnBpKnBvbGFyX2Nvb3Jkc1swXSkKICByZXR1cm4gYm94ZXMKICAgIApkZWYgRXhjaGFuZ2VCb3hlcyAoIHN0YXRlLCBib3gxLCBib3gyICkgOgogICMgIERFU0NSSVBUSU9OOgogICMgICAgICBHaXZlbiBhIHN0YXRlIGFuZCB0d28gb2YgaXRzIGJveGVzLCB0aGUgdmFsdWVzIGZvciB0aGVzZSBib3hlcyBhcmUgZXhjaGFuZ2VkCiAgb3V0cHV0X3N0YXRlID0gc3RhdGUKICB0ZW1wID0gb3V0cHV0X3N0YXRlW2JveDFdCiAgb3V0cHV0X3N0YXRlW2JveDFdID0gb3V0cHV0X3N0YXRlW2JveDJdCiAgb3V0cHV0X3N0YXRlW2JveDJdID0gdGVtcAogIHJldHVybiBvdXRwdXRfc3RhdGUKICAgIApkZWYgQXBwbHlHYXRlICggc3RhdGUsIGdhdGUsIHF1Yml0ICkgOgogICMgIERFU0NSSVBUSU9OOgogICMgICAgICBUcmFuc2Zvcm1zIHRoZSBnaXZlbiBzdGF0ZSBhY2NvcmRpbmcgdG8gdGhlIGdpdmVuIGdhdGUuCiAgIyAgSU5QVVQ6CiAgIyAgICAgIHtTdHJpbmc6IEZsb2F0fSAgICBzdGF0ZSAgICAgICBGdWxsIHR3byBxdWJpdCBzdGF0ZS4gTmVlZHMgZW50cmllcyBmb3IgWEksIFpJLCBJWiwgSVgsIFhYLCBYWiwgWlgsIFpaIGFuZCBZWQogICMgICAgICBTdHJpbmcgICAgICAgICAgICAgIGdhdGUgICAgICAgIFFJU0tpdCBzdHlsZSBzdHIgdG8gc3BlY2lmeSBhIGdhdGUgKGNhbiBiZSB4LCB6LCBoLCBxLCBxZGcsIG9yIGN6KQogICMgICAgICBJbnQgICAgICAgICAgICAgICAgIHF1Yml0ICAgICAgIFF1Yml0IG9uIHdoaWNoIHNpbmdsZSBxdWJpdCBnYXRlIGlzIGFwcGxpZWQuIFVudXNlZCBmb3IgQ1ouCiAgIyAgT1VUUFVUOgogICMgICAgICB7U3RyaW5nOiBGbG9hdH0gICAgc3RhdGUgICAgICAgVHJhbnNmb3JtZWQgdmVyc2lvbiBvZiBpbnB1dCBzdGF0ZS4KICAKICAjIFdlIGJlZ2luIGNvbnN0cnVjdGluZyB0aGUgb3V0cHV0IHN0YXRlIGJ5IGNvcHlpbmcgdGhlIGlucHV0IHN0YXRlLgogIG91dHB1dF9zdGF0ZSA9IHN0YXRlCiAgCiAgIyBTaW5nbGUgcXViaXQgZ2F0ZXMgcmVxdWlyZSBzcGVjaWFsIHRyZWF0bWVudCwgc28gd2UgZGVhbCB3aXRoIHRoZXNlIHNlcGFyYXRlbHkuCiAgaWYgZ2F0ZSBpbiBbIngiLCJ6IiwiaCIsInEiLCJxZGciXSA6CiAgICAjIFNpbmdsZSBxdWJpdCBnYXRlcyBhY3Qgb24gcGFpcnMgb2YgYm94ZXMuIFRoZXNlIGFyZSB0aGUgcGFpcnMgdGhhdCBmb3JtIEJsb2NoIGNpcmNsZXMuCiAgICAjIEZvciBxdWJpdCAwLCB0aGVzZSBwYWlycyBhcmUgIChYSSwgWkkpLCAoWFgsWlgpIGFuZCAoWFosWlopLgogICAgIyBGb3IgcXViaXQgMiB0aGV5IGFyZSAoSVgsIElaKSwgKFhYLFhaKSBhbmQgKFpYLFpaKS4KICAgICMgSGVyZSB3ZSBsb29wIG92ZXIgYW5kIGNvbnN0cnVjdCB0aGUgdGhyZWUgcGFpcnMsIHdoaWNoIGluIGVhY2ggY2FzZSB3aWxsIGJlIChwWzBdLHBbMV0pLgogICAgZm9yIHJjIGluIFsiSSIsIlgiLCJaIl0gOgogICAgICAgICAgICAKICAgICAgYm94X25hbWUgPSB7IlgiOnJjLCJaIjpyY30KICAgICAgZm9yIHAgaW4gWyJYIiwiWiJdIDoKICAgICAgICBpZiBxdWJpdD09IjAiIDoKICAgICAgICAgIGJveF9uYW1lW3BdID0gcCArIGJveF9uYW1lW3BdCiAgICAgICAgZWxzZSA6CiAgICAgICAgICBib3hfbmFtZVtwXSA9IGJveF9uYW1lW3BdICsgcAogICAgICAgICAgCiAgICAgIAogICAgICAKICAgICAgIyBXaGF0IHdlIGRvIHRvIHRoZSBwYWlycyBkZXBlbmRzIG9uIHRoZSBnYXRlIHdlIGFwcGx5LgogICAgICBpZiBnYXRlPT0ieCI6ICMgaW52ZXJ0IFogYm94IGFuZCBpbnZlcnQgWVkKICAgICAgICBvdXRwdXRfc3RhdGVbYm94X25hbWVbIloiXV0gPSAtb3V0cHV0X3N0YXRlW2JveF9uYW1lWyJaIl1dCiAgICAgICAgb3V0cHV0X3N0YXRlWyJZWSJdID0gLW91dHB1dF9zdGF0ZVsiWVkiXQogICAgICBlbGlmIGdhdGU9PSJ6IiA6IyBpbnZlcnQgWCBib3ggYW5kIGludmVydCBZWQogICAgICAgIG91dHB1dF9zdGF0ZVtib3hfbmFtZVsiWCJdXSA9IC1vdXRwdXRfc3RhdGVbYm94X25hbWVbIlgiXV0KICAgICAgICBvdXRwdXRfc3RhdGVbIllZIl0gPSAtb3V0cHV0X3N0YXRlWyJZWSJdCiAgICAgIGVsaWYgZ2F0ZT09ImgiIDogIyBleGNoYW5nZSBYIGFuZCBaIGJveGVzIGFuZCBpbnZlcnQgWVkKICAgICAgICBvdXRwdXRfc3RhdGUgPSBFeGNoYW5nZUJveGVzKCBvdXRwdXRfc3RhdGUsIGJveF9uYW1lWyJYIl0sIGJveF9uYW1lWyJaIl0pCiAgICAgICAgb3V0cHV0X3N0YXRlWyJZWSJdID0gLW91dHB1dF9zdGF0ZVsiWVkiXQogICAgICBlbGlmIGdhdGUgaW4gWyJxIiwicWRnIl0gOgogICAgICAgIHBvbGFyX2Nvb3JkcyA9IEV4cGVjdDJQb2xhciggeyAiWCI6b3V0cHV0X3N0YXRlW2JveF9uYW1lWyJYIl1dLCAiWiI6b3V0cHV0X3N0YXRlW2JveF9uYW1lWyJaIl1dIH0gKSAjIGNvbnZlcnQgdG8gcG9sYXIgY29vcmRzCiAgICAgICAgaWYgZ2F0ZT09InEiIDogIyBjaGFuZ2UgYW5nbGUgYWNjb3JkaW5nIHRvIHRoZSByb3RhdGlvbgogICAgICAgICAgcG9sYXJfY29vcmRzWzBdICs9IDEvOAogICAgICAgIGVsc2UgOgogICAgICAgICAgcG9sYXJfY29vcmRzWzBdIC09IDEvOAogICAgICAgICAgCiAgICAgICAgIyBjb252ZXJ0IGJhY2sgdG8gYm94ZXMKICAgICAgICBvdXRwdXRfYm94ZXMgPSBQb2xhcjJFeHBlY3QocG9sYXJfY29vcmRzKQogICAgICAgIGZvciBwIGluIFsiWCIsIloiXSA6CiAgICAgICAgICBvdXRwdXRfc3RhdGVbYm94X25hbWVbcF1dID0gb3V0cHV0X2JveGVzW3BdCiAgICAgIGVsc2UgOgogICAgICAgIHByaW50KCJFcnJvcjogVW5rbm93biBzaW5nbGUgcXViaXQgZ2F0ZSIpCgogICMgTm93IGZvciB0aGUgdHdvIHF1Yml0IGdhdGVzCiAgZWxpZiBnYXRlPT0iY3oiIDoKICAgICMgZXhjaGFuZ2UgY29udGVudHMgb2YgWEkgYW5kIFhaCiAgICBvdXRwdXRfc3RhdGUgPSBFeGNoYW5nZUJveGVzKCBvdXRwdXRfc3RhdGUsICJYSSIsICJYWiIpCiAgICAjIGV4Y2hhbmdlIGNvbnRlbnRzIG9mIElYIGFuZCBaWAogICAgb3V0cHV0X3N0YXRlID0gRXhjaGFuZ2VCb3hlcyggb3V0cHV0X3N0YXRlLCAiSVgiLCAiWlgiKQogICAgIyBleGNoYW5nZSBjb250ZW50cyBvZiBYWCBhbmQgWVkKICAgIG91dHB1dF9zdGF0ZSA9IEV4Y2hhbmdlQm94ZXMoIG91dHB1dF9zdGF0ZSwgIlhYIiwgIllZIikKICBlbGlmIGdhdGU9PSJjeCIgOgogICAgaWYgcXViaXQ9PSIxIiA6CiAgICAgICMgZXhjaGFuZ2UgY29udGVudHMgb2YgWEkgYW5kIFhYCiAgICAgIG91dHB1dF9zdGF0ZSA9IEV4Y2hhbmdlQm94ZXMoIG91dHB1dF9zdGF0ZSwgIlhJIiwgIlhYIikKICAgICAgIyBleGNoYW5nZSBjb250ZW50cyBvZiBJWiBhbmQgWloKICAgICAgb3V0cHV0X3N0YXRlID0gRXhjaGFuZ2VCb3hlcyggb3V0cHV0X3N0YXRlLCAiSVoiLCAiWloiKQogICAgICAjIGV4Y2hhbmdlIGNvbnRlbnRzIG9mIFhaIGFuZCBZWQogICAgICBvdXRwdXRfc3RhdGUgPSBFeGNoYW5nZUJveGVzKCBvdXRwdXRfc3RhdGUsICJYWiIsICJZWSIpCiAgICAgICMgaW52ZXJ0IFhaCiAgICAgIG91dHB1dF9zdGF0ZVsiWFoiXSA9IC1vdXRwdXRfc3RhdGVbIlhaIl0KICAgIGVsaWYgcXViaXQ9PSIwIiA6CiAgICAgICMgZXhjaGFuZ2UgY29udGVudHMgb2YgWkkgYW5kIFpaCiAgICAgIG91dHB1dF9zdGF0ZSA9IEV4Y2hhbmdlQm94ZXMoIG91dHB1dF9zdGF0ZSwgIlpJIiwgIlpaIikKICAgICAgIyBleGNoYW5nZSBjb250ZW50cyBvZiBJWCBhbmQgWFgKICAgICAgb3V0cHV0X3N0YXRlID0gRXhjaGFuZ2VCb3hlcyggb3V0cHV0X3N0YXRlLCAiSVgiLCAiWFgiKQogICAgICAjIGV4Y2hhbmdlIGNvbnRlbnRzIG9mIFpYIGFuZCBZWQogICAgICBvdXRwdXRfc3RhdGUgPSBFeGNoYW5nZUJveGVzKCBvdXRwdXRfc3RhdGUsICJaWCIsICJZWSIpCiAgICAgICMgaW52ZXJ0IFpYCiAgICAgIG91dHB1dF9zdGF0ZVsiWlgiXSA9IC1vdXRwdXRfc3RhdGVbIlpYIl0KICAgICAgb3V0cHV0X3N0YXRlWyJZWSJdID0gLW91dHB1dF9zdGF0ZVsiWVkiXSAjIGludmVydCBZWQogICAgZWxzZSA6CiAgICAgIHByaW50KCJFcnJvcjogVW5rbm93biBnYXRlIikKICAKICAKICByZXR1cm4gb3V0cHV0X3N0YXRlCiAgCmRlZiBNYWtlSW5pdGlhbCAoIHRhcmdldF9zdGF0ZSwgaW52ZXJzZV9zb2x1dGlvbiApIDoKICAjICBERVNDUklQVElPTjoKICAjICAgICAgQ29uc3RydWN0cyBhbiBpbml0aWFsIHN0YXRlIHN1Y2ggdGhhdCB0aGUgdGFyZ2V0IHN0YXRlIGFuZCBzb2x1dGlvbiBhcmUgYXMgc3BlY2lmaWVkIGJ5IHRoZSBpbnB1dAogICMgICAgICBOb3RlIHRoYXQgdGhlIGludmVyc2Ugb2YgdGhlIGRlc2lyZWQgc29sdXRpb24gbXVzdCBiZSBzdXBwbGllZCBoZXJlCiAgIyAgICAgIFB1dCBzaW1wbHksIHRoaXMgbWVhbnMgdGhhdCB0aGUgZmlyc3QgZ2F0ZSBzaG91bGQgYmUgb24gdGhlIHJpZ2h0LCBhbmQgdGhlIHN1YnN0aXRpb24gcSA8LT4gcWRnIHNob3VsZCBiZSB1c2VkCiAgICAKICBzdGF0ZSA9IHRhcmdldF9zdGF0ZQogIGZvciBnYXRlIGluIGludmVyc2Vfc29sdXRpb24gOgogICAgICBzdGF0ZSA9IEFwcGx5R2F0ZSggc3RhdGUsIGdhdGVbMF0sIGdhdGVbMV0gKQogIHJldHVybiBzdGF0ZQogIApkZWYgTWFrZUNlbGwgKCBjZWxsX3N0YXRlICkgOgogICMgIERFU0NSSVBUSU9OOgogICMgICAgICBQcmludHMgYSBzaW5nbGUgYm94IG9yIEJsb2NoIGNpcmNsZSwgZGVwZW5kaW5nIG9uIHRoZSBpbnB1dCBzdGF0ZS4KICAjICBJTlBVVDoKICAjICAgICAge1N0cmluZzogRmxvYXR9ICAgIGNlbGxfc3RhdGUgIFdpdGgga2V5ICJYIiwgdmFsdWUgaXMgdGhlIGV4cGVjdGF0aW9uIHZhbHVlIGZvciBob3Jpem9udGFsIHJlZCBib3guCiAgIyAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgU2ltaWxhcmx5IGZvciAiWiIgYW5kIHRoZSB2ZXJ0aWNhbCBibHVlIGJveCwgYW5kICJZIiBmb3IgYSBkaWFnb25hbCBwdXJwbGUgYm94LgogICMgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIE5vdGUgdGhhdCBhIGNlbGwgdGhhdCB1c2VzICJZIiB3aWxsIGNvcnJlc3BvbmQgdG8gWFogb3IgWlogYm94ZXMuIE5vdCBhIFkgYm94LgogICMgIE9VVFBVVDoKICAjICAgICAgW1N0cmluZ10gICAgICAgICAgICBsaW5lcyAgICAgICBMaXN0IG9mIDEyIGxpbmVzLCB3aGljaCB3aGVuIHByaW50ZWQgc2VxdWVudGlhbGx5IHdpbGwgZGlzcGxheSB0aGUgY2VsbC4KICAjICBQUk9DRVNTOgogICMgICAgICBXaGVuIGEgc2luZ2xlIGtleSBpcyBzdXBwbGllZCwgdGhlIGNvcnJlc3BvbmRpbmcgYm94IGlzIHByaW50ZWQuCiAgIyAgICAgIFdoZW4gYm90aCAiWCIgYW5kICJaIiBhcmUgc3VwcGxpZWQsIHRoZSBib3hlcyBhcmUgY29tYmluZWQgaW50byBhIEJsb2NoIGNpcmNsZS4KICAjICAgICAgSW4gYWxsIGNhc2VzLCB0aGUgbGV2ZWwgb24gdGhlIGJveCBpcyBmaXJzdCBjb252ZXJ0ZWQgZnJvbSB0aGUgZXhwZWN0YXRpb24gdmFsdWUgdG8gdGhlIHByb2JhYmlsaXR5LgogIAogIHJlc28gPSB7IlgiOjE3LCAiWiI6OSwgIlkiOjEzfSAjIG51bWJlciBvZiBjaGFyYWN0ZXJzIHVzZWQgZm9yIGVhY2ggdHlwZSBvZiBib3ggKGluY2x1ZGluZyBjZW50ZXIpCgogIGJvdHRvbSA9ICLilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIAiICMgYm90dG9tIGJvcmRlcgogIHJpZ2h0ID0gInwiICMgcmlnaHQgYm9yZGVyCgogICMgVGhlIDggcG9pbnRzIGFyb3VuZCB0aGUgY2lyY2xlIGFuZCBvbmUgaW4gdGhlIG1pZGRsZS4gRGVmYXVsdCB0byBhIGRvdAogIGMgPSBbXQogIGMuYXBwZW5kKCLLmSIpCiAgYy5hcHBlbmQoIi4iKQogIGMuYXBwZW5kKCLCtyIpCiAgYy5hcHBlbmQoIsuZIikKICBjLmFwcGVuZCgiLiIpCiAgYy5hcHBlbmQoIsuZIikKICBjLmFwcGVuZCgiwrciKQogIGMuYXBwZW5kKCIuIikKICBjLmFwcGVuZCgiICIpCiAgCiAgIyBXaGVuIGEgQmxvY2ggc3BoZXJlIGlzIGRpc3BsYXllZCwgdGhlIHBvaW50IGNvcnJlc3BvbmRpbmcgdG8gdGhlIHN0YXRlIGlzIGRlbm90ZWQgYnkgIioiCiAgIyBUaGlzIGlzIGRpc3BsYXllZCBvbmx5IGZvciBwcmV0dHkgbWl4ZWQgc3RhdGVzIChyYWRpdXMgPDAuMjUpIGFuZCBwcmV0dHkgcHVyZSBvbmVzIChyYWRpdXM+MC43NSkKICBpZiAoICJYIiBpbiBjZWxsX3N0YXRlLmtleXMoKSBhbmQgIloiIGluIGNlbGxfc3RhdGUua2V5cygpICkgOiAjIGJvdGggWCAgYW5kIFogYm94ZXMgbmVlZCB0byBiZSBwcmVzZW50IGluIHRoZSBjZWxsCiAgICBpZiAoIEV4cGVjdDJQb2xhciggY2VsbF9zdGF0ZSApWzFdPDAuMjUgKSA6ICMgaWYgc3RhdGUgaXMgcHJldHR5IG1peGVkLCBwb2ludCBpcyBzaG93biBpbiB0aGUgY2VudGVyCiAgICAgIGNbOF0gPSAiKiIKICAgIGVsaWYgRXhwZWN0MlBvbGFyKCBjZWxsX3N0YXRlIClbMV0+MC43NSA6ICMgaWYgc3RhdGUgaXMgcHJldHR5IHB1cmUsIGl0IGlzIG9uZSBvZiB0aGUgOCBhcm91bmQgdGhlIGVkZ2UKICAgICAgcG9pbnQgPSAwCiAgICAgIGRlZ3JlZSA9IEV4cGVjdDJQb2xhciggY2VsbF9zdGF0ZSApWzBdCiAgICAgIGZvciBlaWdodGggaW4gcmFuZ2UoMSw4KSA6CiAgICAgICAgaWYgZGVncmVlPihmbG9hdChlaWdodGgpLzggLSAxLjAvMTYpIGFuZCBkZWdyZWU8PShmbG9hdChlaWdodGgpLzggKyAxLjAvMTYgKSA6CiAgICAgICAgICBwb2ludCA9IGVpZ2h0aAogICAgICBpZiBwb2ludCBpbiBbMSw0LDddIDoKICAgICAgICBjWyBwb2ludCBdID0gIuKBjiIKICAgICAgZWxzZSA6CiAgICAgICAgY1sgcG9pbnQgXSA9ICIqIgoKCiAgIyBTdHJpbmdzIGZvciB0aGUgdGhyZWUgYm94ZXMuIEJsYW5rIGlmIHVudXNlZCwgYnV0IGZpbGxlZCB3aXRoIOKWiCBhbmQg4paRIGlmIHVzZWQgdG8gcmVwcmVzZW50IGhvdyAnZmlsbGVkJyB0aGV5IGFyZS4KICBiID0geyJYIjpbXSwgIloiOltdLCAiWSI6W10gfQogIGZvciBib3ggaW4gWyAiWCIsICJaIiwgIlkiIF0gOgogICAgdGhpc19iID0gW10KICAgIGlmIGJveCBub3QgaW4gY2VsbF9zdGF0ZS5rZXlzKCkgOgogICAgICBmb3IgXyBpbiByYW5nZSgxLHJlc29bYm94XSsxKSA6CiAgICAgICAgdGhpc19iLmFwcGVuZCgiICIpCiAgICBlbHNlIDoKICAgICAgcHJvYiA9IEV4cGVjdDJQcm9iKCBjZWxsX3N0YXRlW2JveF0gKSAjIGNvbnZlcnQgZnJvbSBleHBlY3RhdGlvbiB2YWx1ZSB0byBwcm9iIG9mIGEgMSBvdXRjb21lCiAgICAgIGZpbGwgPSBpbnQoIGZsb2F0KHJlc29bYm94XSkgKiBwcm9iICkKICAgICAgCiAgICAgIGlmIChwcm9iPjAuNSBhbmQgZmlsbCAhPSByZXNvW2JveF0pIDogIyBpZiBvdmVyIGhhbGYgZmlsbGVkLCBidXQgbm90IGNvbXBsZXRlbHkgZmlsbGVkLCByb3VuZCB1cCAoZm9yIGNsZWFyIHZpc3VhbHMpCiAgICAgICAgICBmaWxsICs9IDEKICAgICAgZm9yIF8gaW4gcmFuZ2UoZmlsbCkgOgogICAgICAgIGlmIGJveCA9PSAiWCIgOgogICAgICAgICAgdGhpc19iLmFwcGVuZCggQ29sb3VyZWRTdHJpbmcoICLilogiICwgInIiICkgKQogICAgICAgIGVsaWYgYm94ID09ICJaIiA6CiAgICAgICAgICB0aGlzX2IuYXBwZW5kKCBDb2xvdXJlZFN0cmluZyggIuKWiCIgLCAiYiIgKSApCiAgICAgICAgZWxpZiBib3ggPT0gIlkiIDoKICAgICAgICAgIHRoaXNfYi5hcHBlbmQoIENvbG91cmVkU3RyaW5nKCAi4paIIiAsICJwIiApICkKCiAgICAgIGZvciBfIGluIHJhbmdlKGZpbGwscmVzb1tib3hdKSA6CiAgICAgICAgaWYgYm94ID09ICJYIiA6CiAgICAgICAgICB0aGlzX2IuYXBwZW5kKCBDb2xvdXJlZFN0cmluZyggIuKWkSIgLCAiciIgKSApCiAgICAgICAgZWxpZiBib3ggPT0gIloiIDoKICAgICAgICAgIHRoaXNfYi5hcHBlbmQoIENvbG91cmVkU3RyaW5nKCAi4paRIiAsICJiIiApICkKICAgICAgICBlbGlmIGJveCA9PSAiWSIgOgogICAgICAgICAgdGhpc19iLmFwcGVuZCggQ29sb3VyZWRTdHJpbmcoICLilpEiICwgInAiICkgKQogICAgYltib3hdID0gdGhpc19iCiAgCiAgIyBjZW50ZXIgaXMgWCB3aXRoIHRoZSBjb2xvdXIgb2YgdGhlIGNlbGwsIHVubGVzcyB0aGUgY2VsbCBpcyBlbXB0eQogIGlmICJZIiBpbiBjZWxsX3N0YXRlLmtleXMoKSA6CiAgICBjWzhdID0gQ29sb3VyZWRTdHJpbmcoIGJbIlkiXVtpbnQocmVzb1siWSJdLzIpXSwgInAiICkKICBlbGlmICJYIiBpbiBjZWxsX3N0YXRlLmtleXMoKSA6CiAgICBjWzhdID0gQ29sb3VyZWRTdHJpbmcoIGJbIlgiXVtpbnQocmVzb1siWCJdLzIpXSwgInIiICkKICBlbGlmICJaIiBpbiBjZWxsX3N0YXRlLmtleXMoKSA6CiAgICBjWzhdID0gQ29sb3VyZWRTdHJpbmcoIGJbIloiXVtpbnQocmVzb1siWiJdLzIpXSwgImIiICkKICAKICBiWyJYIl1baW50KHJlc29bIlgiXS8yKV0gPSBjWzhdICMgVGhlIGNlbnRlciB3aWxsIGJlIHRoZSBuaW50aCBlbGVtZW50IG9mIGMgaW5zdGVhZAoKICAjIERlY2xhcmUgYW5kIGNvbnN0cnVjdCB0aGUgbGluZXMuCiAgbGluZXMgPSBbXQogIGlmIGNlbGxfc3RhdGU9PVtdIDoKICAgIGZvciBfIGluIHJhbmdlKDExKSA6CiAgICAgIGxpbmVzLmFwcGVuZCggIiAgICAgICAgICAgICAgICAgICAgICAgIityaWdodCApCiAgZWxzZSA6CiAgICBsaW5lcy5hcHBlbmQoICIgICAgICAuwrcgICIrY1swXSsiICDCty4gICAgICAgICIrcmlnaHQgKQogICAgbGluZXMuYXBwZW5kKCAiICAgIitjWzddKyLLmSAgICAgIitiWyJaIl1bOF0rIiAgICAgy5kiK2NbMV0rIiAgICAgIityaWdodCApCiAgICBsaW5lcy5hcHBlbmQoICIgIMK3ICAgICAgICIrYlsiWiJdWzddKyIgICAgIitiWyJZIl1bMTFdK2JbIlkiXVsxMl0rIiDCtyAgICAiK3JpZ2h0ICkKICAgIGxpbmVzLmFwcGVuZCggIiDCtyAgICAgICAgIitiWyJaIl1bNl0rIiAgIitiWyJZIl1bOV0rYlsiWSJdWzEwXSsiICAgIMK3ICAgIityaWdodCApCiAgICBsaW5lcy5hcHBlbmQoICIgICAgICAgICAgIitiWyJaIl1bNV0rIiIrYlsiWSJdWzddK2JbIlkiXVs4XSsiICAgICAgICAgICIrcmlnaHQgKQogICAgbGluZXMuYXBwZW5kKCAiIitjWzZdKyIgIisiIi5qb2luKGJbIlgiXSkrIiAiK2NbMl0rIiAgIityaWdodCApCiAgICBsaW5lcy5hcHBlbmQoICIgICAgICAgICIrYlsiWSJdWzRdK2JbIlkiXVs1XSsiIitiWyJaIl1bM10rIiAgICAgICAgICAgICIrcmlnaHQgKQogICAgbGluZXMuYXBwZW5kKCAiIMuZICAgICIrYlsiWSJdWzJdK2JbIlkiXVszXSsiICAiK2JbIloiXVsyXSsiICAgICAgICDLmSAgICIrcmlnaHQgKQogICAgbGluZXMuYXBwZW5kKCAiICDCtyAiK2JbIlkiXVswXStiWyJZIl1bMV0rIiAgICAiK2JbIloiXVsxXSsiICAgICAgIMK3ICAgICIrcmlnaHQgKQogICAgbGluZXMuYXBwZW5kKCAiICAgIitjWzVdKyIuICAgICAiK2JbIloiXVswXSsiICAgICAuIitjWzNdKyIgICAgICIrcmlnaHQgKQogICAgbGluZXMuYXBwZW5kKCAiICAgICAgy5nCtyAgIitjWzRdKyIgIMK3y5kgICAgICAgICIrcmlnaHQgKQogIGxpbmVzLmFwcGVuZCggYm90dG9tICsgcmlnaHQgKQogIAogIHJldHVybiBsaW5lcwoKZGVmIE1ha2VHcmlkICggc3RhdGUsIHNob3duX3F1Yml0LCBhY3RpdmVfcXViaXQsIGJsb2NoICkgOgoKICAjICBERVNDUklQVElPTjoKICAjICAgICAgVGhlIGlucHV0cyBkZXNjcmliZSB3aGF0IHRoZSBncmlkIGlzIGRvaW5nLiBUaGlzIGZ1bmN0aW9uIHB1dHMgYWxsIHRoYXQgaW5mb3JtYXRpb24gdG9nZXRoZXIgdG8gYWN0dWFsbHkgbWFrZSB0aGUgZ3JpZC4KICAjICBJTlBVVDoKICAjICAgICAge1N0cmluZzogRmxvYXR9ICAgIHN0YXRlICAgRnVsbCB0d28gcXViaXQgc3RhdGUuIE5lZWRzIGVudHJpZXMgZm9yIFhJLCBaSSwgSVosIElYLCBYWCwgWFosIFpYLCBaWiBhbmQgWVkKICAjICAgICAgSW50ICAgICBzaG93bl9xdWJpdCAgICAgSWYgdGhpcyBpcyAwIG9yIDEsIG9ubHkgdGhlIHR3byBib3hlcyBvZiB0aGF0IHF1Yml0IGFyZSBzaG93bi4gT3RoZXJ3aXNlLCBhbGwgYXJlIHNob3duLgogICMgICAgICBJbnQgICAgIGFjdGl2ZV9xdWJpdAlJZiB0aGlzIGlzIDAgb3IgMSwgdGhlIGRpYWdvbmFscyBhcmUgc3RyYWlnaHRlbmVkIGFjY29yZGluZyB0byB0aGVpciBmdW5jdGlvbiBmb3IgdGhpcyBxdWJpdC4gT3RoZXJ3aXNlIHRoZXkgcmVtYWluIGRpYWdvbmFsLgogICMgQm9vbCAgICBibG9jaCAgICAgICAJV2hldGhlciBvciBub3QgdG8gZGlzcGxheSBCbG9jaCBjaXJjbGVzIGZvciB0aGUgcXViaXQgc3BlY2lmaWVkIGFib3ZlCiAgIyAgT1VUUFVUOgogICMgICAgICBbU3RyaW5nXSAgICBncmlkX2xpbmVzICAgQW4gYXJyYXkgb2Ygc3RycyB0aGF0IHJlcHJlc2VudCB0aGUgZ3JpZAogIAogIGNlbGxzID0geyAiWEkiOltdLCAiWkkiOltdLCAiWFgiOltdLCJYWiI6W10sIlpYIjpbXSwiWloiOltdLCJZWSI6W10sIklJIjpbXSwgIklYIjpbXSwgIklaIjpbXSB9CiAgCiAgIyBkZXRlcm1pbmUgd2hpY2ggY2VsbHMgYmVoYXZlIGluIHdoaWNoIHdheSAoSSBpcyBibGFuaywgQiBpcyBCbG9jaCBjaXJjbGUsIFggYW5kIFogYXJlIGhvcml6b250YWwgYW5kIHZlcnRpY2FsIGJveGVzIGFuZCBZIGFyZSBkaWFnb25hbCkKICBncmlkX2xpbmVzID0gW10KICBjZWxsX3R5cGVzID0ge30KICBpZiBibG9jaCA6CiAgICBpZiBzaG93bl9xdWJpdD09MCA6CiAgICAgIGNlbGxfdHlwZXMgPSB7IkkiOlsiSUkiLCJaSSIsIlhYIiwiWFoiLCJaWCIsIlpaIiwiWVkiLCJJWCIsIklaIl0sIlgiOltdLCJZIjpbXSwiWiI6W10sIkIiOlsiWEkiXX0gIyBzaG93bl9xdWJpdCBpcyB1c2VkIGFzIGFjdGl2ZSBxdWJpdAogICAgZWxpZiBzaG93bl9xdWJpdD09MSA6CiAgICAgIGNlbGxfdHlwZXMgPSB7IkkiOlsiSUkiLCJYSSIsIlpJIiwiWFgiLCJYWiIsIlpYIiwiWloiLCJZWSIsIklaIl0sIlgiOltdLCJZIjpbXSwiWiI6W10sIkIiOlsiSVgiXX0gIyBzaG93bl9xdWJpdCBpcyB1c2VkIGFzIGFjdGl2ZSBxdWJpdAogICAgZWxzZSA6CiAgICAgIGlmIGFjdGl2ZV9xdWJpdD09MCA6CiAgICAgICAgY2VsbF90eXBlcyA9IHsiSSI6WyJJSSIsIlpJIiwiWlgiLCJaWiJdLCJYIjpbIklYIl0sIlkiOltdLCJaIjpbIklaIl0sIkIiOlsiWEkiLCJYWCIsIlhaIl19CiAgICAgIGVsaWYgYWN0aXZlX3F1Yml0PT0xIDoKICAgICAgICBjZWxsX3R5cGVzID0geyJJIjpbIklJIiwiSVoiLCJYWiIsIlpaIl0sIlgiOlsiWEkiXSwiWSI6W10sIloiOlsiWkkiXSwiQiI6WyJJWCIsIlhYIiwiWlgiXX0gIyB0aGVzZSBhcmUgdGhlIHNhbWUgYXMgYWJvdmUgYnV0IHdpdGggc3RycyByZXZlcnNlZAogICAgICBlbHNlIDoKICAgICAgICBwcmludCgiRXJyb3I6IEEgdmFsaWQgcXViaXQgbXVzdCBiZSBjaG9zZW4gdG8gZGlzcGxheSBhIEJsb2NoIGNpcmNsZSIpCiAgZWxzZSA6CiAgICBpZiBzaG93bl9xdWJpdD09MCA6CiAgICAgIGNlbGxfdHlwZXMgPSB7IkkiOlsiSUkiLCJYWCIsIlhaIiwiWlgiLCJaWiIsIllZIiwiSVgiLCJJWiJdLCJYIjpbIlhJIl0sIlkiOltdLCJaIjpbIlpJIl0sIkIiOltdfQogICAgZWxpZiBzaG93bl9xdWJpdD09MSA6CiAgICAgIGNlbGxfdHlwZXMgPSB7IkkiOlsiSUkiLCJYSSIsIlpJIiwiWFgiLCJYWiIsIlpYIiwiWloiLCJZWSIsIklYIiwiSVoiXSwiWCI6WyJJWCJdLCJZIjpbXSwiWiI6WyJJWiJdLCJCIjpbXX0KICAgIGVsc2UgOgogICAgICAjIFkgZm9yIGRpYWdvbmFsIGJveGVzLCBzaW5jZSB0aGVyZSBpcyBubyBhY3RpdmUgcXViaXQKICAgICAgY2VsbF90eXBlcyA9IHsiSSI6WyJJSSJdLCJYIjpbIlhJIiwiSVgiLCJYWCJdLCJZIjpbIlhaIiwiWlgiXSwiWiI6WyJaSSIsIklaIiwiWloiXSwiQiI6W119CgogICMgbWFrZSBibGFuayBjZWxsCiAgZm9yIGNlbGwgaW4gY2VsbF90eXBlc1siSSJdIDoKICAgICAgY2VsbHNbY2VsbF0gPSBNYWtlQ2VsbCgge30gKQoKICAjIG1ha2UgY2VsbHMgd2l0aCBob3Jpem9udGFsIGFuZCB2ZXJ0aWNhbCBib3hlcwogIGZvciBjZWxsX3R5cGUgaW4gWyJYIiwiWiJdIDoKICAgICAgZm9yIGNlbGwgaW4gY2VsbF90eXBlc1tjZWxsX3R5cGVdIDoKICAgICAgICAgIGNlbGxzW2NlbGxdID0gTWFrZUNlbGwoIHsgY2VsbF90eXBlOiBzdGF0ZVtjZWxsXSB9ICkKCgoKCiMjIyMjIyMjIyMjIyMjIyMjIyMjIyMKCiAgIyBtYWtlIGNlbGxzIHdpdGggZGlhZ29uYWwgYm94ZXMKICBmb3IgY2VsbCBpbiBjZWxsX3R5cGVzWyJZIl0gOgogICAgaWYgYWN0aXZlX3F1Yml0IGluIFswLDFdIDoKICAgICAgaW5kZXggPSBhY3RpdmVfcXViaXQKICAgICAgY2VsbHNbY2VsbF0gPSBNYWtlQ2VsbCggeyBzdHIoY2VsbFtpbmRleF0pOnN0YXRlW2NlbGxdIH0gKSAjIHF1Yml0IGRlcGVuZGVudCBjZWxsIHR5cGUgaXMgdXNlZAogICAgZWxzZSA6CiAgICAgIGNlbGxzW2NlbGxdID0gTWFrZUNlbGwoIHsgIlkiOnN0YXRlW2NlbGxdIH0gKSAjIHNhbWUgYXMgaW4gWCxaIGxvb3AgYWJvdmUKCiAgIyBtYWtlIGNlbGxzIHdpdGggQmxvY2ggY2lyY2xlCiAgZm9yIGNlbGwgaW4gY2VsbF90eXBlc1siQiJdIDoKICAJaW5kZXggPSAoMS1hY3RpdmVfcXViaXQpCiAgCWlmIGFjdGl2ZV9xdWJpdD09MCA6CiAgCSAgY2VsbHNbY2VsbF0gPSBNYWtlQ2VsbCggeyAiWCI6c3RhdGVbIlgiK3N0cihjZWxsW2luZGV4XSldLCAiWiI6c3RhdGVbIloiK3N0cihjZWxsW2luZGV4XSldIH0gKQogIAllbHNlIDoKICAJICBjZWxsc1tjZWxsXSA9IE1ha2VDZWxsKCB7ICJYIjpzdGF0ZVtzdHIoY2VsbFtpbmRleF0pKyJYIl0sICJaIjpzdGF0ZVtzdHIoY2VsbFtpbmRleF0pKyJaIl0gfSApCiAgCiAgZm9yIGwgaW4gcmFuZ2UoMTIpIDoKICAgICAgZ3JpZF9saW5lcy5hcHBlbmQoIGNlbGxzWyJJSSJdW2xdICsgY2VsbHNbIlpJIl1bbF0gKyBjZWxsc1siWEkiXVtsXSApCiAgZm9yIGwgaW4gcmFuZ2UoMTIpIDoKICAgICAgZ3JpZF9saW5lcy5hcHBlbmQoIGNlbGxzWyJJWiJdW2xdICsgY2VsbHNbIlpaIl1bbF0gKyBjZWxsc1siWFoiXVtsXSApCiAgZm9yIGwgaW4gcmFuZ2UoMTIpIDoKICAgICAgZ3JpZF9saW5lcy5hcHBlbmQoIGNlbGxzWyJJWCJdW2xdICsgY2VsbHNbIlpYIl1bbF0gKyBjZWxsc1siWFgiXVtsXSApCgogIHJldHVybiBncmlkX2xpbmVzCgogCnByaW50KENvbG91cmVkU3RyaW5nKCJoZWxsbyIsInIiKSkKcHJpbnQoQ29sb3VyZWRTdHJpbmcoImhlbGxvIiwiZyIpKQpwcmludChDb2xvdXJlZFN0cmluZygiaGVsbG8iLCJiIikpCnByaW50KENvbG91cmVkU3RyaW5nKCJoZWxsbyIsInAiKSkKcHJpbnQoQ29sb3VyZWRTdHJpbmcoImhlbGxvIiwicyIpKQoKICAKZ3JpZF9saW5lcyA9IE1ha2VHcmlkICggQXBwbHlHYXRlKHsiWEkiOjAuMCwgIlpJIjoxLjAsCiAgICAgICAgICAgICAgICAgICAgICAgICJYWCI6MC4wLCJYWiI6MC4wLCJaWCI6MC4wLCJaWiI6MC4wLCJZWSI6MC4wLAogICAgICAgICAgICAgICAgICAgICAgICAiSVgiOjAuMCwgIklaIjowLjB9LCJjeiIsIjAiKSwgMiwgMiwgRmFsc2UgKQpmb3IgbGluZSBpbiBncmlkX2xpbmVzIDoKICBwcmludChsaW5lKQoKCiAgICAKICAgIA=="},"asBuffer":null},"loaded":true}}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
#  Created by James Wootton
#  Copyright © 2017 University of Basel. All rights reserved.

import math

def ColouredString (message,colour) :
  #  DESCRIPTION:
  #      Prints in a colour specified by the colour in ["r","b","p"] and then sets what follows back to white

  # first the colour
  coloured_message = ""
  if colour=="r": # red
    coloured_message += "\x1b[1;31m"
  elif colour=="g": # green
    coloured_message += "\x1b[1;32m"
  elif colour=="b": # blue
    coloured_message += "\x1b[1;34m" 
  elif colour=="p": # purple
    coloured_message += "\x1b[1;35m"
  else: # black (which should actually be the default text colour)
    coloured_message += "\x1b[0m"
  
  # then the message
  coloured_message += message

  # and back to black
  coloured_message += "\x1b[0m"
  
  return coloured_message

def  Expect2Prob ( expect ) :
  #  DESCRIPTION:
  #      Converts expectation value to a probability of getting the outcome 1.
  return (1-expect)/2
  
def Expect2Polar ( boxes ) :
  #  DESCRIPTION:
  #      Takes the contents of an X and Z box and turns it into polar coordinates for the Bloch circle.
  #  INPUT:
  #      {String: Float}    boxes       Should have entries for "X" and "Z", which serve as the horizontal and vertical boxes respectively.
  #  OUTPUT:
  #      [Float]            [ degrees, radius ]     degrees is between 0 and 1. It is the angle clockwise from the top as a fraction of 2*Pi. Radius is how far out the point is. Will be 1 for pure states and 0 for maximally mixed.
 
  radius = math.sqrt( boxes["X"]**2 + boxes["Z"]**2)
  degrees = 0 # default value of 0
  if radius>0.0:
    degrees = math.acos( -boxes["Z"] / radius ) / (2*math.pi)
    if boxes["X"]>=0.0:
      degrees = 1 - degrees

    return [ degrees, radius ]

def Polar2Expect ( polar_coords ) :
  #  DESCRIPTION:
  #      As Boxes2Polar, but with inputs and outputs reversed
  boxes = {}
  boxes["X"] = -polar_coords[1] * sin( 2*math.pi*polar_coords[0])
  boxes["Z"] = -polar_coords[1] * cos( 2*math.pi*polar_coords[0])
  return boxes
    
def ExchangeBoxes ( state, box1, box2 ) :
  #  DESCRIPTION:
  #      Given a state and two of its boxes, the values for these boxes are exchanged
  output_state = state
  temp = output_state[box1]
  output_state[box1] = output_state[box2]
  output_state[box2] = temp
  return output_state
    
def ApplyGate ( state, gate, qubit ) :
  #  DESCRIPTION:
  #      Transforms the given state according to the given gate.
  #  INPUT:
  #      {String: Float}    state       Full two qubit state. Needs entries for XI, ZI, IZ, IX, XX, XZ, ZX, ZZ and YY
  #      String              gate        QISKit style str to specify a gate (can be x, z, h, q, qdg, or cz)
  #      Int                 qubit       Qubit on which single qubit gate is applied. Unused for CZ.
  #  OUTPUT:
  #      {String: Float}    state       Transformed version of input state.
  
  # We begin constructing the output state by copying the input state.
  output_state = state
  
  # Single qubit gates require special treatment, so we deal with these separately.
  if gate in ["x","z","h","q","qdg"] :
    # Single qubit gates act on pairs of boxes. These are the pairs that form Bloch circles.
    # For qubit 0, these pairs are  (XI, ZI), (XX,ZX) and (XZ,ZZ).
    # For qubit 2 they are (IX, IZ), (XX,XZ) and (ZX,ZZ).
    # Here we loop over and construct the three pairs, which in each case will be (p[0],p[1]).
    for rc in ["I","X","Z"] :
            
      box_name = {"X":rc,"Z":rc}
      for p in ["X","Z"] :
        if qubit=="0" :
          box_name[p] = p + box_name[p]
        else :
          box_name[p] = box_name[p] + p
          
      
      
      # What we do to the pairs depends on the gate we apply.
      if gate=="x": # invert Z box and invert YY
        output_state[box_name["Z"]] = -output_state[box_name["Z"]]
        output_state["YY"] = -output_state["YY"]
      elif gate=="z" :# invert X box and invert YY
        output_state[box_name["X"]] = -output_state[box_name["X"]]
        output_state["YY"] = -output_state["YY"]
      elif gate=="h" : # exchange X and Z boxes and invert YY
        output_state = ExchangeBoxes( output_state, box_name["X"], box_name["Z"])
        output_state["YY"] = -output_state["YY"]
      elif gate in ["q","qdg"] :
        polar_coords = Expect2Polar( { "X":output_state[box_name["X"]], "Z":output_state[box_name["Z"]] } ) # convert to polar coords
        if gate=="q" : # change angle according to the rotation
          polar_coords[0] += 1/8
        else :
          polar_coords[0] -= 1/8
          
        # convert back to boxes
        output_boxes = Polar2Expect(polar_coords)
        for p in ["X","Z"] :
          output_state[box_name[p]] = output_boxes[p]
      else :
        print("Error: Unknown single qubit gate")

  # Now for the two qubit gates
  elif gate=="cz" :
    # exchange contents of XI and XZ
    output_state = ExchangeBoxes( output_state, "XI", "XZ")
    # exchange contents of IX and ZX
    output_state = ExchangeBoxes( output_state, "IX", "ZX")
    # exchange contents of XX and YY
    output_state = ExchangeBoxes( output_state, "XX", "YY")
  elif gate=="cx" :
    if qubit=="1" :
      # exchange contents of XI and XX
      output_state = ExchangeBoxes( output_state, "XI", "XX")
      # exchange contents of IZ and ZZ
      output_state = ExchangeBoxes( output_state, "IZ", "ZZ")
      # exchange contents of XZ and YY
      output_state = ExchangeBoxes( output_state, "XZ", "YY")
      # invert XZ
      output_state["XZ"] = -output_state["XZ"]
    elif qubit=="0" :
      # exchange contents of ZI and ZZ
      output_state = ExchangeBoxes( output_state, "ZI", "ZZ")
      # exchange contents of IX and XX
      output_state = ExchangeBoxes( output_state, "IX", "XX")
      # exchange contents of ZX and YY
      output_state = ExchangeBoxes( output_state, "ZX", "YY")
      # invert ZX
      output_state["ZX"] = -output_state["ZX"]
      output_state["YY"] = -output_state["YY"] # invert YY
    else :
      print("Error: Unknown gate")
  
  
  return output_state
  
def MakeInitial ( target_state, inverse_solution ) :
  #  DESCRIPTION:
  #      Constructs an initial state such that the target state and solution are as specified by the input
  #      Note that the inverse of the desired solution must be supplied here
  #      Put simply, this means that the first gate should be on the right, and the substition q <-> qdg should be used
    
  state = target_state
  for gate in inverse_solution :
      state = ApplyGate( state, gate[0], gate[1] )
  return state
  
def MakeCell ( cell_state ) :
  #  DESCRIPTION:
  #      Prints a single box or Bloch circle, depending on the input state.
  #  INPUT:
  #      {String: Float}    cell_state  With key "X", value is the expectation value for horizontal red box.
  #                                      Similarly for "Z" and the vertical blue box, and "Y" for a diagonal purple box.
  #                                      Note that a cell that uses "Y" will correspond to XZ or ZZ boxes. Not a Y box.
  #  OUTPUT:
  #      [String]            lines       List of 12 lines, which when printed sequentially will display the cell.
  #  PROCESS:
  #      When a single key is supplied, the corresponding box is printed.
  #      When both "X" and "Z" are supplied, the boxes are combined into a Bloch circle.
  #      In all cases, the level on the box is first converted from the expectation value to the probability.
  
  reso = {"X":17, "Z":9, "Y":13} # number of characters used for each type of box (including center)

  bottom = "───────────────────────" # bottom border
  right = "|" # right border

  # The 8 points around the circle and one in the middle. Default to a dot
  c = []
  c.append("˙")
  c.append(".")
  c.append("·")
  c.append("˙")
  c.append(".")
  c.append("˙")
  c.append("·")
  c.append(".")
  c.append(" ")
  
  # When a Bloch sphere is displayed, the point corresponding to the state is denoted by "*"
  # This is displayed only for pretty mixed states (radius <0.25) and pretty pure ones (radius>0.75)
  if ( "X" in cell_state.keys() and "Z" in cell_state.keys() ) : # both X  and Z boxes need to be present in the cell
    if ( Expect2Polar( cell_state )[1]<0.25 ) : # if state is pretty mixed, point is shown in the center
      c[8] = "*"
    elif Expect2Polar( cell_state )[1]>0.75 : # if state is pretty pure, it is one of the 8 around the edge
      point = 0
      degree = Expect2Polar( cell_state )[0]
      for eighth in range(1,8) :
        if degree>(float(eighth)/8 - 1.0/16) and degree<=(float(eighth)/8 + 1.0/16 ) :
          point = eighth
      if point in [1,4,7] :
        c[ point ] = "⁎"
      else :
        c[ point ] = "*"


  # Strings for the three boxes. Blank if unused, but filled with █ and ░ if used to represent how 'filled' they are.
  b = {"X":[], "Z":[], "Y":[] }
  for box in [ "X", "Z", "Y" ] :
    this_b = []
    if box not in cell_state.keys() :
      for _ in range(1,reso[box]+1) :
        this_b.append(" ")
    else :
      prob = Expect2Prob( cell_state[box] ) # convert from expectation value to prob of a 1 outcome
      fill = int( float(reso[box]) * prob )
      
      if (prob>0.5 and fill != reso[box]) : # if over half filled, but not completely filled, round up (for clear visuals)
          fill += 1
      for _ in range(fill) :
        if box == "X" :
          this_b.append( ColouredString( "█" , "r" ) )
        elif box == "Z" :
          this_b.append( ColouredString( "█" , "b" ) )
        elif box == "Y" :
          this_b.append( ColouredString( "█" , "p" ) )

      for _ in range(fill,reso[box]) :
        if box == "X" :
          this_b.append( ColouredString( "░" , "r" ) )
        elif box == "Z" :
          this_b.append( ColouredString( "░" , "b" ) )
        elif box == "Y" :
          this_b.append( ColouredString( "░" , "p" ) )
    b[box] = this_b
  
  # center is X with the colour of the cell, unless the cell is empty
  if "Y" in cell_state.keys() :
    c[8] = ColouredString( b["Y"][int(reso["Y"]/2)], "p" )
  elif "X" in cell_state.keys() :
    c[8] = ColouredString( b["X"][int(reso["X"]/2)], "r" )
  elif "Z" in cell_state.keys() :
    c[8] = ColouredString( b["Z"][int(reso["Z"]/2)], "b" )
  
  b["X"][int(reso["X"]/2)] = c[8] # The center will be the ninth element of c instead

  # Declare and construct the lines.
  lines = []
  if cell_state==[] :
    for _ in range(11) :
      lines.append( "                       "+right )
  else :
    lines.append( "      .·  "+c[0]+"  ·.        "+right )
    lines.append( "   "+c[7]+"˙     "+b["Z"][8]+"     ˙"+c[1]+"     "+right )
    lines.append( "  ·       "+b["Z"][7]+"    "+b["Y"][11]+b["Y"][12]+" ·    "+right )
    lines.append( " ·        "+b["Z"][6]+"  "+b["Y"][9]+b["Y"][10]+"    ·   "+right )
    lines.append( "          "+b["Z"][5]+""+b["Y"][7]+b["Y"][8]+"          "+right )
    lines.append( ""+c[6]+" "+"".join(b["X"])+" "+c[2]+"  "+right )
    lines.append( "        "+b["Y"][4]+b["Y"][5]+""+b["Z"][3]+"            "+right )
    lines.append( " ˙    "+b["Y"][2]+b["Y"][3]+"  "+b["Z"][2]+"        ˙   "+right )
    lines.append( "  · "+b["Y"][0]+b["Y"][1]+"    "+b["Z"][1]+"       ·    "+right )
    lines.append( "   "+c[5]+".     "+b["Z"][0]+"     ."+c[3]+"     "+right )
    lines.append( "      ˙·  "+c[4]+"  ·˙        "+right )
  lines.append( bottom + right )
  
  return lines

def MakeGrid ( state, shown_qubit, active_qubit, bloch ) :

  #  DESCRIPTION:
  #      The inputs describe what the grid is doing. This function puts all that information together to actually make the grid.
  #  INPUT:
  #      {String: Float}    state   Full two qubit state. Needs entries for XI, ZI, IZ, IX, XX, XZ, ZX, ZZ and YY
  #      Int     shown_qubit     If this is 0 or 1, only the two boxes of that qubit are shown. Otherwise, all are shown.
  #      Int     active_qubit	If this is 0 or 1, the diagonals are straightened according to their function for this qubit. Otherwise they remain diagonal.
  # Bool    bloch       	Whether or not to display Bloch circles for the qubit specified above
  #  OUTPUT:
  #      [String]    grid_lines   An array of strs that represent the grid
  
  cells = { "XI":[], "ZI":[], "XX":[],"XZ":[],"ZX":[],"ZZ":[],"YY":[],"II":[], "IX":[], "IZ":[] }
  
  # determine which cells behave in which way (I is blank, B is Bloch circle, X and Z are horizontal and vertical boxes and Y are diagonal)
  grid_lines = []
  cell_types = {}
  if bloch :
    if shown_qubit==0 :
      cell_types = {"I":["II","ZI","XX","XZ","ZX","ZZ","YY","IX","IZ"],"X":[],"Y":[],"Z":[],"B":["XI"]} # shown_qubit is used as active qubit
    elif shown_qubit==1 :
      cell_types = {"I":["II","XI","ZI","XX","XZ","ZX","ZZ","YY","IZ"],"X":[],"Y":[],"Z":[],"B":["IX"]} # shown_qubit is used as active qubit
    else :
      if active_qubit==0 :
        cell_types = {"I":["II","ZI","ZX","ZZ"],"X":["IX"],"Y":[],"Z":["IZ"],"B":["XI","XX","XZ"]}
      elif active_qubit==1 :
        cell_types = {"I":["II","IZ","XZ","ZZ"],"X":["XI"],"Y":[],"Z":["ZI"],"B":["IX","XX","ZX"]} # these are the same as above but with strs reversed
      else :
        print("Error: A valid qubit must be chosen to display a Bloch circle")
  else :
    if shown_qubit==0 :
      cell_types = {"I":["II","XX","XZ","ZX","ZZ","YY","IX","IZ"],"X":["XI"],"Y":[],"Z":["ZI"],"B":[]}
    elif shown_qubit==1 :
      cell_types = {"I":["II","XI","ZI","XX","XZ","ZX","ZZ","YY","IX","IZ"],"X":["IX"],"Y":[],"Z":["IZ"],"B":[]}
    else :
      # Y for diagonal boxes, since there is no active qubit
      cell_types = {"I":["II"],"X":["XI","IX","XX"],"Y":["XZ","ZX"],"Z":["ZI","IZ","ZZ"],"B":[]}

  # make blank cell
  for cell in cell_types["I"] :
      cells[cell] = MakeCell( {} )

  # make cells with horizontal and vertical boxes
  for cell_type in ["X","Z"] :
      for cell in cell_types[cell_type] :
          cells[cell] = MakeCell( { cell_type: state[cell] } )




######################

  # make cells with diagonal boxes
  for cell in cell_types["Y"] :
    if active_qubit in [0,1] :
      index = active_qubit
      cells[cell] = MakeCell( { str(cell[index]):state[cell] } ) # qubit dependent cell type is used
    else :
      cells[cell] = MakeCell( { "Y":state[cell] } ) # same as in X,Z loop above

  # make cells with Bloch circle
  for cell in cell_types["B"] :
  	index = (1-active_qubit)
  	if active_qubit==0 :
  	  cells[cell] = MakeCell( { "X":state["X"+str(cell[index])], "Z":state["Z"+str(cell[index])] } )
  	else :
  	  cells[cell] = MakeCell( { "X":state[str(cell[index])+"X"], "Z":state[str(cell[index])+"Z"] } )
  
  for l in range(12) :
      grid_lines.append( cells["II"][l] + cells["ZI"][l] + cells["XI"][l] )
  for l in range(12) :
      grid_lines.append( cells["IZ"][l] + cells["ZZ"][l] + cells["XZ"][l] )
  for l in range(12) :
      grid_lines.append( cells["IX"][l] + cells["ZX"][l] + cells["XX"][l] )

  return grid_lines

 
print(ColouredString("hello","r"))
print(ColouredString("hello","g"))
print(ColouredString("hello","b"))
print(ColouredString("hello","p"))
print(ColouredString("hello","s"))

  
grid_lines = MakeGrid ( ApplyGate({"XI":0.0, "ZI":1.0,
                        "XX":0.0,"XZ":0.0,"ZX":0.0,"ZZ":0.0,"YY":0.0,
                        "IX":0.0, "IZ":0.0},"cz","0"), 2, 2, False )
for line in grid_lines :
  print(line)