diff --git a/Pipfile.lock b/Pipfile.lock index f472835..1da918e 100644 --- a/Pipfile.lock +++ b/Pipfile.lock @@ -4,16 +4,10 @@ "sha256": "4f6bbdc0b85a30b4f8812a03bb3dd9d233ff359e8c6340fa79ecb90e4ac8c0f7" }, "pipfile-spec": 6, - "requires": { - "python_version": "3.10" - }, + "requires": {"python_version": "3.10"}, "sources": [ - { - "name": "pypi", - "url": "https://pypi.org/simple", - "verify_ssl": true - } - ] + {"name": "pypi", "url": "https://pypi.org/simple", "verify_ssl": true} + ], }, "default": {}, "develop": { @@ -55,76 +49,76 @@ "sha256:e54962802d4b8b18b6207d4a927032826af39395a3bd9196a5af43fc4e60b009", "sha256:f705e12750171c0ab4ef2a3c76b9a4024a62c4103e3a55dd6f99265b9bc6fcfc", "sha256:f881853d2643a29e643609da57b96d5f9c9b93f62429dcc1cbb413c7d07f0e1a", - "sha256:fe60131d21b31fd1a14bd43e6bb88256f69dfc3188b3a89d736d6c71ed43ec95" + "sha256:fe60131d21b31fd1a14bd43e6bb88256f69dfc3188b3a89d736d6c71ed43ec95", ], "markers": "python_version >= '3.6'", - "version": "==3.7.4.post0" + "version": "==3.7.4.post0", }, "aiohttp-jinja2": { "hashes": [ "sha256:860da7582efa866744bad5883947557d0f82e457d69903ea65d666b66f8a69ca", - "sha256:9c22a0e48e3b277fc145c67dd8c3b8f609dab36bce9eb337f70dfe716663c9a0" + "sha256:9c22a0e48e3b277fc145c67dd8c3b8f609dab36bce9eb337f70dfe716663c9a0", ], "markers": "python_full_version >= '3.5.3'", - "version": "==1.4.2" + "version": "==1.4.2", }, "aioopenssl": { "hashes": [ "sha256:eae2fb193ec0d2a3f752f72d8f672191cc836b1039de5e334cc9cb835b800831" ], - "version": "==0.6.0" + "version": "==0.6.0", }, "aiosasl": { "hashes": [ "sha256:d927a8f9d855c4c00dea9d88fb86ea0d09dd4e7642b2109d2bd93be2f4c17b4e" ], - "version": "==0.5.0" + "version": "==0.5.0", }, "aioxmpp": { "hashes": [ "sha256:3cf963a0513d07c397fab4cdbf41a7ad6aa736790449e97716a934b61e58feba" ], - "version": "==0.13.2" + "version": "==0.13.2", }, "anyio": { "hashes": [ "sha256:a0aeffe2fb1fdf374a8e4b471444f0f3ac4fb9f5a5b542b48824475e0042a5a6", - "sha256:b5fa16c5ff93fa1046f2eeb5bbff2dad4d3514d6cda61d02816dba34fa8c3c2e" + "sha256:b5fa16c5ff93fa1046f2eeb5bbff2dad4d3514d6cda61d02816dba34fa8c3c2e", ], "markers": "python_full_version >= '3.6.2'", - "version": "==3.5.0" + "version": "==3.5.0", }, "arrow": { "hashes": [ "sha256:05caf1fd3d9a11a1135b2b6f09887421153b94558e5ef4d090b567b47173ac2b", - "sha256:d622c46ca681b5b3e3574fcb60a04e5cc81b9625112d5fb2b44220c36c892177" + "sha256:d622c46ca681b5b3e3574fcb60a04e5cc81b9625112d5fb2b44220c36c892177", ], "markers": "python_version >= '3.6'", - "version": "==1.2.2" + "version": "==1.2.2", }, "async-timeout": { "hashes": [ "sha256:0c3c816a028d47f659d6ff5c745cb2acf1f966da1fe5c19c77a70282b25f4c5f", - "sha256:4291ca197d287d274d0b6cb5d6f8f8f82d434ed288f962539ff18cc9012f9ea3" + "sha256:4291ca197d287d274d0b6cb5d6f8f8f82d434ed288f962539ff18cc9012f9ea3", ], "markers": "python_full_version >= '3.5.3'", - "version": "==3.0.1" + "version": "==3.0.1", }, "attrs": { "hashes": [ "sha256:2d27e3784d7a565d36ab851fe94887c5eccd6a463168875832a1be79c82828b4", - "sha256:626ba8234211db98e869df76230a137c4c40a12d72445c45d5f5b716f076e2fd" + "sha256:626ba8234211db98e869df76230a137c4c40a12d72445c45d5f5b716f076e2fd", ], "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4'", - "version": "==21.4.0" + "version": "==21.4.0", }, "babel": { "hashes": [ "sha256:3f349e85ad3154559ac4930c3918247d319f21910d5ce4b25d439ed8693b98d2", - "sha256:98aeaca086133efb3e1e2aad0396987490c8425929ddbcfe0550184fdc54cd13" + "sha256:98aeaca086133efb3e1e2aad0396987490c8425929ddbcfe0550184fdc54cd13", ], "markers": "python_version >= '3.6'", - "version": "==2.10.1" + "version": "==2.10.1", }, "black": { "hashes": [ @@ -150,17 +144,17 @@ "sha256:e3556168e2e5c49629f7b0f377070240bd5511e45e25a4497bb0073d9dda776a", "sha256:e8477ec6bbfe0312c128e74644ac8a02ca06bcdb8982d4ee06f209be28cdf163", "sha256:ee8f1f7228cce7dffc2b464f07ce769f478968bfb3dd1254a4c2eeed84928aad", - "sha256:fd57160949179ec517d32ac2ac898b5f20d68ed1a9c977346efbac9c2f1e779d" + "sha256:fd57160949179ec517d32ac2ac898b5f20d68ed1a9c977346efbac9c2f1e779d", ], "index": "pypi", - "version": "==22.3.0" + "version": "==22.3.0", }, "certifi": { "hashes": [ "sha256:78884e7c1d4b00ce3cea67b44566851c4343c120abd683433ce934a68ea58872", - "sha256:d62a0163eb4c2344ac042ab2bdf75399a71a2d8c7d47eac2e2ee91b9d6339569" + "sha256:d62a0163eb4c2344ac042ab2bdf75399a71a2d8c7d47eac2e2ee91b9d6339569", ], - "version": "==2021.10.8" + "version": "==2021.10.8", }, "cffi": { "hashes": [ @@ -213,33 +207,33 @@ "sha256:f5c7150ad32ba43a07c4479f40241756145a1f03b43480e058cfd862bf5041c7", "sha256:f6f824dc3bce0edab5f427efcfb1d63ee75b6fcb7282900ccaf925be84efb0fc", "sha256:fd8a250edc26254fe5b33be00402e6d287f562b6a5b2152dec302fa15bb3e997", - "sha256:ffaa5c925128e29efbde7301d8ecaf35c8c60ffbcd6a1ffd3a552177c8e5e796" + "sha256:ffaa5c925128e29efbde7301d8ecaf35c8c60ffbcd6a1ffd3a552177c8e5e796", ], - "version": "==1.15.0" + "version": "==1.15.0", }, "chardet": { "hashes": [ "sha256:0d6f53a15db4120f2b08c94f11e7d93d2c911ee118b6b30a04ec3ee8310179fa", - "sha256:f864054d66fd9118f2e67044ac8981a54775ec5b67aed0441892edb553d21da5" + "sha256:f864054d66fd9118f2e67044ac8981a54775ec5b67aed0441892edb553d21da5", ], "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4'", - "version": "==4.0.0" + "version": "==4.0.0", }, "charset-normalizer": { "hashes": [ "sha256:2857e29ff0d34db842cd7ca3230549d1a697f96ee6d3fb071cfa6c7393832597", - "sha256:6881edbebdb17b39b4eaaa821b438bf6eddffb4468cf344f09f89def34a8b1df" + "sha256:6881edbebdb17b39b4eaaa821b438bf6eddffb4468cf344f09f89def34a8b1df", ], "markers": "python_version >= '3.5'", - "version": "==2.0.12" + "version": "==2.0.12", }, "click": { "hashes": [ "sha256:7682dc8afb30297001674575ea00d1814d808d6a36af415a82bd481d37ba7b8e", - "sha256:bb4d8133cb15a609f44e8213d9b391b0809795062913b383c62be0ee95b1db48" + "sha256:bb4d8133cb15a609f44e8213d9b391b0809795062913b383c62be0ee95b1db48", ], "markers": "python_version >= '3.7'", - "version": "==8.1.3" + "version": "==8.1.3", }, "cryptography": { "hashes": [ @@ -264,73 +258,73 @@ "sha256:e53258e69874a306fcecb88b7534d61820db8a98655662a3dd2ec7f1afd9132f", "sha256:ef15c2df7656763b4ff20a9bc4381d8352e6640cfeb95c2972c38ef508e75181", "sha256:f224ad253cc9cea7568f49077007d2263efa57396a2f2f78114066fd54b5c68e", - "sha256:f8ec91983e638a9bcd75b39f1396e5c0dc2330cbd9ce4accefe68717e6779e0a" + "sha256:f8ec91983e638a9bcd75b39f1396e5c0dc2330cbd9ce4accefe68717e6779e0a", ], "markers": "python_version >= '3.6'", - "version": "==37.0.2" + "version": "==37.0.2", }, "dnspython": { "hashes": [ "sha256:0f7569a4a6ff151958b64304071d370daa3243d15941a7beedf0c9fe5105603e", - "sha256:a851e51367fb93e9e1361732c1d60dab63eff98712e503ea7d92e6eccb109b4f" + "sha256:a851e51367fb93e9e1361732c1d60dab63eff98712e503ea7d92e6eccb109b4f", ], "markers": "python_version >= '3.6' and python_version < '4.0'", - "version": "==2.2.1" + "version": "==2.2.1", }, "h11": { "hashes": [ "sha256:36a3cb8c0a032f56e2da7084577878a035d3b61d104230d4bd49c0c6b555a9c6", - "sha256:47222cb6067e4a307d535814917cd98fd0a57b6788ce715755fa2b6c28b56042" + "sha256:47222cb6067e4a307d535814917cd98fd0a57b6788ce715755fa2b6c28b56042", ], "markers": "python_version >= '3.6'", - "version": "==0.12.0" + "version": "==0.12.0", }, "httpcore": { "hashes": [ "sha256:036f960468759e633574d7c121afba48af6419615d36ab8ede979f1ad6276fa3", - "sha256:369aa481b014cf046f7067fddd67d00560f2f00426e79569d99cb11245134af0" + "sha256:369aa481b014cf046f7067fddd67d00560f2f00426e79569d99cb11245134af0", ], "markers": "python_version >= '3.6'", - "version": "==0.13.7" + "version": "==0.13.7", }, "httpx": { "hashes": [ "sha256:2f57e72cee80879eaccde550fd1192d827d26662c6f3a65b89acdaaba03a4c89", - "sha256:78bf0260283a9c10682b1dc2d6d753f154eb876df669518f18dfa8a0e8700dc5" + "sha256:78bf0260283a9c10682b1dc2d6d753f154eb876df669518f18dfa8a0e8700dc5", ], "index": "pypi", - "version": "==1.0.0b0" + "version": "==1.0.0b0", }, "idna": { "hashes": [ "sha256:84d9dd047ffa80596e0f246e2eab0b391788b0503584e8945f2368256d2735ff", - "sha256:9d643ff0a55b762d5cdb124b8eaa99c66322e2157b69160bc32796e824360e6d" + "sha256:9d643ff0a55b762d5cdb124b8eaa99c66322e2157b69160bc32796e824360e6d", ], "markers": "python_version >= '3.5'", - "version": "==3.3" + "version": "==3.3", }, "isort": { "hashes": [ "sha256:6f62d78e2f89b4500b080fe3a81690850cd254227f27f75c3a0c491a1f351ba7", - "sha256:e8443a5e7a020e9d7f97f1d7d9cd17c88bcb3bc7e218bf9cf5095fe550be2951" + "sha256:e8443a5e7a020e9d7f97f1d7d9cd17c88bcb3bc7e218bf9cf5095fe550be2951", ], "index": "pypi", - "version": "==5.10.1" + "version": "==5.10.1", }, "jinja2": { "hashes": [ "sha256:1f06f2da51e7b56b8f238affdd6b4e2c61e39598a378cc49345bc1bd42a978a4", - "sha256:703f484b47a6af502e743c9122595cc812b0271f661722403114f71a79d0f5a4" + "sha256:703f484b47a6af502e743c9122595cc812b0271f661722403114f71a79d0f5a4", ], "markers": "python_version >= '3.6'", - "version": "==3.0.1" + "version": "==3.0.1", }, "jinja2-time": { "hashes": [ "sha256:d14eaa4d315e7688daa4969f616f226614350c48730bfa1692d2caebd8c90d40", - "sha256:d3eab6605e3ec8b7a0863df09cc1d23714908fa61aa6986a845c20ba488b4efa" + "sha256:d3eab6605e3ec8b7a0863df09cc1d23714908fa61aa6986a845c20ba488b4efa", ], - "version": "==0.2.0" + "version": "==0.2.0", }, "lxml": { "hashes": [ @@ -394,10 +388,10 @@ "sha256:f10ce66fcdeb3543df51d423ede7e238be98412232fca5daec3e54bcd16b8da0", "sha256:f63f62fc60e6228a4ca9abae28228f35e1bd3ce675013d1dfb828688d50c6e23", "sha256:fa56bb08b3dd8eac3a8c5b7d075c94e74f755fd9d8a04543ae8d37b1612dd170", - "sha256:fa9b7c450be85bfc6cd39f6df8c5b8cbd76b5d6fc1f69efec80203f9894b885f" + "sha256:fa9b7c450be85bfc6cd39f6df8c5b8cbd76b5d6fc1f69efec80203f9894b885f", ], "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4'", - "version": "==4.8.0" + "version": "==4.8.0", }, "markupsafe": { "hashes": [ @@ -440,10 +434,10 @@ "sha256:e8c843bbcda3a2f1e3c2ab25913c80a3c5376cd00c6e8c4a86a89a28c8dc5452", "sha256:efc1913fd2ca4f334418481c7e595c00aad186563bbc1ec76067848c7ca0a933", "sha256:f121a1420d4e173a5d96e47e9a0c0dcff965afdf1626d28de1460815f7c4ee7a", - "sha256:fc7b548b17d238737688817ab67deebb30e8073c95749d55538ed473130ec0c7" + "sha256:fc7b548b17d238737688817ab67deebb30e8073c95749d55538ed473130ec0c7", ], "markers": "python_version >= '3.7'", - "version": "==2.1.1" + "version": "==2.1.1", }, "multidict": { "hashes": [ @@ -475,24 +469,24 @@ "sha256:ce20044d0317649ddbb4e54dab3c1bcc7483c78c27d3f58ab3d0c7e6bc60d26a", "sha256:d1071414dd06ca2eafa90c85a079169bfeb0e5f57fd0b45d44c092546fcd6fd9", "sha256:d3be11ac43ab1a3e979dac80843b42226d5d3cccd3986f2e03152720a4297cd7", - "sha256:db603a1c235d110c860d5f39988ebc8218ee028f07a7cbc056ba6424372ca31b" + "sha256:db603a1c235d110c860d5f39988ebc8218ee028f07a7cbc056ba6424372ca31b", ], "markers": "python_full_version >= '3.4.1'", - "version": "==4.5.2" + "version": "==4.5.2", }, "mypy-extensions": { "hashes": [ "sha256:090fedd75945a69ae91ce1303b5824f428daf5a028d2f6ab8a299250a846f15d", - "sha256:2d82818f5bb3e369420cb3c4060a7970edba416647068eb4c5343488a6c604a8" + "sha256:2d82818f5bb3e369420cb3c4060a7970edba416647068eb4c5343488a6c604a8", ], - "version": "==0.4.3" + "version": "==0.4.3", }, "nodeenv": { "hashes": [ "sha256:3ef13ff90291ba2a4a7a4ff9a979b63ffdd00a464dbe04acf0ea6471517a4c2b", - "sha256:621e6b7076565ddcacd2db0294c0381e01fd28945ab36bcf00f41c5daf63bef7" + "sha256:621e6b7076565ddcacd2db0294c0381e01fd28945ab36bcf00f41c5daf63bef7", ], - "version": "==1.6.0" + "version": "==1.6.0", }, "numpy": { "hashes": [ @@ -515,10 +509,10 @@ "sha256:f8c1f39caad2c896bc0018f699882b345b2a63708008be29b1f355ebf6f933fe", "sha256:f950f8845b480cffe522913d35567e29dd381b0dc7e4ce6a4a9f9156417d2430", "sha256:fade0d4f4d292b6f39951b6836d7a3c7ef5b2347f3c420cd9820a1d90d794802", - "sha256:fdf3c08bce27132395d3c3ba1503cac12e17282358cb4bddc25cc46b0aca07aa" + "sha256:fdf3c08bce27132395d3c3ba1503cac12e17282358cb4bddc25cc46b0aca07aa", ], "index": "pypi", - "version": "==1.22.3" + "version": "==1.22.3", }, "orjson": { "hashes": [ @@ -553,25 +547,25 @@ "sha256:dd24f66b6697ee7424f7da575ec6cbffc8ede441114d53470949cda4d97c6e56", "sha256:e19d23741c5de13689bb316abfccea15a19c264e3ec8eb332a5319a583595ace", "sha256:ea32015a5d8a4ce00d348a0de5dc7040e0ad58f970a8fcbb5713a1eac129e493", - "sha256:eb22485847b9a0c4bbedc668df860126ac931edbed1d456cf41a59f3cb961ed8" + "sha256:eb22485847b9a0c4bbedc668df860126ac931edbed1d456cf41a59f3cb961ed8", ], "index": "pypi", - "version": "==3.6.8" + "version": "==3.6.8", }, "pathspec": { "hashes": [ "sha256:7d15c4ddb0b5c802d161efc417ec1a2558ea2653c2e8ad9c19098201dc1c993a", - "sha256:e564499435a2673d586f6b2130bb5b95f04a3ba06f81b8f895b651a3c76aabb1" + "sha256:e564499435a2673d586f6b2130bb5b95f04a3ba06f81b8f895b651a3c76aabb1", ], - "version": "==0.9.0" + "version": "==0.9.0", }, "platformdirs": { "hashes": [ "sha256:027d8e83a2d7de06bbac4e5ef7e023c02b863d7ea5d079477e722bb41ab25788", - "sha256:58c8abb07dcb441e6ee4b11d8df0ac856038f944ab98b7be6b27b2a3c7feef19" + "sha256:58c8abb07dcb441e6ee4b11d8df0ac856038f944ab98b7be6b27b2a3c7feef19", ], "markers": "python_version >= '3.7'", - "version": "==2.5.2" + "version": "==2.5.2", }, "pyasn1": { "hashes": [ @@ -587,9 +581,9 @@ "sha256:a9495356ca1d66ed197a0f72b41eb1823cf7ea8b5bd07191673e8147aecf8604", "sha256:bcac468e38d16e94fee4c8f76eef1feb9a06a911e93465f2351a4140fa66d303", "sha256:c39d11c72f0e5e71faa35c8c8ef5ee9b810ec99a3c64f05133f1325fe5636bba", - "sha256:f124185ccc1c1c5e782aa58d46bc28be279673a482334d70de6735d05d8b4b10" + "sha256:f124185ccc1c1c5e782aa58d46bc28be279673a482334d70de6735d05d8b4b10", ], - "version": "==0.4.7" + "version": "==0.4.7", }, "pyasn1-modules": { "hashes": [ @@ -605,144 +599,142 @@ "sha256:9ca5e376a6d9dee35bb3a62608dfa2e6698798aa6b8db3c7afd0eb31af0d63c7", "sha256:b6ada4f840fe51abf5a6bd545b45bf537bea62221fa0dde2e8a553ed9f06a4e3", "sha256:c14b107a67ee36a7f183ae9f4803ffde4a03b67f3192eab0a62e851af71371d3", - "sha256:eaf35047a0b068e3e0c2a99618b13b65c98c329661daa78c9d44a4ef0fe8139e" + "sha256:eaf35047a0b068e3e0c2a99618b13b65c98c329661daa78c9d44a4ef0fe8139e", ], - "version": "==0.2.7" + "version": "==0.2.7", }, "pycparser": { "hashes": [ "sha256:8ee45429555515e1f6b185e78100aea234072576aa43ab53aefcae078162fca9", - "sha256:e644fdec12f7872f86c58ff790da456218b10f863970249516d60a5eaca77206" + "sha256:e644fdec12f7872f86c58ff790da456218b10f863970249516d60a5eaca77206", ], - "version": "==2.21" + "version": "==2.21", }, "pyopenssl": { "hashes": [ "sha256:660b1b1425aac4a1bea1d94168a85d99f0b3144c869dd4390d27629d0087f1bf", - "sha256:ea252b38c87425b64116f808355e8da644ef9b07e429398bfece610f893ee2e0" + "sha256:ea252b38c87425b64116f808355e8da644ef9b07e429398bfece610f893ee2e0", ], "markers": "python_version >= '3.6'", - "version": "==22.0.0" + "version": "==22.0.0", }, "pyright": { "hashes": [ "sha256:2ccb43792e03a1af1da406b7dcf12212d4671b6b14cda3a0492e2b40e252b24f", - "sha256:3ac37f74588f4dab35da48398727f79ebc90c703ad0230f95c006ef158d63d30" + "sha256:3ac37f74588f4dab35da48398727f79ebc90c703ad0230f95c006ef158d63d30", ], "index": "pypi", - "version": "==1.1.246" + "version": "==1.1.246", }, "python-dateutil": { "hashes": [ "sha256:0123cacc1627ae19ddf3c27a5de5bd67ee4586fbdd6440d9748f8abb483d3e86", - "sha256:961d03dc3453ebbc59dbdea9e4e11c5651520a876d0f4db161e8674aae935da9" + "sha256:961d03dc3453ebbc59dbdea9e4e11c5651520a876d0f4db161e8674aae935da9", ], "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'", - "version": "==2.8.2" + "version": "==2.8.2", }, "pytz": { "hashes": [ "sha256:1e760e2fe6a8163bc0b3d9a19c4f84342afa0a2affebfaa84b01b978a02ecaa7", - "sha256:e68985985296d9a66a881eb3193b0906246245294a881e7c8afe623866ac6a5c" + "sha256:e68985985296d9a66a881eb3193b0906246245294a881e7c8afe623866ac6a5c", ], - "version": "==2022.1" + "version": "==2022.1", }, "pytz-deprecation-shim": { "hashes": [ "sha256:8314c9692a636c8eb3bda879b9f119e350e93223ae83e70e80c31675a0fdc1a6", - "sha256:af097bae1b616dde5c5744441e2ddc69e74dfdcb0c263129610d85b87445a59d" + "sha256:af097bae1b616dde5c5744441e2ddc69e74dfdcb0c263129610d85b87445a59d", ], "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4, 3.5'", - "version": "==0.1.0.post0" + "version": "==0.1.0.post0", }, "rfc3986": { - "extras": [ - "idna2008" - ], + "extras": ["idna2008"], "hashes": [ "sha256:270aaf10d87d0d4e095063c65bf3ddbc6ee3d0b226328ce21e036f946e421835", - "sha256:a86d6e1f5b1dc238b218b012df0aa79409667bb209e58da56d0b94704e712a97" + "sha256:a86d6e1f5b1dc238b218b012df0aa79409667bb209e58da56d0b94704e712a97", ], - "version": "==1.5.0" + "version": "==1.5.0", }, "singletonify": { "hashes": [ "sha256:51e8d6c895d8de72d126e0b523f3c34817442201245da517c91c4a29d82ad133", - "sha256:e04ba8278b3dee3d46877482cef9682f7d5df9bd305722f6828a49bbeb9a4def" + "sha256:e04ba8278b3dee3d46877482cef9682f7d5df9bd305722f6828a49bbeb9a4def", ], - "version": "==0.2.3" + "version": "==0.2.3", }, "six": { "hashes": [ "sha256:1e61c37477a1626458e36f7b1d82aa5c9b094fa4802892072e49de9c60c4c926", - "sha256:8abb2f1d86890a2dfb989f9a77cfcfd3e47c2a354b01111771326f8aa26e0254" + "sha256:8abb2f1d86890a2dfb989f9a77cfcfd3e47c2a354b01111771326f8aa26e0254", ], "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'", - "version": "==1.16.0" + "version": "==1.16.0", }, "sniffio": { "hashes": [ "sha256:471b71698eac1c2112a40ce2752bb2f4a4814c22a54a3eed3676bc0f5ca9f663", - "sha256:c4666eecec1d3f50960c6bdf61ab7bc350648da6c126e3cf6898d8cd4ddcd3de" + "sha256:c4666eecec1d3f50960c6bdf61ab7bc350648da6c126e3cf6898d8cd4ddcd3de", ], "markers": "python_version >= '3.5'", - "version": "==1.2.0" + "version": "==1.2.0", }, "sortedcollections": { "hashes": [ "sha256:b07abbc73472cc459da9dd6e2607d73d1f3b9309a32dd9a57fa2c6fa882f4c6c", - "sha256:d8e9609d6c580a16a1224a3dc8965789e03ebc4c3e5ffd05ada54a2fed5dcacd" + "sha256:d8e9609d6c580a16a1224a3dc8965789e03ebc4c3e5ffd05ada54a2fed5dcacd", ], - "version": "==2.1.0" + "version": "==2.1.0", }, "sortedcontainers": { "hashes": [ "sha256:25caa5a06cc30b6b83d11423433f65d1f9d76c4c6a0c90e3379eaa43b9bfdb88", - "sha256:a163dcaede0f1c021485e957a39245190e74249897e2ae4b2aa38595db237ee0" + "sha256:a163dcaede0f1c021485e957a39245190e74249897e2ae4b2aa38595db237ee0", ], - "version": "==2.4.0" + "version": "==2.4.0", }, "spade": { "git": "https://github.com/agent-based-information-flow-simulation/spade", - "ref": "6a857c2ae0a86b3bdfd20ccfcd28a11e1c6db81e" + "ref": "6a857c2ae0a86b3bdfd20ccfcd28a11e1c6db81e", }, "timeago": { "hashes": [ "sha256:f2acf144a9aabbc1e46a7f84387e6dd17bf41ff5fd87822c878621d06ef6b77c" ], - "version": "==1.0.8" + "version": "==1.0.8", }, "tomli": { "hashes": [ "sha256:939de3e7a6161af0c887ef91b7d41a53e7c5a1ca976325f429cb46ea9bc30ecc", - "sha256:de526c12914f0c550d15924c62d72abc48d6fe7364aa87328337a31007fe8a4f" + "sha256:de526c12914f0c550d15924c62d72abc48d6fe7364aa87328337a31007fe8a4f", ], "markers": "python_version < '3.11'", - "version": "==2.0.1" + "version": "==2.0.1", }, "typing-extensions": { "hashes": [ "sha256:6657594ee297170d19f67d55c05852a874e7eb634f4f753dbd667855e07c1708", - "sha256:f1c24655a0da0d1b67f07e17a5e6b2a105894e6824b92096378bb3668ef02376" + "sha256:f1c24655a0da0d1b67f07e17a5e6b2a105894e6824b92096378bb3668ef02376", ], "markers": "python_version >= '3.7'", - "version": "==4.2.0" + "version": "==4.2.0", }, "tzdata": { "hashes": [ "sha256:238e70234214138ed7b4e8a0fab0e5e13872edab3be586ab8198c407620e2ab9", - "sha256:8b536a8ec63dc0751342b3984193a3118f8fca2afe25752bb9b7fffd398552d3" + "sha256:8b536a8ec63dc0751342b3984193a3118f8fca2afe25752bb9b7fffd398552d3", ], "markers": "python_version >= '3.6'", - "version": "==2022.1" + "version": "==2022.1", }, "tzlocal": { "hashes": [ "sha256:89885494684c929d9191c57aa27502afc87a579be5cdd3225c77c463ea043745", - "sha256:ee5842fa3a795f023514ac2d801c4a81d1743bbe642e3940143326b3a00addd7" + "sha256:ee5842fa3a795f023514ac2d801c4a81d1743bbe642e3940143326b3a00addd7", ], "markers": "python_version >= '3.6'", - "version": "==4.2" + "version": "==4.2", }, "yarl": { "hashes": [ @@ -817,10 +809,10 @@ "sha256:f64394bd7ceef1237cc604b5a89bf748c95982a84bcd3c4bbeb40f685c810794", "sha256:fc4dd8b01a8112809e6b636b00f487846956402834a7fd59d46d4f4267181c41", "sha256:fce78593346c014d0d986b7ebc80d782b7f5e19843ca798ed62f8e3ba8728576", - "sha256:fd547ec596d90c8676e369dd8a581a21227fe9b4ad37d0dc7feb4ccf544c2d59" + "sha256:fd547ec596d90c8676e369dd8a581a21227fe9b4ad37d0dc7feb4ccf544c2d59", ], "markers": "python_version >= '3.6'", - "version": "==1.7.2" - } - } + "version": "==1.7.2", + }, + }, } diff --git a/examples/EXAMPLES.md b/examples/EXAMPLES.md new file mode 100644 index 0000000..7f722a6 --- /dev/null +++ b/examples/EXAMPLES.md @@ -0,0 +1,16 @@ +# Examples + +The examples provided are supposed to illustrate the usage of AASM as a language. + +## Facebook + +The facebook simulations showcase basic functionalities of AASM, namely minimal example of sending and receiving parametrised messages. +Two versions are provided, with and without macro usage. + +## Wolfsheep + +A more complex simulation, showcasing computational capabilities of AASM, as well as advanced state management. +The simulation has been inspired by the [Wolf Sheep simple](http://www.netlogoweb.org/launch#http://www.netlogoweb.org/assets/modelslib/IABM%20Textbook/chapter%204/Wolf%20Sheep%20Simple%205.nlogo) 5 example from NetLogo. + +## More coming soon... + diff --git a/examples/facebook.aasm b/examples/facebook.aasm index a81d8bb..6a3bc6d 100644 --- a/examples/facebook.aasm +++ b/examples/facebook.aasm @@ -2,8 +2,20 @@ message facebook_post, query prm photos, float emessage -agent average_user +agent user prm friends, list, conn + prm num_seen_photos, float, init, 0 + + behav initialize, setup + action initialize_friends, modify_self + decl max_friends, float, 0 + len max_friends, connections + decl num_friends, float, 0 + rand num_friends, int, uniform, 0, max_friends + subs friends, connections, num_friends + eaction + ebehav + behav facebook_activity, cyclic, 30 action post_photos, send_msg, facebook_post, query decl num_photos, float, 0 @@ -12,12 +24,14 @@ agent average_user send friends eaction ebehav + + behav read_posts, msg_rcv, facebook_post, query + action update_seen_photos, modify_self + add num_seen_photos, rcv.photos + eaction + ebehav eagent -graph matrix - SCALE 3 - DEFNODE average_user, R0110 - DEFNODE average_user, R1011 - DEFNODE average_user, R1100 - DEFNODE average_user, R1000 +graph statistical + defg user, 15, dist_exp, 0.1 egraph diff --git a/examples/facebook.py b/examples/facebook.py deleted file mode 100644 index 253a482..0000000 --- a/examples/facebook.py +++ /dev/null @@ -1,145 +0,0 @@ -import copy -import datetime -import random -import httpx -import numpy -import orjson -import spade -import sys - - -class average_user(spade.agent.Agent): - def __init__(self, jid, password, backup_method = None, backup_queue = None, backup_url = None, backup_period = 60, backup_delay = 0, logger = None, **kwargs): - super().__init__(jid, password, verify_security=False) - if logger: logger.debug(f'[{jid}] Received parameters: jid: {jid}, password: {password}, backup_method: {backup_method}, backup_queue: {backup_queue}, backup_url: {backup_url}, backup_period: {backup_period}, backup_delay: {backup_delay}, kwargs: {kwargs}') - self.logger = logger - self.backup_method = backup_method - self.backup_queue = backup_queue - self.backup_url = backup_url - self.backup_period = backup_period - self.backup_delay = backup_delay - self.connections = kwargs.get("connections", []) - self.msgRCount = self.limit_number(kwargs.get("msgRCount", 0)) - self.msgSCount = self.limit_number(kwargs.get("msgSCount", 0)) - self.friends = kwargs.get("friends", []) - if self.logger: self.logger.debug(f'[{self.jid}] Class dict after initialization: {self.__dict__}') - - @property - def connCount(self): - return self.limit_number(len(self.connections)) - - def limit_number(self, value): - return float(max(-2147483648, min(value, 2147483647))) - - def get_json_from_spade_message(self, msg): - return orjson.loads(msg.body) - - def get_spade_message(self, receiver_jid, body): - msg = spade.message.Message(to=receiver_jid) - body["sender"] = str(self.jid) - msg.metadata["type"] = body["type"] - msg.metadata["performative"] = body["performative"] - msg.body = str(orjson.dumps(body), encoding="utf-8") - return msg - - def setup(self): - if self.backup_method is not None: - BackupBehaviour_template = spade.template.Template() - BackupBehaviour_template.set_metadata("reserved", "no_message_match") - self.add_behaviour(self.BackupBehaviour(start_at=datetime.datetime.now() + datetime.timedelta(seconds=self.backup_delay), period=self.backup_period), BackupBehaviour_template) - facebook_activity_template = spade.template.Template() - facebook_activity_template.set_metadata("reserved", "no_message_match") - self.add_behaviour(self.facebook_activity(period=30), facebook_activity_template) - if self.logger: self.logger.debug(f'[{self.jid}] Class dict after setup: {self.__dict__}') - - class BackupBehaviour(spade.behaviour.PeriodicBehaviour): - def __init__(self, start_at, period): - super().__init__(start_at=start_at, period=period) - self.http_client = httpx.AsyncClient(timeout=period) - - async def run(self): - data = { - "__timestamp__": int(datetime.datetime.timestamp(datetime.datetime.utcnow())), - "jid": str(self.agent.jid), - "type": "average_user", - "floats": { - "msgRCount": self.agent.msgRCount, - "msgSCount": self.agent.msgSCount, - "connCount": self.agent.connCount, - }, - "enums": { - }, - "connections": { - "connections": self.agent.connections, - "friends": self.agent.friends, - }, - "messages": { - }, - "float_lists": { - }, - } - if self.agent.backup_method == 'http': - if self.agent.logger: self.agent.logger.debug(f'[{self.agent.jid}] Sending backup data with http: {data}') - try: - await self.http_client.post(self.agent.backup_url, headers={"Content-Type": "application/json"}, data=orjson.dumps(data)) - except Exception as e: - if self.agent.logger: self.agent.logger.error(f'[{self.agent.jid}] Backup error type: {e.__class__}, additional info: {e}') - elif self.agent.backup_method == 'queue': - if self.agent.logger: self.agent.logger.debug(f'[{self.agent.jid}] Sending backup data with queue: {data}') - try: - await self.agent.backup_queue.coro_put(data) - except Exception as e: - if self.agent.logger: self.agent.logger.error(f'[{self.agent.jid}] Backup error type: {e.__class__}, additional info: {e}') - else: - if self.agent.logger: self.agent.logger.warning(f'[{self.agent.jid}] Unknown backup method: {self.agent.backup_method}') - - class facebook_activity(spade.behaviour.PeriodicBehaviour): - async def post_photos(self): - if self.agent.logger: self.agent.logger.debug(f'[{self.agent.jid}] Run action post_photos') - send = { "type": "facebook_post", "performative": "query", "photos": 0.0, } - - # float declaration - num_photos = self.agent.limit_number(0) - - # uniform distribution - num_photos = self.agent.limit_number(random.uniform(self.agent.limit_number(21), self.agent.limit_number(37))) - - # round - num_photos = self.agent.limit_number(round(self.agent.limit_number(num_photos))) - - # set - send["photos"] = self.agent.limit_number(num_photos) - - # send - if self.agent.logger: self.agent.logger.debug(f'[{self.agent.jid}] Send message {send} to {self.agent.friends}') - for receiver in self.agent.friends: - await self.send(self.agent.get_spade_message(receiver, send)) - self.agent.msgSCount = self.agent.limit_number(self.agent.msgSCount + 1) - - async def run(self): - await self.post_photos() - - -import random -import uuid -import numpy - - -def generate_graph_structure(domain): - _num_average_user = round(100 / 100 * 150) - num_agents = _num_average_user - random_id = str(uuid.uuid4())[:5] - jids = [f"{i}_{random_id}@{domain}" for i in range(num_agents)] - agents = [] - next_agent_idx = 0 - for _ in range(_num_average_user): - num_connections = int(numpy.random.exponential(1 / 0.1)) - num_connections = max(min(num_connections, len(jids) - 1), 0) - jid = jids[next_agent_idx] - agents.append({ - "jid": jid, - "type": "average_user", - "connections": random.sample([other_jid for other_jid in jids if other_jid != jid], num_connections), - }) - next_agent_idx += 1 - return agents diff --git a/examples/facebook_macro.aasm b/examples/facebook_macro.aasm index be4698a..532d81d 100644 --- a/examples/facebook_macro.aasm +++ b/examples/facebook_macro.aasm @@ -10,7 +10,19 @@ message facebook_post, query emessage agent average_user + prm num_seen_photos, float, init, 0 prm friends, list, conn + + behav initialize, setup + action initialize_friends, modify_self + decl max_friends, float, 0 + len max_friends, connections + decl num_friends, float, 0 + rand num_friends, int, uniform, 0, max_friends + subs friends, connections, num_friends + eaction + ebehav + behav facebook_activity, cyclic, 30 action post_photos, send_msg, facebook_post, query randint, num_photos, 1, 5 @@ -19,6 +31,12 @@ agent average_user send friends eaction ebehav + + behav read_posts, msg_rcv, facebook_post, query + action update_seen_photos, modify_self + add num_seen_photos, rcv.photos + eaction + ebehav eagent graph statistical diff --git a/examples/facebook_macro.py b/examples/facebook_macro.py deleted file mode 100644 index 8dce1b6..0000000 --- a/examples/facebook_macro.py +++ /dev/null @@ -1,134 +0,0 @@ -import copy -import datetime -import random -import httpx -import numpy -import orjson -import spade -import sys - - -class average_user(spade.agent.Agent): - def __init__(self, jid, password, backup_url = None, backup_period = 60, backup_delay = 0, logger = None, **kwargs): - super().__init__(jid, password, verify_security=False) - if logger: logger.debug(f'[{jid}] Received parameters: jid: {jid}, password: {password}, backup_url: {backup_url}, backup_period: {backup_period}, backup_delay: {backup_delay}, kwargs: {kwargs}') - self.logger = logger - self.backup_url = backup_url - self.backup_period = backup_period - self.backup_delay = backup_delay - self.connections = kwargs.get("connections", []) - self.msgRCount = self.limit_number(kwargs.get("msgRCount", 0)) - self.msgSCount = self.limit_number(kwargs.get("msgSCount", 0)) - self.friends = kwargs.get("friends", []) - if self.logger: self.logger.debug(f'[{self.jid}] Class dict after initialization: {self.__dict__}') - - @property - def connCount(self): - return self.limit_number(len(self.connections)) - - def limit_number(self, value): - return float(max(-2147483648, min(value, 2147483647))) - - def get_json_from_spade_message(self, msg): - return orjson.loads(msg.body) - - def get_spade_message(self, receiver_jid, body): - msg = spade.message.Message(to=receiver_jid) - body["sender"] = str(self.jid) - msg.metadata["type"] = body["type"] - msg.metadata["performative"] = body["performative"] - msg.body = str(orjson.dumps(body), encoding="utf-8") - return msg - - def setup(self): - if self.backup_url: - BackupBehaviour_template = spade.template.Template() - BackupBehaviour_template.set_metadata("reserved", "no_message_match") - self.add_behaviour(self.BackupBehaviour(start_at=datetime.datetime.now() + datetime.timedelta(seconds=self.backup_delay), period=self.backup_period), BackupBehaviour_template) - facebook_activity_template = spade.template.Template() - facebook_activity_template.set_metadata("reserved", "no_message_match") - self.add_behaviour(self.facebook_activity(period=30), facebook_activity_template) - if self.logger: self.logger.debug(f'[{self.jid}] Class dict after setup: {self.__dict__}') - - class BackupBehaviour(spade.behaviour.PeriodicBehaviour): - def __init__(self, start_at, period): - super().__init__(start_at=start_at, period=period) - self.http_client = httpx.AsyncClient(timeout=period) - - async def run(self): - data = { - "__timestamp__": int(datetime.datetime.timestamp(datetime.datetime.utcnow())), - "jid": str(self.agent.jid), - "type": "average_user", - "floats": { - "msgRCount": self.agent.msgRCount, - "msgSCount": self.agent.msgSCount, - "connCount": self.agent.connCount, - }, - "enums": { - }, - "connections": { - "connections": self.agent.connections, - "friends": self.agent.friends, - }, - "messages": { - }, - "float_lists": { - }, - } - if self.agent.logger: self.agent.logger.debug(f'[{self.agent.jid}] Sending backup data: {data}') - try: - await self.http_client.post(self.agent.backup_url, headers={"Content-Type": "application/json"}, data=orjson.dumps(data)) - except Exception as e: - if self.agent.logger: self.agent.logger.error(f'[{self.agent.jid}] Backup error type: {e.__class__}, additional info: {e}') - - class facebook_activity(spade.behaviour.PeriodicBehaviour): - async def post_photos(self): - if self.agent.logger: self.agent.logger.debug(f'[{self.agent.jid}] Run action post_photos') - send = { "type": "facebook_post", "performative": "query", "photos": 0.0, } - - # declaration - num_photos = self.agent.limit_number(0) - - # uniform distribution - num_photos = self.agent.limit_number(random.uniform(self.agent.limit_number(21), self.agent.limit_number(37))) - - # round - num_photos = self.agent.limit_number(round(self.agent.limit_number(num_photos))) - - # set - send["photos"] = self.agent.limit_number(num_photos) - - # send - if self.agent.logger: self.agent.logger.debug(f'[{self.agent.jid}] Send message {send} to {self.agent.friends}') - for receiver in self.agent.friends: - await self.send(self.agent.get_spade_message(receiver, send)) - self.agent.msgSCount = self.agent.limit_number(self.agent.msgSCount + 1) - - async def run(self): - await self.post_photos() - - -import random -import uuid -import numpy - - -def generate_graph_structure(domain): - _num_average_user = round(100 / 100 * 150) - num_agents = _num_average_user - random_id = str(uuid.uuid4())[:5] - jids = [f"{i}_{random_id}@{domain}" for i in range(num_agents)] - agents = [] - next_agent_idx = 0 - for _ in range(_num_average_user): - num_connections = int(numpy.random.exponential(1 / 0.1)) - num_connections = max(min(num_connections, len(jids) - 1), 0) - jid = jids[next_agent_idx] - agents.append({ - "jid": jid, - "type": "average_user", - "connections": random.sample([other_jid for other_jid in jids if other_jid != jid], num_connections), - }) - next_agent_idx += 1 - return agents diff --git a/examples/facebook_macro_error_1.aasm b/examples/facebook_macro_error_1.aasm deleted file mode 100644 index fa2c2ea..0000000 --- a/examples/facebook_macro_error_1.aasm +++ /dev/null @@ -1,26 +0,0 @@ -%makro randint name, a, b - decl name, 0 - rand name, int, uniform, a, b -%emakro - -message facebook_post, query - prm photos, float -emessage - -agent average_user - prm friends, list, conn - behav facebook_activity, cyclic, 30 - action post_photos, send_msg, facebook_post, query - randint num_photos, 21, 37 - set send.photos, num_photos - randint kappa, 21, 37 - send friends - randint zonk, 21, 37 - eaction - ebehav -eagent - -grph statistical - size 150 - defg average_user, 100%, dist_exp, 0.1 -egraph diff --git a/examples/fptp.aasm b/examples/fptp.aasm deleted file mode 100644 index e69de29..0000000 diff --git a/examples/wolfsheep.aasm b/examples/wolfsheep.aasm index a770c63..50f5d38 100644 --- a/examples/wolfsheep.aasm +++ b/examples/wolfsheep.aasm @@ -8,28 +8,29 @@ MESSAGE eat, Inform EMESSAGE MESSAGE broadcast, Inform - PRM type, float # 0 - field, 1 - sheep, 2 - wolf + # 0 - field, 1 - sheep, 2 - wolf + PRM typ, float PRM state, float EMESSAGE MESSAGE spawn, Inform - PRM type, float + PRM typ, float EMESSAGE MESSAGE kill, Inform EMESSAGE AGENT grass - PRM field, list, float, 10000, 0 + PRM field, list, float PRM dead_sheep, list, conn PRM alive_sheep, list, conn PRM dead_wolf, list, conn PRM alive_wolf, list, conn - PRM spawn_candidate, list, conn - BEHAV setup, setup + PRM spawn_target, list, conn + BEHAV initialize, setup ACTION setup_field, modify_self - DECL it, 0 - DECL amt, 0 + DECL it, float, 0 + DECL amt, float, 0 WLT it, 10000 RAND amt, float, uniform, 0, 10 LW field, it, amt @@ -37,60 +38,63 @@ AGENT grass EBLOCK EACTION ACTION broadcast, send_msg, broadcast, Inform - SET SEND.type, 0 + SET SEND.typ, 0 SEND connections EACTION EBEHAV BEHAV recv_spawn, msg_rcv, spawn, Inform ACTION choose_spawn, modify_self - CLR spawn_candidate - IEQ RCV.type, 1 - SUBS spawn_candidate, dead_sheep, 1 + CLR spawn_target + DECL spawn_candidate, conn, "0" + IEQ RCV.typ, 1 + LR spawn_candidate, dead_sheep, 0 REME dead_sheep, spawn_candidate - ADDE alive_wolf, spawn_candidate + ADDE alive_sheep, spawn_candidate + ADDE spawn_target, spawn_candidate EBLOCK - IEQ RCV.type, 2 - SUBS spawn_candidate, dead_wolf, 1 + IEQ RCV.typ, 2 + LR spawn_candidate, dead_wolf, 0 REME dead_wolf, spawn_candidate ADDE alive_wolf, spawn_candidate + ADDE spawn_target, spawn_candidate EBLOCK EACTION ACTION spawn, send_msg, spawn, Inform - SEND spawn_candidate + SEND spawn_target EACTION EBEHAV BEHAV recv_broadcast, msg_rcv, broadcast, Inform ACTION add_agent, modify_self - IEQ RCV.type, 1 + IEQ RCV.typ, 1 IEQ RCV.state, 0 - REME alive_sheep, RCV.jid - ADDE dead_sheep, RCV.jid + REME alive_sheep, RCV.sender + ADDE dead_sheep, RCV.sender EBLOCK IEQ RCV.state, 1 - REME dead_sheep, RCV.jid - ADDE alive_sheep, RCV.jid + REME dead_sheep, RCV.sender + ADDE alive_sheep, RCV.sender EBLOCK EBLOCK - IEQ RCV.type, 2 + IEQ RCV.typ, 2 IEQ RCV.state, 0 - REME alive_wolf, RCV.jid - ADDE dead_wolf, RCV.jid + REME alive_wolf, RCV.sender + ADDE dead_wolf, RCV.sender EBLOCK IEQ RCV.state, 1 - REME dead_wolf, RCV.jid - ADDE alive_wolf, RCV.jid + REME dead_wolf, RCV.sender + ADDE alive_wolf, RCV.sender EBLOCK EBLOCK EACTION EBEHAV BEHAV eat_grass, msg_rcv, eat, Request ACTION parse_eat, send_msg, eat, Inform - DECL index, RCV.x + DECL index, float, RCV.x MULT index, 10 ADD index, RCV.y - DECL grass_val, 0 - LR grass_val, field, it - DECL send_flag, 0 + DECL grass_val, float, 0 + LR grass_val, field, index + DECL send_flag, float, 0 IGT grass_val, 1 SET send_flag, 1 SET SEND.energy, 1 @@ -100,13 +104,13 @@ AGENT grass IEQ send_flag, 0 SET SEND.energy, 0 EBLOCK - SEND RCV.jid + SEND RCV.sender EACTION EBEHAV BEHAV regrow_grass, cyclic, 10 ACTION regrow, modify_self - DECL it, 0 - DECL amt, 0 + DECL it, float, 0 + DECL amt, float, 0 WLT it, 10000 LR amt, field, it ADD amt, 0.1 @@ -120,9 +124,9 @@ AGENT grass EBEHAV BEHAV recv_kill, msg_rcv, kill, Inform ACTION kill_creature, modify_self - IN alive_sheep, RCV.jid + IN alive_sheep, RCV.sender EBLOCK - IN alive_wolf, RCV.jid + IN alive_wolf, RCV.sender EBLOCK EACTION EBEHAV @@ -150,9 +154,9 @@ AGENT sheep EACTION EBEHAV - BEHAV setup, setup + BEHAV initialize, setup ACTION broadcast, send_msg, broadcast, Inform - SET SEND.type, 1 + SET SEND.typ, 1 IEQ dead, YES SET SEND.state, 0 EBLOCK @@ -166,11 +170,11 @@ AGENT sheep BEHAV move_around, cyclic, 10 ACTION wiggle, modify_self IEQ dead, NO - DECL wiglR, 0 - DECL wiglL, 0 + DECL wiglR, float, 0 + DECL wiglL, float, 0 RAND wiglR, float, uniform, 0, 90 RAND wiglL, float, uniform, 0, 90 - DECL change_flag, 0 + DECL change_flag, float, 0 IEQ invert, YES SET change_flag, 1 ADD heading, wiglL @@ -202,25 +206,14 @@ AGENT sheep EACTION # wiggle ACTION move, modify_self IEQ dead, NO - DECL sin, 0 - DECL numerator, 180 - DECL denumerator, 40500 - SUBT numerator, x - MULT numerator, x - MULT numerator, 4 - DECL tmp, 180 - SUBT tmp, x - MULT tmp, x - SUBT denumerator, tmp - SET sin, numerator - DIV sin, denumerator # Bhaskara I sin approximation - DECL a, sin - DECL b, 1 - MULT a, a - SUBT b, a - SET a, sin - DECL newx, x - DECL newy, y + DECL a, float, 0 + DECL b, float, 0 + SIN a, heading + COS b, heading + MULT a, 10 + MULT b, 10 + DECL newx, float, x + DECL newy, float, y IGT heading, 90 SUBT newx, a EBLOCK @@ -233,7 +226,7 @@ AGENT sheep IEQ invert, NO ADD newy, b EBLOCK - DECL bump, 0 + DECL bump, float, 0 ILT newx, 0 SET bump, 1 EBLOCK @@ -255,7 +248,7 @@ AGENT sheep ADD heading, 90 IGT heading, 180 SUBT heading, 180 - DECL flag, 0 + DECL flag, float, 0 IEQ invert, YES SET flag, 1 SET invert, NO @@ -285,8 +278,8 @@ AGENT sheep BEHAV reproduce, cyclic, 20 ACTION hatch, send_msg, spawn, Inform IEQ dead, NO - IEQ energy > 100 - SET SEND.type, 1 + IGTEQ energy, 100 + SET SEND.typ, 1 SEND field EBLOCK EBLOCK @@ -294,22 +287,24 @@ AGENT sheep EBEHAV BEHAV grass_eat, msg_rcv, eat, Inform ACTION change_energy, modify_self - ADD energy, SEND.energy + ADD energy, RCV.energy EACTION EBEHAV - BEHAV recv_broadcast, broadcast, Inform - IEQ RCV.type, 0 - ADDE field, RCV.jid - EBLOCK + BEHAV recv_broadcast, msg_rcv, broadcast, Inform + ACTION parse_broadcast, modify_self + IEQ RCV.typ, 0 + ADDE field, RCV.sender + EBLOCK + EACTION EBEHAV - BEHAV get_eaten_request, eat, Request - ACTION send_msg, eat, Inform + BEHAV get_eaten_request, msg_rcv, eat, Request + ACTION send_eat, send_msg, eat, Inform IEQ dead, NO - DECL lowx, x - DECL lowy, y - DECL highx, x - DECL highy, y + DECL lowx, float, x + DECL lowy, float, y + DECL highx, float, x + DECL highy, float, y SUBT lowx, 1 SUBT lowy, 1 @@ -321,7 +316,7 @@ AGENT sheep IGT lowx, RCV.x IGT lowy, RCV.y SET SEND.energy, 1 - SEND RCV.jid + SEND RCV.sender EBLOCK EBLOCK EBLOCK @@ -349,9 +344,9 @@ AGENT wolf EACTION EBEHAV - BEHAV setup, setup + BEHAV initialize, setup ACTION broadcast, send_msg, broadcast, Inform - SET SEND.type, 2 + SET SEND.typ, 2 IEQ dead, YES SET SEND.state, 0 EBLOCK @@ -364,11 +359,11 @@ AGENT wolf BEHAV move_around, cyclic, 10 ACTION wiggle, modify_self IEQ dead, NO - DECL wiglR, 0 - DECL wiglL, 0 + DECL wiglR, float, 0 + DECL wiglL, float, 0 RAND wiglR, float, uniform, 0, 90 RAND wiglL, float, uniform, 0, 90 - DECL change_flag, 0 + DECL change_flag, float, 0 IEQ invert, YES SET change_flag, 1 ADD heading, wiglL @@ -400,25 +395,14 @@ AGENT wolf EACTION # wiggle ACTION move, modify_self IEQ dead, NO - DECL sin, 0 - DECL numerator, 180 - DECL denumerator, 40500 - SUBT numerator, x - MULT numerator, x - MULT numerator, 4 - DECL tmp, 180 - SUBT tmp, x - MULT tmp, x - SUBT denumerator, tmp - SET sin, numerator - DIV sin, denumerator # Bhaskara I sin approximation - DECL a, sin - DECL b, 1 - MULT a, a - SUBT b, a - SET a, sin - DECL newx, x - DECL newy, y + DECL a, float, 0 + DECL b, float, 0 + SIN a, heading + COS b, heading + MULT a, 10 + MULT b, 10 + DECL newx, float, x + DECL newy, float, y IGT heading, 90 SUBT newx, a EBLOCK @@ -431,7 +415,7 @@ AGENT wolf IEQ invert, NO ADD newy, b EBLOCK - DECL bump, 0 + DECL bump, float, 0 ILT newx, 0 SET bump, 1 EBLOCK @@ -453,7 +437,7 @@ AGENT wolf ADD heading, 90 IGT heading, 180 SUBT heading, 180 - DECL flag, 0 + DECL flag, float, 0 IEQ invert, YES SET flag, 1 SET invert, NO @@ -483,17 +467,18 @@ AGENT wolf ACTION eat_sheep, send_msg, kill, Inform IEQ is_eating, YES SET is_eating, NO - SEND RCV.jid + SEND RCV.sender EBLOCK EACTION EBEHAV BEHAV recv_broadcast, msg_rcv, broadcast, Inform - IEQ RCV.type, 0 - ADDE field, RCV.jid - EBLOCK - IEQ RCV.type, 1 - ADDE sheep, RCV.jid - EBLOCK + ACTION parse_broadcast, modify_self + IEQ RCV.typ, 0 + ADDE field, RCV.sender + EBLOCK + IEQ RCV.typ, 1 + ADDE sheep, RCV.sender + EBLOCK + EACTION EBEHAV EAGENT - diff --git a/examples/wolfsheep_macro.aasm b/examples/wolfsheep_macro.aasm index ffb321e..4283fd1 100644 --- a/examples/wolfsheep_macro.aasm +++ b/examples/wolfsheep_macro.aasm @@ -140,7 +140,7 @@ AGENT grass PRM alive_sheep, list, conn PRM dead_wolf, list, conn PRM alive_wolf, list, conn - PRM spawn_candidate, list, conn + PRM spawn_target, list, conn BEHAV initilise, setup ACTION setup_field, modify_self DECL it, float, 0 @@ -158,36 +158,39 @@ AGENT grass EBEHAV BEHAV recv_spawn, msg_rcv, spawn, Inform ACTION choose_spawn, modify_self - CLR spawn_candidate + CLR spawn_target + DECL spawn_candidate, conn, "0" IEQ RCV.typ, sheep_id - SUBS spawn_candidate, dead_sheep, 1 + LR spawn_candidate, dead_sheep, 0 move_to alive_sheep, dead_sheep, spawn_candidate + ADDE spawn_target, spawn_candidate EBLOCK IEQ RCV.typ, wolf_id - SUBS spawn_candidate, dead_wolf, 1 + LR spawn_candidate, dead_wolf, 0 move_to alive_wolf, dead_wolf, spawn_candidate + ADDE spawn_target, spawn_candidate EBLOCK EACTION ACTION spawn, send_msg, spawn, Inform - SEND spawn_candidate + SEND spawn_target EACTION EBEHAV BEHAV recv_broadcast, msg_rcv, broadcast, Inform ACTION add_agent, modify_self IEQ RCV.typ, sheep_id IEQ RCV.state, 0 - move_to dead_sheep, alive_sheep, RCV.jid + move_to dead_sheep, alive_sheep, RCV.sender EBLOCK IEQ RCV.state, 1 - move_to alive_sheep, dead_sheep, RCV.jid + move_to alive_sheep, dead_sheep, RCV.sender EBLOCK EBLOCK IEQ RCV.typ, 2 IEQ RCV.state, 0 - move_to dead_wolf, alive_wolf, RCV.jid + move_to dead_wolf, alive_wolf, RCV.sender EBLOCK IEQ RCV.state, 1 - move_to alive_wolf, dead_wolf, RCV.jid + move_to alive_wolf, dead_wolf, RCV.sender EBLOCK EBLOCK EACTION @@ -209,7 +212,7 @@ AGENT grass IEQ send_flag, 0 SET SEND.energy, 0 EBLOCK - SEND RCV.jid + SEND RCV.sender EACTION EBEHAV BEHAV regrow_grass, cyclic, 10 @@ -229,11 +232,11 @@ AGENT grass EBEHAV BEHAV recv_kill, msg_rcv, kill, Inform ACTION kill_creature, modify_self - IN alive_sheep, RCV.jid - move_to dead_sheep, alive_sheep, RCV.jid + IN alive_sheep, RCV.sender + move_to dead_sheep, alive_sheep, RCV.sender EBLOCK - IN alive_wolf, RCV.jid - move_to dead_wolf, alive_wolf, RCV.jid + IN alive_wolf, RCV.sender + move_to dead_wolf, alive_wolf, RCV.sender EBLOCK EACTION EBEHAV @@ -312,7 +315,7 @@ AGENT sheep BEHAV recv_broadcast, msg_rcv, broadcast, Inform ACTION xd, modify_self IEQ RCV.typ, 0 - ADDE field, RCV.jid + ADDE field, RCV.sender EBLOCK EACTION EBEHAV @@ -335,7 +338,7 @@ AGENT sheep IGT lowx, RCV.x IGT lowy, RCV.y SET SEND.energy, 1 - SEND RCV.jid + SEND RCV.sender EBLOCK EBLOCK EBLOCK @@ -397,23 +400,23 @@ AGENT wolf ACTION eat_sheep, send_msg, kill, Inform IEQ is_eating, YES SET is_eating, NO - SEND RCV.jid + SEND RCV.sender EBLOCK EACTION EBEHAV BEHAV recv_broadcast, msg_rcv, broadcast, Inform ACTION save_data, modify_self IEQ RCV.typ, 0 - ADDE field, RCV.jid + ADDE field, RCV.sender EBLOCK IEQ RCV.typ, 1 - ADDE sheep, RCV.jid + ADDE sheep, RCV.sender EBLOCK EACTION EBEHAV EAGENT -GRPH statistical +GRAPH statistical SIZE graph_size DEFG grass, 1, field_conns DEFG sheep, sheep_amt, field_conns diff --git a/examples/wolfsheep_macro.py b/examples/wolfsheep_macro.py deleted file mode 100644 index f9a2aa7..0000000 --- a/examples/wolfsheep_macro.py +++ /dev/null @@ -1,1408 +0,0 @@ -import copy -import datetime -import random -import httpx -import numpy -import orjson -import spade -import sys - - -class grass(spade.agent.Agent): - def __init__(self, jid, password, backup_url = None, backup_period = 60, backup_delay = 0, logger = None, **kwargs): - super().__init__(jid, password, verify_security=False) - if logger: logger.debug(f'[{jid}] Received parameters: jid: {jid}, password: {password}, backup_url: {backup_url}, backup_period: {backup_period}, backup_delay: {backup_delay}, kwargs: {kwargs}') - self.logger = logger - self.backup_url = backup_url - self.backup_period = backup_period - self.backup_delay = backup_delay - self.connections = kwargs.get("connections", []) - self.msgRCount = self.limit_number(kwargs.get("msgRCount", 0)) - self.msgSCount = self.limit_number(kwargs.get("msgSCount", 0)) - self.dead_sheep = kwargs.get("dead_sheep", []) - self.alive_sheep = kwargs.get("alive_sheep", []) - self.dead_wolf = kwargs.get("dead_wolf", []) - self.alive_wolf = kwargs.get("alive_wolf", []) - self.spawn_candidate = kwargs.get("spawn_candidate", []) - self.field = kwargs.get("field", []) - if self.logger: self.logger.debug(f'[{self.jid}] Class dict after initialization: {self.__dict__}') - - @property - def connCount(self): - return self.limit_number(len(self.connections)) - - def limit_number(self, value): - return float(max(-2147483648, min(value, 2147483647))) - - def get_json_from_spade_message(self, msg): - return orjson.loads(msg.body) - - def get_spade_message(self, receiver_jid, body): - msg = spade.message.Message(to=receiver_jid) - body["sender"] = str(self.jid) - msg.metadata["type"] = body["type"] - msg.metadata["performative"] = body["performative"] - msg.body = str(orjson.dumps(body), encoding="utf-8") - return msg - - def setup(self): - if self.backup_url: - BackupBehaviour_template = spade.template.Template() - BackupBehaviour_template.set_metadata("reserved", "no_message_match") - self.add_behaviour(self.BackupBehaviour(start_at=datetime.datetime.now() + datetime.timedelta(seconds=self.backup_delay), period=self.backup_period), BackupBehaviour_template) - setup_template = spade.template.Template() - setup_template.set_metadata("reserved", "no_message_match") - self.add_behaviour(self.setup(), setup_template) - regrow_grass_template = spade.template.Template() - regrow_grass_template.set_metadata("reserved", "no_message_match") - self.add_behaviour(self.regrow_grass(period=10), regrow_grass_template) - recv_spawn_template = spade.template.Template() - recv_spawn_template.set_metadata("type", "spawn") - recv_spawn_template.set_metadata("performative", "Inform") - self.add_behaviour(self.recv_spawn(), recv_spawn_template) - recv_broadcast_template = spade.template.Template() - recv_broadcast_template.set_metadata("type", "broadcast") - recv_broadcast_template.set_metadata("performative", "Inform") - self.add_behaviour(self.recv_broadcast(), recv_broadcast_template) - eat_grass_template = spade.template.Template() - eat_grass_template.set_metadata("type", "eat") - eat_grass_template.set_metadata("performative", "Request") - self.add_behaviour(self.eat_grass(), eat_grass_template) - recv_kill_template = spade.template.Template() - recv_kill_template.set_metadata("type", "kill") - recv_kill_template.set_metadata("performative", "Inform") - self.add_behaviour(self.recv_kill(), recv_kill_template) - if self.logger: self.logger.debug(f'[{self.jid}] Class dict after setup: {self.__dict__}') - - class BackupBehaviour(spade.behaviour.PeriodicBehaviour): - def __init__(self, start_at, period): - super().__init__(start_at=start_at, period=period) - self.http_client = httpx.AsyncClient(timeout=period) - - async def run(self): - data = { - "__timestamp__": int(datetime.datetime.timestamp(datetime.datetime.utcnow())), - "jid": str(self.agent.jid), - "type": "grass", - "floats": { - "msgRCount": self.agent.msgRCount, - "msgSCount": self.agent.msgSCount, - "connCount": self.agent.connCount, - }, - "enums": { - }, - "connections": { - "connections": self.agent.connections, - "dead_sheep": self.agent.dead_sheep, - "alive_sheep": self.agent.alive_sheep, - "dead_wolf": self.agent.dead_wolf, - "alive_wolf": self.agent.alive_wolf, - "spawn_candidate": self.agent.spawn_candidate, - }, - "messages": { - }, - "float_lists": { - "field": self.agent.field, - }, - } - if self.agent.logger: self.agent.logger.debug(f'[{self.agent.jid}] Sending backup data: {data}') - try: - await self.http_client.post(self.agent.backup_url, headers={"Content-Type": "application/json"}, data=orjson.dumps(data)) - except Exception as e: - if self.agent.logger: self.agent.logger.error(f'[{self.agent.jid}] Backup error type: {e.__class__}, additional info: {e}') - - class setup(spade.behaviour.OneShotBehaviour): - def setup_field(self): - if self.agent.logger: self.agent.logger.debug(f'[{self.agent.jid}] Run action setup_field') - - # float declaration - it = self.agent.limit_number(0) - - # float declaration - amt = self.agent.limit_number(0) - - # while less than - while self.agent.limit_number(it) < self.agent.limit_number(10000): - - # uniform distribution - amt = self.agent.limit_number(random.uniform(self.agent.limit_number(0), self.agent.limit_number(10))) - - # add element - self.agent.field.append(amt) - - # add - it = self.agent.limit_number(it + self.agent.limit_number(1)) - - async def broadcast(self): - if self.agent.logger: self.agent.logger.debug(f'[{self.agent.jid}] Run action broadcast') - send = { "type": "broadcast", "performative": "Inform", "typ": 0.0, "state": 0.0, } - - # set - send["typ"] = self.agent.limit_number(0) - - # send - if self.agent.logger: self.agent.logger.debug(f'[{self.agent.jid}] Send message {send} to {self.agent.connections}') - for receiver in self.agent.connections: - await self.send(self.agent.get_spade_message(receiver, send)) - self.agent.msgSCount = self.agent.limit_number(self.agent.msgSCount + 1) - - async def run(self): - self.setup_field() - await self.broadcast() - - class regrow_grass(spade.behaviour.PeriodicBehaviour): - def regrow(self): - if self.agent.logger: self.agent.logger.debug(f'[{self.agent.jid}] Run action regrow') - - # float declaration - it = self.agent.limit_number(0) - - # float declaration - amt = self.agent.limit_number(0) - - # while less than - while self.agent.limit_number(it) < self.agent.limit_number(10000): - - # list read - if int(self.agent.limit_number(round(self.agent.limit_number(it)))) < 0 or int(self.agent.limit_number(round(self.agent.limit_number(it)))) >= int(self.agent.limit_number(len(self.agent.field))): - if self.agent.logger: self.agent.logger.warning(f'[{self.agent.jid}] Incorrect index (rounded, either negative or bigger than the list size): {int(self.agent.limit_number(round(self.agent.limit_number(it))))}') - return - amt = self.agent.limit_number(self.agent.field[int(self.agent.limit_number(round(self.agent.limit_number(it))))]) - - # add - amt = self.agent.limit_number(amt + self.agent.limit_number(0.1)) - - # if greater than - if self.agent.limit_number(amt) > self.agent.limit_number(10): - - # set - amt = self.agent.limit_number(10) - - # list write - if int(self.agent.limit_number(round(self.agent.limit_number(it)))) < 0 or int(self.agent.limit_number(round(self.agent.limit_number(it)))) >= int(self.agent.limit_number(len(self.agent.field))): - if self.agent.logger: self.agent.logger.warning(f'[{self.agent.jid}] Incorrect index (rounded, either negative or bigger than the list size): {int(self.agent.limit_number(round(self.agent.limit_number(it))))}') - return - self.agent.field[int(self.agent.limit_number(round(self.agent.limit_number(it))))] = self.agent.limit_number(amt) - - # add - it = self.agent.limit_number(it + self.agent.limit_number(1)) - - async def run(self): - self.regrow() - - class recv_spawn(spade.behaviour.CyclicBehaviour): - def choose_spawn(self, rcv): - if self.agent.logger: self.agent.logger.debug(f'[{self.agent.jid}] Run action choose_spawn') - - # clear - self.agent.spawn_candidate.clear() - - # if equal - if self.agent.limit_number(rcv["typ"]) == self.agent.limit_number(1): - - # subset - if int(self.agent.limit_number(round(self.agent.limit_number(1)))) <= 0: - if self.agent.logger: self.agent.logger.debug(f'[{self.agent.jid}] Non-positive subset size (rounded): {int(self.agent.limit_number(round(self.agent.limit_number(1))))}') - return - self.agent.spawn_candidate = [copy.deepcopy(elem) for elem in random.sample(self.agent.dead_sheep, min(int(self.agent.limit_number(round(self.agent.limit_number(1)))), int(self.agent.limit_number(len(self.agent.dead_sheep)))))] - - # remove element - if "spawn_candidate" in self.agent.dead_sheep: self.agent.dead_sheep.remove("spawn_candidate") - - # add element - self.agent.alive_sheep.append("spawn_candidate") - - # if equal - if self.agent.limit_number(rcv["typ"]) == self.agent.limit_number(2): - - # subset - if int(self.agent.limit_number(round(self.agent.limit_number(1)))) <= 0: - if self.agent.logger: self.agent.logger.debug(f'[{self.agent.jid}] Non-positive subset size (rounded): {int(self.agent.limit_number(round(self.agent.limit_number(1))))}') - return - self.agent.spawn_candidate = [copy.deepcopy(elem) for elem in random.sample(self.agent.dead_wolf, min(int(self.agent.limit_number(round(self.agent.limit_number(1)))), int(self.agent.limit_number(len(self.agent.dead_wolf)))))] - - # remove element - if "spawn_candidate" in self.agent.dead_wolf: self.agent.dead_wolf.remove("spawn_candidate") - - # add element - self.agent.alive_wolf.append("spawn_candidate") - - async def spawn(self, rcv): - if self.agent.logger: self.agent.logger.debug(f'[{self.agent.jid}] Run action spawn') - send = { "type": "spawn", "performative": "Inform", "typ": 0.0, } - - # send - if self.agent.logger: self.agent.logger.debug(f'[{self.agent.jid}] Send message {send} to {self.agent.spawn_candidate}') - for receiver in self.agent.spawn_candidate: - await self.send(self.agent.get_spade_message(receiver, send)) - self.agent.msgSCount = self.agent.limit_number(self.agent.msgSCount + 1) - - async def run(self): - rcv = await self.receive(timeout=100000) - if rcv: - rcv = self.agent.get_json_from_spade_message(rcv) - self.agent.msgRCount = self.agent.limit_number(self.agent.msgRCount + 1) - if self.agent.logger: self.agent.logger.debug(f'[{self.agent.jid}] Received message: {rcv}') - self.choose_spawn(rcv) - await self.spawn(rcv) - - class recv_broadcast(spade.behaviour.CyclicBehaviour): - def add_agent(self, rcv): - if self.agent.logger: self.agent.logger.debug(f'[{self.agent.jid}] Run action add_agent') - - # if equal - if self.agent.limit_number(rcv["typ"]) == self.agent.limit_number(1): - - # if equal - if self.agent.limit_number(rcv["state"]) == self.agent.limit_number(0): - - # remove element - if "RCV.jid" in self.agent.alive_sheep: self.agent.alive_sheep.remove("RCV.jid") - - # add element - self.agent.dead_sheep.append("RCV.jid") - - # if equal - if self.agent.limit_number(rcv["state"]) == self.agent.limit_number(1): - - # remove element - if "RCV.jid" in self.agent.dead_sheep: self.agent.dead_sheep.remove("RCV.jid") - - # add element - self.agent.alive_sheep.append("RCV.jid") - - # if equal - if self.agent.limit_number(rcv["typ"]) == self.agent.limit_number(2): - - # if equal - if self.agent.limit_number(rcv["state"]) == self.agent.limit_number(0): - - # remove element - if "RCV.jid" in self.agent.alive_wolf: self.agent.alive_wolf.remove("RCV.jid") - - # add element - self.agent.dead_wolf.append("RCV.jid") - - # if equal - if self.agent.limit_number(rcv["state"]) == self.agent.limit_number(1): - - # remove element - if "RCV.jid" in self.agent.dead_wolf: self.agent.dead_wolf.remove("RCV.jid") - - # add element - self.agent.alive_wolf.append("RCV.jid") - - async def run(self): - rcv = await self.receive(timeout=100000) - if rcv: - rcv = self.agent.get_json_from_spade_message(rcv) - self.agent.msgRCount = self.agent.limit_number(self.agent.msgRCount + 1) - if self.agent.logger: self.agent.logger.debug(f'[{self.agent.jid}] Received message: {rcv}') - self.add_agent(rcv) - - class eat_grass(spade.behaviour.CyclicBehaviour): - async def parse_eat(self, rcv): - if self.agent.logger: self.agent.logger.debug(f'[{self.agent.jid}] Run action parse_eat') - send = { "type": "eat", "performative": "Inform", "energy": 0.0, } - - # float declaration - index = self.agent.limit_number(rcv["x"]) - - # multiply - index = self.agent.limit_number(index * self.agent.limit_number(99)) - - # add - index = self.agent.limit_number(index + self.agent.limit_number(rcv["y"])) - - # float declaration - grass_val = self.agent.limit_number(0) - - # list read - if int(self.agent.limit_number(round(self.agent.limit_number(index)))) < 0 or int(self.agent.limit_number(round(self.agent.limit_number(index)))) >= int(self.agent.limit_number(len(self.agent.field))): - if self.agent.logger: self.agent.logger.warning(f'[{self.agent.jid}] Incorrect index (rounded, either negative or bigger than the list size): {int(self.agent.limit_number(round(self.agent.limit_number(index))))}') - return - grass_val = self.agent.limit_number(self.agent.field[int(self.agent.limit_number(round(self.agent.limit_number(index))))]) - - # float declaration - send_flag = self.agent.limit_number(0) - - # if greater than - if self.agent.limit_number(grass_val) > self.agent.limit_number(1): - - # set - send_flag = self.agent.limit_number(1) - - # set - send["energy"] = self.agent.limit_number(1) - - # subtract - grass_val = self.agent.limit_number(grass_val - self.agent.limit_number(1)) - - # list write - if int(self.agent.limit_number(round(self.agent.limit_number(index)))) < 0 or int(self.agent.limit_number(round(self.agent.limit_number(index)))) >= int(self.agent.limit_number(len(self.agent.field))): - if self.agent.logger: self.agent.logger.warning(f'[{self.agent.jid}] Incorrect index (rounded, either negative or bigger than the list size): {int(self.agent.limit_number(round(self.agent.limit_number(index))))}') - return - self.agent.field[int(self.agent.limit_number(round(self.agent.limit_number(index))))] = self.agent.limit_number(grass_val) - - # if equal - if self.agent.limit_number(send_flag) == self.agent.limit_number(0): - - # set - send["energy"] = self.agent.limit_number(0) - - # send - if self.agent.logger: self.agent.logger.debug(f'[{self.agent.jid}] Send message {send} to {"RCV.jid"}') - await self.send(self.agent.get_spade_message("RCV.jid", send)) - self.agent.msgSCount = self.agent.limit_number(self.agent.msgSCount + 1) - - async def run(self): - rcv = await self.receive(timeout=100000) - if rcv: - rcv = self.agent.get_json_from_spade_message(rcv) - self.agent.msgRCount = self.agent.limit_number(self.agent.msgRCount + 1) - if self.agent.logger: self.agent.logger.debug(f'[{self.agent.jid}] Received message: {rcv}') - await self.parse_eat(rcv) - - class recv_kill(spade.behaviour.CyclicBehaviour): - def kill_creature(self, rcv): - if self.agent.logger: self.agent.logger.debug(f'[{self.agent.jid}] Run action kill_creature') - - # if in list - if "RCV.jid" in self.agent.alive_sheep: - - # remove element - if "RCV.jid" in self.agent.alive_sheep: self.agent.alive_sheep.remove("RCV.jid") - - # add element - self.agent.dead_sheep.append("RCV.jid") - - # if in list - if "RCV.jid" in self.agent.alive_wolf: - - # remove element - if "RCV.jid" in self.agent.alive_wolf: self.agent.alive_wolf.remove("RCV.jid") - - # add element - self.agent.dead_wolf.append("RCV.jid") - - async def run(self): - rcv = await self.receive(timeout=100000) - if rcv: - rcv = self.agent.get_json_from_spade_message(rcv) - self.agent.msgRCount = self.agent.limit_number(self.agent.msgRCount + 1) - if self.agent.logger: self.agent.logger.debug(f'[{self.agent.jid}] Received message: {rcv}') - self.kill_creature(rcv) - - - -class sheep(spade.agent.Agent): - def __init__(self, jid, password, backup_url = None, backup_period = 60, backup_delay = 0, logger = None, **kwargs): - super().__init__(jid, password, verify_security=False) - if logger: logger.debug(f'[{jid}] Received parameters: jid: {jid}, password: {password}, backup_url: {backup_url}, backup_period: {backup_period}, backup_delay: {backup_delay}, kwargs: {kwargs}') - self.logger = logger - self.backup_url = backup_url - self.backup_period = backup_period - self.backup_delay = backup_delay - self.connections = kwargs.get("connections", []) - self.msgRCount = self.limit_number(kwargs.get("msgRCount", 0)) - self.msgSCount = self.limit_number(kwargs.get("msgSCount", 0)) - self.energy = self.limit_number(kwargs.get("energy", 100)) - self.x = self.limit_number(kwargs.get("x", random.uniform(self.limit_number(0), self.limit_number(99)))) - self.y = self.limit_number(kwargs.get("y", random.uniform(self.limit_number(0), self.limit_number(99)))) - self.heading = self.limit_number(kwargs.get("heading", random.uniform(self.limit_number(0), self.limit_number(180)))) - self.invert = kwargs.get("invert", random.choices(["YES", "NO"], [0, 100])[0]) - self.dead = kwargs.get("dead", random.choices(["YES", "NO"], [0, 100])[0]) - self.field = kwargs.get("field", []) - if self.logger: self.logger.debug(f'[{self.jid}] Class dict after initialization: {self.__dict__}') - - @property - def connCount(self): - return self.limit_number(len(self.connections)) - - def limit_number(self, value): - return float(max(-2147483648, min(value, 2147483647))) - - def get_json_from_spade_message(self, msg): - return orjson.loads(msg.body) - - def get_spade_message(self, receiver_jid, body): - msg = spade.message.Message(to=receiver_jid) - body["sender"] = str(self.jid) - msg.metadata["type"] = body["type"] - msg.metadata["performative"] = body["performative"] - msg.body = str(orjson.dumps(body), encoding="utf-8") - return msg - - def setup(self): - if self.backup_url: - BackupBehaviour_template = spade.template.Template() - BackupBehaviour_template.set_metadata("reserved", "no_message_match") - self.add_behaviour(self.BackupBehaviour(start_at=datetime.datetime.now() + datetime.timedelta(seconds=self.backup_delay), period=self.backup_period), BackupBehaviour_template) - setup_template = spade.template.Template() - setup_template.set_metadata("reserved", "no_message_match") - self.add_behaviour(self.setup(), setup_template) - move_around_template = spade.template.Template() - move_around_template.set_metadata("reserved", "no_message_match") - self.add_behaviour(self.move_around(period=10), move_around_template) - reproduce_template = spade.template.Template() - reproduce_template.set_metadata("reserved", "no_message_match") - self.add_behaviour(self.reproduce(period=20), reproduce_template) - recv_spawn_template = spade.template.Template() - recv_spawn_template.set_metadata("type", "spawn") - recv_spawn_template.set_metadata("performative", "Inform") - self.add_behaviour(self.recv_spawn(), recv_spawn_template) - recv_kill_template = spade.template.Template() - recv_kill_template.set_metadata("type", "kill") - recv_kill_template.set_metadata("performative", "Inform") - self.add_behaviour(self.recv_kill(), recv_kill_template) - grass_eat_template = spade.template.Template() - grass_eat_template.set_metadata("type", "eat") - grass_eat_template.set_metadata("performative", "Inform") - self.add_behaviour(self.grass_eat(), grass_eat_template) - recv_broadcast_template = spade.template.Template() - recv_broadcast_template.set_metadata("type", "broadcast") - recv_broadcast_template.set_metadata("performative", "Inform") - self.add_behaviour(self.recv_broadcast(), recv_broadcast_template) - get_eaten_request_template = spade.template.Template() - get_eaten_request_template.set_metadata("type", "eat") - get_eaten_request_template.set_metadata("performative", "Request") - self.add_behaviour(self.get_eaten_request(), get_eaten_request_template) - if self.logger: self.logger.debug(f'[{self.jid}] Class dict after setup: {self.__dict__}') - - class BackupBehaviour(spade.behaviour.PeriodicBehaviour): - def __init__(self, start_at, period): - super().__init__(start_at=start_at, period=period) - self.http_client = httpx.AsyncClient(timeout=period) - - async def run(self): - data = { - "__timestamp__": int(datetime.datetime.timestamp(datetime.datetime.utcnow())), - "jid": str(self.agent.jid), - "type": "sheep", - "floats": { - "msgRCount": self.agent.msgRCount, - "msgSCount": self.agent.msgSCount, - "connCount": self.agent.connCount, - "energy": self.agent.energy, - "x": self.agent.x, - "y": self.agent.y, - "heading": self.agent.heading, - }, - "enums": { - "invert": self.agent.invert, - "dead": self.agent.dead, - }, - "connections": { - "connections": self.agent.connections, - "field": self.agent.field, - }, - "messages": { - }, - "float_lists": { - }, - } - if self.agent.logger: self.agent.logger.debug(f'[{self.agent.jid}] Sending backup data: {data}') - try: - await self.http_client.post(self.agent.backup_url, headers={"Content-Type": "application/json"}, data=orjson.dumps(data)) - except Exception as e: - if self.agent.logger: self.agent.logger.error(f'[{self.agent.jid}] Backup error type: {e.__class__}, additional info: {e}') - - class setup(spade.behaviour.OneShotBehaviour): - async def broadcast(self): - if self.agent.logger: self.agent.logger.debug(f'[{self.agent.jid}] Run action broadcast') - send = { "type": "broadcast", "performative": "Inform", "typ": 0.0, "state": 0.0, } - - # set - send["typ"] = self.agent.limit_number(1) - - # if equal - if self.agent.dead == "YES": - - # set - send["state"] = self.agent.limit_number(0) - - # if equal - if self.agent.dead == "NO": - - # set - send["state"] = self.agent.limit_number(1) - - # send - if self.agent.logger: self.agent.logger.debug(f'[{self.agent.jid}] Send message {send} to {self.agent.connections}') - for receiver in self.agent.connections: - await self.send(self.agent.get_spade_message(receiver, send)) - self.agent.msgSCount = self.agent.limit_number(self.agent.msgSCount + 1) - - async def run(self): - await self.broadcast() - - class move_around(spade.behaviour.PeriodicBehaviour): - def wiggle(self): - if self.agent.logger: self.agent.logger.debug(f'[{self.agent.jid}] Run action wiggle') - - # if equal - if self.agent.dead == "NO": - - # float declaration - wiglR = self.agent.limit_number(0) - - # float declaration - wiglL = self.agent.limit_number(0) - - # uniform distribution - wiglR = self.agent.limit_number(random.uniform(self.agent.limit_number(0), self.agent.limit_number(90))) - - # uniform distribution - wiglL = self.agent.limit_number(random.uniform(self.agent.limit_number(0), self.agent.limit_number(90))) - - # float declaration - change_flag = self.agent.limit_number(0) - - # if equal - if self.agent.invert == "YES": - - # set - change_flag = self.agent.limit_number(1) - - # add - self.agent.heading = self.agent.limit_number(self.agent.heading + self.agent.limit_number(wiglL)) - - # subtract - self.agent.heading = self.agent.limit_number(self.agent.heading - self.agent.limit_number(wiglR)) - - # if less than - if self.agent.limit_number(self.agent.heading) < self.agent.limit_number(0): - - # set - self.agent.invert = "NO" - - # add - self.agent.heading = self.agent.limit_number(self.agent.heading + self.agent.limit_number(180)) - - # if greater than - if self.agent.limit_number(self.agent.heading) > self.agent.limit_number(180): - - # set - self.agent.invert = "NO" - - # subtract - self.agent.heading = self.agent.limit_number(self.agent.heading - self.agent.limit_number(180)) - - # if equal - if self.agent.invert == "NO": - - # if equal - if self.agent.limit_number(change_flag) == self.agent.limit_number(0): - - # add - self.agent.heading = self.agent.limit_number(self.agent.heading + self.agent.limit_number(wiglL)) - - # subtract - self.agent.heading = self.agent.limit_number(self.agent.heading - self.agent.limit_number(wiglR)) - - # if less than - if self.agent.limit_number(self.agent.heading) < self.agent.limit_number(0): - - # set - self.agent.invert = "YES" - - # add - self.agent.heading = self.agent.limit_number(self.agent.heading + self.agent.limit_number(180)) - - # if greater than - if self.agent.limit_number(self.agent.heading) > self.agent.limit_number(180): - - # set - self.agent.invert = "YES" - - # subtract - self.agent.heading = self.agent.limit_number(self.agent.heading - self.agent.limit_number(180)) - - def move(self): - if self.agent.logger: self.agent.logger.debug(f'[{self.agent.jid}] Run action move') - - # if equal - if self.agent.dead == "NO": - - # float declaration - a = self.agent.limit_number(0) - - # float declaration - b = self.agent.limit_number(0) - - # sin - a = self.agent.limit_number(numpy.sin(numpy.deg2rad(self.agent.limit_number(self.agent.heading)))) - - # sin - b = self.agent.limit_number(numpy.sin(numpy.deg2rad(self.agent.limit_number(self.agent.heading)))) - - # float declaration - newx = self.agent.limit_number(self.agent.x) - - # float declaration - newy = self.agent.limit_number(self.agent.y) - - # if greater than - if self.agent.limit_number(self.agent.heading) > self.agent.limit_number(90): - - # subtract - newx = self.agent.limit_number(newx - self.agent.limit_number(a)) - - # if greater than or equal - if self.agent.limit_number(self.agent.heading) <= self.agent.limit_number(90): - - # add - newx = self.agent.limit_number(newx + self.agent.limit_number(a)) - - # if equal - if self.agent.invert == "YES": - - # subtract - newy = self.agent.limit_number(newy - self.agent.limit_number(b)) - - # if equal - if self.agent.invert == "NO": - - # add - newy = self.agent.limit_number(newy + self.agent.limit_number(b)) - - # float declaration - bump = self.agent.limit_number(0) - - # if less than - if self.agent.limit_number(newx) < self.agent.limit_number(0): - - # set - bump = self.agent.limit_number(1) - - # if less than - if self.agent.limit_number(newy) < self.agent.limit_number(0): - - # set - bump = self.agent.limit_number(1) - - # if greater than - if self.agent.limit_number(newx) > self.agent.limit_number(99): - - # set - bump = self.agent.limit_number(1) - - # if greater than - if self.agent.limit_number(newy) > self.agent.limit_number(99): - - # set - bump = self.agent.limit_number(1) - - # if equal - if self.agent.limit_number(bump) == self.agent.limit_number(0): - - # set - self.agent.x = self.agent.limit_number(newx) - - # set - self.agent.y = self.agent.limit_number(newy) - - # subtract - self.agent.energy = self.agent.limit_number(self.agent.energy - self.agent.limit_number(1)) - - # if equal - if self.agent.limit_number(bump) == self.agent.limit_number(1): - - # add - self.agent.heading = self.agent.limit_number(self.agent.heading + self.agent.limit_number(90)) - - # if greater than - if self.agent.limit_number(self.agent.heading) > self.agent.limit_number(180): - - # subtract - self.agent.heading = self.agent.limit_number(self.agent.heading - self.agent.limit_number(180)) - - # float declaration - flag = self.agent.limit_number(0) - - # if equal - if self.agent.invert == "YES": - - # set - flag = self.agent.limit_number(1) - - # set - self.agent.invert = "NO" - - # if equal - if self.agent.invert == "NO": - - # if equal - if self.agent.limit_number(flag) == self.agent.limit_number(0): - - # set - self.agent.invert = "YES" - - def check_if_dead(self): - if self.agent.logger: self.agent.logger.debug(f'[{self.agent.jid}] Run action check_if_dead') - - # if greater than or equal - if self.agent.limit_number(self.agent.energy) <= self.agent.limit_number(0): - - # set - self.agent.dead = "YES" - - async def eat(self): - if self.agent.logger: self.agent.logger.debug(f'[{self.agent.jid}] Run action eat') - send = { "type": "eat", "performative": "Request", "x": 0.0, "y": 0.0, } - - # if equal - if self.agent.dead == "NO": - - # set - send["x"] = self.agent.limit_number(self.agent.x) - - # set - send["y"] = self.agent.limit_number(self.agent.y) - - # send - if self.agent.logger: self.agent.logger.debug(f'[{self.agent.jid}] Send message {send} to {self.agent.field}') - for receiver in self.agent.field: - await self.send(self.agent.get_spade_message(receiver, send)) - self.agent.msgSCount = self.agent.limit_number(self.agent.msgSCount + 1) - - async def run(self): - self.wiggle() - self.move() - self.check_if_dead() - await self.eat() - - class reproduce(spade.behaviour.PeriodicBehaviour): - async def hatch(self): - if self.agent.logger: self.agent.logger.debug(f'[{self.agent.jid}] Run action hatch') - send = { "type": "spawn", "performative": "Inform", "typ": 0.0, } - - # if equal - if self.agent.dead == "NO": - - # if equal - if self.agent.limit_number(self.agent.energy) == self.agent.limit_number(100): - - # set - send["typ"] = self.agent.limit_number(1) - - # send - if self.agent.logger: self.agent.logger.debug(f'[{self.agent.jid}] Send message {send} to {self.agent.field}') - for receiver in self.agent.field: - await self.send(self.agent.get_spade_message(receiver, send)) - self.agent.msgSCount = self.agent.limit_number(self.agent.msgSCount + 1) - - async def run(self): - await self.hatch() - - class recv_spawn(spade.behaviour.CyclicBehaviour): - def spawn(self, rcv): - if self.agent.logger: self.agent.logger.debug(f'[{self.agent.jid}] Run action spawn') - - # set - self.agent.dead = "NO" - - async def run(self): - rcv = await self.receive(timeout=100000) - if rcv: - rcv = self.agent.get_json_from_spade_message(rcv) - self.agent.msgRCount = self.agent.limit_number(self.agent.msgRCount + 1) - if self.agent.logger: self.agent.logger.debug(f'[{self.agent.jid}] Received message: {rcv}') - self.spawn(rcv) - - class recv_kill(spade.behaviour.CyclicBehaviour): - async def die(self, rcv): - if self.agent.logger: self.agent.logger.debug(f'[{self.agent.jid}] Run action die') - send = { "type": "kill", "performative": "Inform", } - - # set - self.agent.dead = "YES" - - # send - if self.agent.logger: self.agent.logger.debug(f'[{self.agent.jid}] Send message {send} to {self.agent.field}') - for receiver in self.agent.field: - await self.send(self.agent.get_spade_message(receiver, send)) - self.agent.msgSCount = self.agent.limit_number(self.agent.msgSCount + 1) - - async def run(self): - rcv = await self.receive(timeout=100000) - if rcv: - rcv = self.agent.get_json_from_spade_message(rcv) - self.agent.msgRCount = self.agent.limit_number(self.agent.msgRCount + 1) - if self.agent.logger: self.agent.logger.debug(f'[{self.agent.jid}] Received message: {rcv}') - await self.die(rcv) - - class grass_eat(spade.behaviour.CyclicBehaviour): - def change_energy(self, rcv): - if self.agent.logger: self.agent.logger.debug(f'[{self.agent.jid}] Run action change_energy') - - # add - self.agent.energy = self.agent.limit_number(self.agent.energy + self.agent.limit_number(rcv["energy"])) - - async def run(self): - rcv = await self.receive(timeout=100000) - if rcv: - rcv = self.agent.get_json_from_spade_message(rcv) - self.agent.msgRCount = self.agent.limit_number(self.agent.msgRCount + 1) - if self.agent.logger: self.agent.logger.debug(f'[{self.agent.jid}] Received message: {rcv}') - self.change_energy(rcv) - - class recv_broadcast(spade.behaviour.CyclicBehaviour): - def xd(self, rcv): - if self.agent.logger: self.agent.logger.debug(f'[{self.agent.jid}] Run action xd') - - # if equal - if self.agent.limit_number(rcv["typ"]) == self.agent.limit_number(0): - - # add element - self.agent.field.append("RCV.jid") - - async def run(self): - rcv = await self.receive(timeout=100000) - if rcv: - rcv = self.agent.get_json_from_spade_message(rcv) - self.agent.msgRCount = self.agent.limit_number(self.agent.msgRCount + 1) - if self.agent.logger: self.agent.logger.debug(f'[{self.agent.jid}] Received message: {rcv}') - self.xd(rcv) - - class get_eaten_request(spade.behaviour.CyclicBehaviour): - async def kappa(self, rcv): - if self.agent.logger: self.agent.logger.debug(f'[{self.agent.jid}] Run action kappa') - send = { "type": "eat", "performative": "Inform", "energy": 0.0, } - - # if equal - if self.agent.dead == "NO": - - # float declaration - lowx = self.agent.limit_number(self.agent.x) - - # float declaration - lowy = self.agent.limit_number(self.agent.y) - - # float declaration - highx = self.agent.limit_number(self.agent.x) - - # float declaration - highy = self.agent.limit_number(self.agent.y) - - # subtract - lowx = self.agent.limit_number(lowx - self.agent.limit_number(1)) - - # subtract - lowy = self.agent.limit_number(lowy - self.agent.limit_number(1)) - - # add - highx = self.agent.limit_number(highx + self.agent.limit_number(1)) - - # add - highy = self.agent.limit_number(highy + self.agent.limit_number(1)) - - # if less than - if self.agent.limit_number(highx) < self.agent.limit_number(rcv["x"]): - - # if less than - if self.agent.limit_number(highy) < self.agent.limit_number(rcv["y"]): - - # if greater than - if self.agent.limit_number(lowx) > self.agent.limit_number(rcv["x"]): - - # if greater than - if self.agent.limit_number(lowy) > self.agent.limit_number(rcv["y"]): - - # set - send["energy"] = self.agent.limit_number(1) - - # send - if self.agent.logger: self.agent.logger.debug(f'[{self.agent.jid}] Send message {send} to {"RCV.jid"}') - await self.send(self.agent.get_spade_message("RCV.jid", send)) - self.agent.msgSCount = self.agent.limit_number(self.agent.msgSCount + 1) - - async def run(self): - rcv = await self.receive(timeout=100000) - if rcv: - rcv = self.agent.get_json_from_spade_message(rcv) - self.agent.msgRCount = self.agent.limit_number(self.agent.msgRCount + 1) - if self.agent.logger: self.agent.logger.debug(f'[{self.agent.jid}] Received message: {rcv}') - await self.kappa(rcv) - - - -class wolf(spade.agent.Agent): - def __init__(self, jid, password, backup_url = None, backup_period = 60, backup_delay = 0, logger = None, **kwargs): - super().__init__(jid, password, verify_security=False) - if logger: logger.debug(f'[{jid}] Received parameters: jid: {jid}, password: {password}, backup_url: {backup_url}, backup_period: {backup_period}, backup_delay: {backup_delay}, kwargs: {kwargs}') - self.logger = logger - self.backup_url = backup_url - self.backup_period = backup_period - self.backup_delay = backup_delay - self.connections = kwargs.get("connections", []) - self.msgRCount = self.limit_number(kwargs.get("msgRCount", 0)) - self.msgSCount = self.limit_number(kwargs.get("msgSCount", 0)) - self.energy = self.limit_number(kwargs.get("energy", 100)) - self.x = self.limit_number(kwargs.get("x", random.uniform(self.limit_number(0), self.limit_number(99)))) - self.y = self.limit_number(kwargs.get("y", random.uniform(self.limit_number(0), self.limit_number(99)))) - self.heading = self.limit_number(kwargs.get("heading", random.uniform(self.limit_number(0), self.limit_number(180)))) - self.invert = kwargs.get("invert", random.choices(["YES", "NO"], [0, 100])[0]) - self.dead = kwargs.get("dead", random.choices(["YES", "NO"], [0, 100])[0]) - self.is_eating = kwargs.get("is_eating", random.choices(["YES", "NO"], [0, 100])[0]) - self.field = kwargs.get("field", []) - self.sheep = kwargs.get("sheep", []) - if self.logger: self.logger.debug(f'[{self.jid}] Class dict after initialization: {self.__dict__}') - - @property - def connCount(self): - return self.limit_number(len(self.connections)) - - def limit_number(self, value): - return float(max(-2147483648, min(value, 2147483647))) - - def get_json_from_spade_message(self, msg): - return orjson.loads(msg.body) - - def get_spade_message(self, receiver_jid, body): - msg = spade.message.Message(to=receiver_jid) - body["sender"] = str(self.jid) - msg.metadata["type"] = body["type"] - msg.metadata["performative"] = body["performative"] - msg.body = str(orjson.dumps(body), encoding="utf-8") - return msg - - def setup(self): - if self.backup_url: - BackupBehaviour_template = spade.template.Template() - BackupBehaviour_template.set_metadata("reserved", "no_message_match") - self.add_behaviour(self.BackupBehaviour(start_at=datetime.datetime.now() + datetime.timedelta(seconds=self.backup_delay), period=self.backup_period), BackupBehaviour_template) - setup_template = spade.template.Template() - setup_template.set_metadata("reserved", "no_message_match") - self.add_behaviour(self.setup(), setup_template) - move_around_template = spade.template.Template() - move_around_template.set_metadata("reserved", "no_message_match") - self.add_behaviour(self.move_around(period=10), move_around_template) - recv_spawn_template = spade.template.Template() - recv_spawn_template.set_metadata("type", "spawn") - recv_spawn_template.set_metadata("performative", "Inform") - self.add_behaviour(self.recv_spawn(), recv_spawn_template) - rcv_eat_template = spade.template.Template() - rcv_eat_template.set_metadata("type", "eat") - rcv_eat_template.set_metadata("performative", "Inform") - self.add_behaviour(self.rcv_eat(), rcv_eat_template) - recv_broadcast_template = spade.template.Template() - recv_broadcast_template.set_metadata("type", "broadcast") - recv_broadcast_template.set_metadata("performative", "Inform") - self.add_behaviour(self.recv_broadcast(), recv_broadcast_template) - if self.logger: self.logger.debug(f'[{self.jid}] Class dict after setup: {self.__dict__}') - - class BackupBehaviour(spade.behaviour.PeriodicBehaviour): - def __init__(self, start_at, period): - super().__init__(start_at=start_at, period=period) - self.http_client = httpx.AsyncClient(timeout=period) - - async def run(self): - data = { - "__timestamp__": int(datetime.datetime.timestamp(datetime.datetime.utcnow())), - "jid": str(self.agent.jid), - "type": "wolf", - "floats": { - "msgRCount": self.agent.msgRCount, - "msgSCount": self.agent.msgSCount, - "connCount": self.agent.connCount, - "energy": self.agent.energy, - "x": self.agent.x, - "y": self.agent.y, - "heading": self.agent.heading, - }, - "enums": { - "invert": self.agent.invert, - "dead": self.agent.dead, - "is_eating": self.agent.is_eating, - }, - "connections": { - "connections": self.agent.connections, - "field": self.agent.field, - "sheep": self.agent.sheep, - }, - "messages": { - }, - "float_lists": { - }, - } - if self.agent.logger: self.agent.logger.debug(f'[{self.agent.jid}] Sending backup data: {data}') - try: - await self.http_client.post(self.agent.backup_url, headers={"Content-Type": "application/json"}, data=orjson.dumps(data)) - except Exception as e: - if self.agent.logger: self.agent.logger.error(f'[{self.agent.jid}] Backup error type: {e.__class__}, additional info: {e}') - - class setup(spade.behaviour.OneShotBehaviour): - async def broadcast(self): - if self.agent.logger: self.agent.logger.debug(f'[{self.agent.jid}] Run action broadcast') - send = { "type": "broadcast", "performative": "Inform", "typ": 0.0, "state": 0.0, } - - # set - send["typ"] = self.agent.limit_number(2) - - # if equal - if self.agent.dead == "YES": - - # set - send["state"] = self.agent.limit_number(0) - - # if equal - if self.agent.dead == "NO": - - # set - send["state"] = self.agent.limit_number(1) - - # send - if self.agent.logger: self.agent.logger.debug(f'[{self.agent.jid}] Send message {send} to {self.agent.connections}') - for receiver in self.agent.connections: - await self.send(self.agent.get_spade_message(receiver, send)) - self.agent.msgSCount = self.agent.limit_number(self.agent.msgSCount + 1) - - async def run(self): - await self.broadcast() - - class move_around(spade.behaviour.PeriodicBehaviour): - def wiggle(self): - if self.agent.logger: self.agent.logger.debug(f'[{self.agent.jid}] Run action wiggle') - - # if equal - if self.agent.dead == "NO": - - # float declaration - wiglR = self.agent.limit_number(0) - - # float declaration - wiglL = self.agent.limit_number(0) - - # uniform distribution - wiglR = self.agent.limit_number(random.uniform(self.agent.limit_number(0), self.agent.limit_number(90))) - - # uniform distribution - wiglL = self.agent.limit_number(random.uniform(self.agent.limit_number(0), self.agent.limit_number(90))) - - # float declaration - change_flag = self.agent.limit_number(0) - - # if equal - if self.agent.invert == "YES": - - # set - change_flag = self.agent.limit_number(1) - - # add - self.agent.heading = self.agent.limit_number(self.agent.heading + self.agent.limit_number(wiglL)) - - # subtract - self.agent.heading = self.agent.limit_number(self.agent.heading - self.agent.limit_number(wiglR)) - - # if less than - if self.agent.limit_number(self.agent.heading) < self.agent.limit_number(0): - - # set - self.agent.invert = "NO" - - # add - self.agent.heading = self.agent.limit_number(self.agent.heading + self.agent.limit_number(180)) - - # if greater than - if self.agent.limit_number(self.agent.heading) > self.agent.limit_number(180): - - # set - self.agent.invert = "NO" - - # subtract - self.agent.heading = self.agent.limit_number(self.agent.heading - self.agent.limit_number(180)) - - # if equal - if self.agent.invert == "NO": - - # if equal - if self.agent.limit_number(change_flag) == self.agent.limit_number(0): - - # add - self.agent.heading = self.agent.limit_number(self.agent.heading + self.agent.limit_number(wiglL)) - - # subtract - self.agent.heading = self.agent.limit_number(self.agent.heading - self.agent.limit_number(wiglR)) - - # if less than - if self.agent.limit_number(self.agent.heading) < self.agent.limit_number(0): - - # set - self.agent.invert = "YES" - - # add - self.agent.heading = self.agent.limit_number(self.agent.heading + self.agent.limit_number(180)) - - # if greater than - if self.agent.limit_number(self.agent.heading) > self.agent.limit_number(180): - - # set - self.agent.invert = "YES" - - # subtract - self.agent.heading = self.agent.limit_number(self.agent.heading - self.agent.limit_number(180)) - - def move(self): - if self.agent.logger: self.agent.logger.debug(f'[{self.agent.jid}] Run action move') - - # if equal - if self.agent.dead == "NO": - - # float declaration - a = self.agent.limit_number(0) - - # float declaration - b = self.agent.limit_number(0) - - # sin - a = self.agent.limit_number(numpy.sin(numpy.deg2rad(self.agent.limit_number(self.agent.heading)))) - - # sin - b = self.agent.limit_number(numpy.sin(numpy.deg2rad(self.agent.limit_number(self.agent.heading)))) - - # float declaration - newx = self.agent.limit_number(self.agent.x) - - # float declaration - newy = self.agent.limit_number(self.agent.y) - - # if greater than - if self.agent.limit_number(self.agent.heading) > self.agent.limit_number(90): - - # subtract - newx = self.agent.limit_number(newx - self.agent.limit_number(a)) - - # if greater than or equal - if self.agent.limit_number(self.agent.heading) <= self.agent.limit_number(90): - - # add - newx = self.agent.limit_number(newx + self.agent.limit_number(a)) - - # if equal - if self.agent.invert == "YES": - - # subtract - newy = self.agent.limit_number(newy - self.agent.limit_number(b)) - - # if equal - if self.agent.invert == "NO": - - # add - newy = self.agent.limit_number(newy + self.agent.limit_number(b)) - - # float declaration - bump = self.agent.limit_number(0) - - # if less than - if self.agent.limit_number(newx) < self.agent.limit_number(0): - - # set - bump = self.agent.limit_number(1) - - # if less than - if self.agent.limit_number(newy) < self.agent.limit_number(0): - - # set - bump = self.agent.limit_number(1) - - # if greater than - if self.agent.limit_number(newx) > self.agent.limit_number(99): - - # set - bump = self.agent.limit_number(1) - - # if greater than - if self.agent.limit_number(newy) > self.agent.limit_number(99): - - # set - bump = self.agent.limit_number(1) - - # if equal - if self.agent.limit_number(bump) == self.agent.limit_number(0): - - # set - self.agent.x = self.agent.limit_number(newx) - - # set - self.agent.y = self.agent.limit_number(newy) - - # subtract - self.agent.energy = self.agent.limit_number(self.agent.energy - self.agent.limit_number(1)) - - # if equal - if self.agent.limit_number(bump) == self.agent.limit_number(1): - - # add - self.agent.heading = self.agent.limit_number(self.agent.heading + self.agent.limit_number(90)) - - # if greater than - if self.agent.limit_number(self.agent.heading) > self.agent.limit_number(180): - - # subtract - self.agent.heading = self.agent.limit_number(self.agent.heading - self.agent.limit_number(180)) - - # float declaration - flag = self.agent.limit_number(0) - - # if equal - if self.agent.invert == "YES": - - # set - flag = self.agent.limit_number(1) - - # set - self.agent.invert = "NO" - - # if equal - if self.agent.invert == "NO": - - # if equal - if self.agent.limit_number(flag) == self.agent.limit_number(0): - - # set - self.agent.invert = "YES" - - def check_if_dead(self): - if self.agent.logger: self.agent.logger.debug(f'[{self.agent.jid}] Run action check_if_dead') - - # if greater than or equal - if self.agent.limit_number(self.agent.energy) <= self.agent.limit_number(0): - - # set - self.agent.dead = "YES" - - async def eat_sheep(self): - if self.agent.logger: self.agent.logger.debug(f'[{self.agent.jid}] Run action eat_sheep') - send = { "type": "eat", "performative": "Request", "x": 0.0, "y": 0.0, } - - # set - send["x"] = self.agent.limit_number(self.agent.x) - - # set - send["y"] = self.agent.limit_number(self.agent.y) - - # send - if self.agent.logger: self.agent.logger.debug(f'[{self.agent.jid}] Send message {send} to {self.agent.sheep}') - for receiver in self.agent.sheep: - await self.send(self.agent.get_spade_message(receiver, send)) - self.agent.msgSCount = self.agent.limit_number(self.agent.msgSCount + 1) - - # set - self.agent.is_eating = "YES" - - async def run(self): - self.wiggle() - self.move() - self.check_if_dead() - await self.eat_sheep() - - class recv_spawn(spade.behaviour.CyclicBehaviour): - def spawn(self, rcv): - if self.agent.logger: self.agent.logger.debug(f'[{self.agent.jid}] Run action spawn') - - # set - self.agent.dead = "NO" - - async def run(self): - rcv = await self.receive(timeout=100000) - if rcv: - rcv = self.agent.get_json_from_spade_message(rcv) - self.agent.msgRCount = self.agent.limit_number(self.agent.msgRCount + 1) - if self.agent.logger: self.agent.logger.debug(f'[{self.agent.jid}] Received message: {rcv}') - self.spawn(rcv) - - class rcv_eat(spade.behaviour.CyclicBehaviour): - async def eat_sheep(self, rcv): - if self.agent.logger: self.agent.logger.debug(f'[{self.agent.jid}] Run action eat_sheep') - send = { "type": "kill", "performative": "Inform", } - - # if equal - if self.agent.is_eating == "YES": - - # set - self.agent.is_eating = "NO" - - # send - if self.agent.logger: self.agent.logger.debug(f'[{self.agent.jid}] Send message {send} to {"RCV.jid"}') - await self.send(self.agent.get_spade_message("RCV.jid", send)) - self.agent.msgSCount = self.agent.limit_number(self.agent.msgSCount + 1) - - async def run(self): - rcv = await self.receive(timeout=100000) - if rcv: - rcv = self.agent.get_json_from_spade_message(rcv) - self.agent.msgRCount = self.agent.limit_number(self.agent.msgRCount + 1) - if self.agent.logger: self.agent.logger.debug(f'[{self.agent.jid}] Received message: {rcv}') - await self.eat_sheep(rcv) - - class recv_broadcast(spade.behaviour.CyclicBehaviour): - def save_data(self, rcv): - if self.agent.logger: self.agent.logger.debug(f'[{self.agent.jid}] Run action save_data') - - # if equal - if self.agent.limit_number(rcv["typ"]) == self.agent.limit_number(0): - - # add element - self.agent.field.append("RCV.jid") - - # if equal - if self.agent.limit_number(rcv["typ"]) == self.agent.limit_number(1): - - # add element - self.agent.sheep.append("RCV.jid") - - async def run(self): - rcv = await self.receive(timeout=100000) - if rcv: - rcv = self.agent.get_json_from_spade_message(rcv) - self.agent.msgRCount = self.agent.limit_number(self.agent.msgRCount + 1) - if self.agent.logger: self.agent.logger.debug(f'[{self.agent.jid}] Received message: {rcv}') - self.save_data(rcv) - - -import random -import uuid -import numpy - - -def generate_graph_structure(domain): - _num_grass = 1 - _num_sheep = 95 - _num_wolf = 5 - num_agents = _num_grass + _num_sheep + _num_wolf - random_id = str(uuid.uuid4())[:5] - jids = [f"{i}_{random_id}@{domain}" for i in range(num_agents)] - agents = [] - next_agent_idx = 0 - for _ in range(_num_grass): - num_connections = 100 - num_connections = max(min(num_connections, len(jids) - 1), 0) - jid = jids[next_agent_idx] - agents.append({ - "jid": jid, - "type": "grass", - "connections": random.sample([other_jid for other_jid in jids if other_jid != jid], num_connections), - }) - next_agent_idx += 1 - for _ in range(_num_sheep): - num_connections = 100 - num_connections = max(min(num_connections, len(jids) - 1), 0) - jid = jids[next_agent_idx] - agents.append({ - "jid": jid, - "type": "sheep", - "connections": random.sample([other_jid for other_jid in jids if other_jid != jid], num_connections), - }) - next_agent_idx += 1 - for _ in range(_num_wolf): - num_connections = 100 - num_connections = max(min(num_connections, len(jids) - 1), 0) - jid = jids[next_agent_idx] - agents.append({ - "jid": jid, - "type": "wolf", - "connections": random.sample([other_jid for other_jid in jids if other_jid != jid], num_connections), - }) - next_agent_idx += 1 - return agents