diff --git a/config.py b/config.py index 6bbd171..c4e9d21 100644 --- a/config.py +++ b/config.py @@ -25,6 +25,7 @@ config = { 'data_privacy': {'enabled': True}, 'terms_privacy': {'enabled': True}, 'knucklebones': {'enabled': True}, + 'wordle': {'enabled': True}, 'profiles': {'enabled': True} } } diff --git a/data/encrypted_word_list.bin b/data/encrypted_word_list.bin new file mode 100644 index 0000000..0c7edc3 --- /dev/null +++ b/data/encrypted_word_list.bin @@ -0,0 +1,142 @@ +gAAAAABmiGBez3P25GGn0jWx1deDsb1oIpEV7IU4ZVgOOL24S5r6WfidvQ6g4Yrq84E9gQTSkdcwn_lnm_2zpjSbe9X_qhontQ== +gAAAAABmiGBejvP841lVXZ3ZCA_95MlnRk3UMtJCnzCFMa3QSN5ViaSg4UD3SSqQq9gIE-fc1GL8Gb6m8iOEqhxfmR5HeNyu1Q== +gAAAAABmiGBeRhhg4lJY8Wyz0fUkmZELYKr_twUFba2ZbxoUTKGGGdVUt7yrkG4-UQxqg-IP4ufHZUu-k4w-mJ2gWA25sKrp9A== +gAAAAABmiGBevngRUaVoomllodc0IpcvKWhm-AjzNUaTpjyns_rh5DHbYuWTj5pgUjJXERZEhDa1BrQ3OqLAk2wayONLNnH3eQ== +gAAAAABmiGBeUp0Wyr0XNACS_tY_55WTFf84Jdmg2JCTR9_9bkAfhqZv22PTSN-xdxz9VADh264BDucz2YRoHOVmdbqXMoz0eQ== +gAAAAABmiGBe5vAqONV8OfOznlcLYMh9KcyPxI8IcyIOUDdxSmMOoxDVGpxRPwyowJDokgzZGmq6tvXLlnBcwbWleoECopUO-Q== +gAAAAABmiGBeAXmUWejjs0rIvDlVsx-U3d2MdS_rjNLbSgq6-ukcuFhDbr0nWIOD83DMcO2CjAGJWN-a2Mw8Vdql287v7M_AEA== +gAAAAABmiGBeA1jW_FbcAo3JDFC9iX2abGFIR7EW8MOH5zcWfZMhPCGnsvbu69fZP35SudeqbMNhLy7drASV-Z4KtXnwyZD7qQ== +gAAAAABmiGBeYf819SSXTwW_9MbUtfE8xAjtqHkFCbXY7Vgma36Tchl6LqV62jlodDqvHhbQ-fStSEsjG2bPdO5OI3_PmCb3TA== +gAAAAABmiGBeztzZr4I-jyrB76dZjjDkvK5b5kaY06Vol6lGjoqz10qzIWBkbpvmvvdAT31Q01vPyN4iU8vpWNSNTPkV1vlfAg== +gAAAAABmiGBekhbLv-48kdCUF6j4hU2JrTXnu5hnezTz2UEXqD15PZeDITuyRUqa7hNbo3FkBzqGYQsXz4gDi_f-0ViYCsCQJQ== +gAAAAABmiGBeja_0vafWUUN87JOvFh-aQci_XzIqTrCqr629Y_xHO9cBvrSa0tmK_DHMcGISN_Ls8iVFOWt1U82sTy2DiDU-pw== +gAAAAABmiGBeR9ovJk2ONg0Pee3LXsJQoj5ddXdGIln9yakJ4ZztJUmjHMjFKU1S8tZb_xpHEHp6pbG10RFqk1yRRR-T5Y_WVg== +gAAAAABmiGBegcizm8mJR5V7yHpp7Xp0Fs0uC2mxf-4NzeIyQK_zEmPOOHQj8s8htTdk-x-fUwSD9qpFSJt11zSHdyONRkHvDw== +gAAAAABmiGBeJIUMxf6HdcWpsLLeKEJDwt6QwbC709xUEPdfmQVAA1N7Nl78MtJqSJxQ9bJC7wcJgg87IRC0koqViN3M1YWjKQ== +gAAAAABmiGBeL9xj9HLcmegi45KteAbupTac77kfC484qPi7MJA_xHMcHGY-YOrIFEo37Xb7w7aivNt9YaVOi5IkVNan1OnVFw== +gAAAAABmiGBe87S8w710hzzQlEdplEsJxAygJb9ZBvcd8_9l3IMzWLoI9lwJrlZtbG9a1mpO37EbTLcKdN0trhqZCtnItsWa2g== +gAAAAABmiGBetXiT4f2aeTQmpibgYQtgreQC3mDYuTqYFcuz5Im_b9EF3X4cP6Xg_TWNzz1x4GtduktHrRZ169Ro8CvBxcuWfQ== +gAAAAABmiGBeVIXUxhIGbdpqjiJ5pcZ2mbbr_YaG0M98u9iysVJqxsgTKtxhrI8BDux2PxF71vHS9VY7aiM27UMXBnoQTJqniA== +gAAAAABmiGBeFZ_eKtFb9anrmyns5cMMDfvhH6ZeIjUUt2QDgZLBRhE_ObgyWXFj4MSk32hl60p4ZkBzd9TivlUv6pfZmN0HUw== +gAAAAABmiGBeGltFO5nGfyvZB48Y86Jb2RTJEUWlYe_0uAkAeqagJhQkM0L41Wa5ipFhtdhvaYUzIw2WEWcpPMh4Rbrc4k-Ugg== +gAAAAABmiGBetjFqcCEB-85G3iMm_ITyZH78ECDtWvgEzFHsfWeKkt2LW5dhw1NCG-_A4xkrUbtp98X9_-AHwOOVDA_Qnvgt0Q== +gAAAAABmiGBeA22zlQbVE_cFLQIaFKR_Dd01G2Y9MG1zM1iP_W2YEYS5kCeV4FmR2w--0tdajPxljhQnZoFSqh-xAkR8SfhGvg== +gAAAAABmiGBezdUKsSIPdOruL-MByI4F3vXvEHLQHauzifJnqXIrAlo_8uoICLOb8lH2tXBe2oMfVGTXuCt4v2v8cvLfyJCvtg== +gAAAAABmiGBeXCtGzc-NksPzpLZHGXkY9mgQb_jVu8rW-jR8NZrvESY5HpkRb49RdmOloo4npmvc2IqdPJLhnMtUYWl4x-MciQ== +gAAAAABmiGBe3Ly8SPsWI-kQyWKouMHRlyqJP8j9GlW5eHZlZxaB0uz1WLJgfqG0hXebQZmVwLZRKRMbn7-hNDXhAIxuyf6rqA== +gAAAAABmiGBeVUxmJrqpAA0yEwRUrFnZuPv-aZRO33xkDZ3LHK7jTaUbG-7GWEduFnth0O65Y7xpx20ehxeWWeHg9B18eeZLEA== +gAAAAABmiGBebS6ZFcceVeM1FdE1DcykOAHrH6q6lK9jQ8Ys3na2VwwymC8ut6muZgWYVjRuposve-62LJlpZ7G4rm1czdtDsQ== +gAAAAABmiGBek_OcTkRg3v5xwKvx_-FSBTHGFkzBrGVw1RQAR8AekT5aluuyroxP46uVGlnH-8fSsCNDTIZ7A45EwMIpLt-5JQ== +gAAAAABmiGBedkkvrywKcZv9ncnXDzkjLlt02Dj9cn1_pxcZLub0oWlsuQS2gqGyZlaW3TySBK40FJhWEYGFrGxz0eOXG4kocQ== +gAAAAABmiGBe4kaJLtMhIVtkzXkLFkWeQI1fEoJ4fNJCQas9xnEi-n672yrrS8wr7ZJd193gTp6t7FOhrrIM6KlnXCax0PBXXQ== +gAAAAABmiGBeO8kOd-oG3AJ-hRBM3xYHI-paZGLzHlPUFnAWl3iftg0hLvbDEACyn32JwLH-53FEIV5D3IDw88XubwCMboHAzw== +gAAAAABmiGBe9QPlqsPdu-FtddreMB0L19_frNSz0qWKuelo9Gv5rheGpBSuOI7iKFrBXQFziZJQpF9LrzYBHNAsqzPEOqxvEg== +gAAAAABmiGBeP5LsqXg_NFMY7vzs0aGsVK9n5Nay_i_E_ym6hD4KG_bix4u39AqUjb9Xqo-coHgCaKui8V9oCFVXEMIFxxnz3A== +gAAAAABmiGBexoCMcMLDoVJkHzcld4iUE2Tw8SO97GYkrDsf3Nv5mWyuiP4tvfBLDvok1Prz7IDcNu6ioy_IP0v4169THgh0kA== +gAAAAABmiGBetT6P2YhqftrXd8qawxZejTP20_L5IB0MI_gFhCO0dZt_GBZDV0L-45ob60QiVuXAQFDjFT5a7QOPVH8Q5eiyUQ== +gAAAAABmiGBeyxX-J0HZpxGfWxIvBhBNCRdeVdRwc_idW-p4qaejNJRNfkCMvZ-V5ou0bslAuWJu51iQJgMmnfGrWdmgWenPxA== +gAAAAABmiGBeXyiN7FNM5ol6WlQCz8aCwFN5mkY37u9mgX1nt3tlYtht9lovrcBOSQxytOCHjk2TQowrKqyUitu0VK-Byq0p6w== +gAAAAABmiGBeTqYfz3oXMKzLMETkmA-Ua8IcliNFih8TtsfQUiaqyiTWUzmiqJMRVbp_DNWwCs1QVWB5E9xNu_OpdJPZ3xCSvg== +gAAAAABmiGBe8Gdq0EE1p5StrJFxLunocKPcGKV-CJknJ0vOeG8Ma5eJTLhuIMxYxbBzochyJUY9Awipl5C8yU9bY9fjgVIVXA== +gAAAAABmiGBe-GdlZxJalBfeRTRsk2QEKNrom9s4vkn0cX2OpDc3O9vWQ4sZsF-prQzLJpd-_QucJz87wYloPOkDcCyIlUfghQ== +gAAAAABmiGBeJM-M6EdiJFP_tGFFT2Jfi1gAn6zzi81sIMPo94EuVg3MacLdi7M1jMSSeXigmTcZJffP0cHZrmAWKiY73v_--Q== +gAAAAABmiGBe439eGaTd-xNK242LyNdpCb62lh4ycdwkCORZX3C6-Gc48Gav31eh1r4-SH2b5R5ianSSWHeXZTn8GkK9JXPlbw== +gAAAAABmiGBeYR2bhkF5E_JQ2aP64S9Rk3MLUop5l7ePI2KQg55tRZzd45HuwwedvfSbQ6bQnE8YGMbL9F6H_s84Ad2XzBqraw== +gAAAAABmiGBemMMKI3IxikqSbq0PC2mcTnhDWMkYaq8BTxoFPZvcuIviqkXax94vNBnmvW2cb1i8TyWNEjuri_zYBLK9RmdBBQ== +gAAAAABmiGBehBFXbc5a4ZGmVf2QSWmjt9d46sk8MRLwDEW0XZGsBpBhqXFsd-OI4cKcvhIIq_3ekLhVbykueQq6zwhPbL2mxw== +gAAAAABmiGBeqw2AIQ-va8eclQqvMTDOFQrcfvab7zr-KLyDJ3QDt4NUeqZsvS8Sb-nOxjvcSoSxYs6yOlBi6KjMnggmJIjA5Q== +gAAAAABmiGBexrW0Y8F12ZOv_Q36tye3jHauY8ZEdivO-PthNOwbGdsH9hDmUHWbfJNzJjHzL2kcJrKgupY88R9WEjGXn8ZBuw== +gAAAAABmiGBemR2jD_liGj5LcKczsKQi-0uuMmOnWIih0-7umAZoYy3Nzl13FC-Nd0Gj6c4ElqO3dNGl7soM1VqNWXvNxLpwdQ== +gAAAAABmiGBePuRqnyLDCnZTqPBMrDbqRneWhtxZAVqd4npd9bIMv_7KSFq1k_nZG_S3wT11NiWbQUqmucxOvWlblFmYxHpxcQ== +gAAAAABmiGBe9EnAWtWzYrhM1Wqwz2BiijQ07PC8qOHUL5CZkpz4akFl0gb7r9Y-i6v_uuIAg9BATG-rnNSeQtRfYAhVv9qLBw== +gAAAAABmiGBeE0yy6A1e4tYMp2Dz8RbRPKJ3iDt5n-PgzPcMQz63anVMgJmbNXcxvdCn7eKFAJw-qMRhvBtgF_MEkpGnz66l-A== +gAAAAABmiGBexBqB8-W-TStm_-Eb45Tj1tmtwACtdImH9fuffUUePUvYpyK7DynmSLK6s4Hcl27O2muCEp_bPvSPFy0Tb9bpzA== +gAAAAABmiGBeM_fbbOguy8O4iYH6ktnkLp82ZyV9B4lZILhf5QHC4n6g5Ah81cCKPjoHSRqgm77DUAu7EI78fs9YIHL9XHiFtg== +gAAAAABmiGBe9JwFSkg6QhnwWcH1YrN8dnMYg53Z90B_VI91KAA4jmeqZCAUvtxmYvCeFMUuJ350XCqv4wcj_BtJ3SKuPceL-w== +gAAAAABmiGBeIsuGLeD0D2hL5HwWYANwpRzr-IYIE2oRajniXrpf8qZyhI91mlhkXlDLjeFr0TxzXgFwy9EOheXbOvGL3Xs_Dg== +gAAAAABmiGBevIc9u4DzZc-gCqXX0f4EJXBMVYzBg69Q0bxEWKyAzkpdTCHqTypJ7nE5EKGXqfUhXsQYWacrdcRWkBmc3ZD6_w== +gAAAAABmiGBeBuJ6KHF1qrF05mnpd77lwL4tmmk6FR3ahXTdZuiHr7xhCccjiFDTffvfHJZc-2ccFm0Kdas5AVKGkDWI4L9bXw== +gAAAAABmiGBeaj50_Ea0jqe-E5kz1T2ywI2UJ__pcMkA5ggEmMtV_X_g1zIL_MVLkHaNPuBbCS5zUErusOQziazQYO51lC9zSw== +gAAAAABmiGBeJ8zpbvRNQMSha8XovkGg4O7Nh1BrtzvuPDrU4j3g9OfrIRRZY6gs9B5Y7X3snvYOFUhv69Vvo5SxtK-eN3n1ug== +gAAAAABmiGBega5Bct8hU5YwFaV-sln_C0Nkqk874oeExWvLOA63bHUS-fMWaYf20KssRlR5F43QVCV8p37QMOzAW2SBzTEgVw== +gAAAAABmiGBeKh6N_zSAYIjlMi0sYPiaeiLOTMLlE4VdDCVYiaNiA9tW5gdnVkXJRS7bEGf-EFQ86qed0B_lAixe-Q30kEyDsw== +gAAAAABmiGBeOLbCos9_j0Vd9TIaK-f4YZch5yxafMWWKyuHTH3tLT3oqac9n4khN1AVs-Osusv5EVrYl3l4C7TVHFoAeqANWg== +gAAAAABmiGBedjUiInJnLly6cylrkP2HlRA2vj6VboTeucpZ_U9sFtygbee5oglUGS66x8hj2FW7qDWA9UZty--aOKP3LixWng== +gAAAAABmiGBe1XwlvfvBn9eM9zXfHD-vlTblMIRvDkFSizj-pYh9cU_-672zFjr_zdLPYo0K9bB0k8-Lz9fwf3liiYhLx1OTnA== +gAAAAABmiGBe9oO3mQhwHiTQAep6U5DLQULXoD1KLg0fMWc1z7iaXQ_87RcUZ9Vg10IgA7CR5aVRXFmwugOi2ROO4Umj59bt9Q== +gAAAAABmiGBemOYRBnd9PaLchxYZehMr__NL4WMG7c8dTiWxCQBWTUXsPBYVkR-pthLGXySVNK5JWa_ECPSoUk4Su0yOuuGAHg== +gAAAAABmiGBeJs7d4P240rE71BVNsOCJQMM5nnw9u5CP2t6wh3mq79W0xsj0SDQS0OWvmJaPo9JWD53dp_2vkF5uBx0IWhQr7Q== +gAAAAABmiGBekT7VZL9zsgvDyYqM4gMfvLGBvhi7tTIojtD7Sf0crCh4A1y-VMqHPkt-lhrXnt0-z97zbPj4YzyTehVrJbTOdA== +gAAAAABmiGBeXuC2QEOzaY6Rh4UPKdU5Uai4rgJPdJxwecWnzjMyQ75DzZFZnR63fRJzZDzEX0MDB2X0qnMc0P_6poPcS4CgdA== +gAAAAABmiGBehbwKXfjeBurCrBGAW-pFLJvAIjcjR4uFs3XUsxz94FgSRhcP3EM3wF0L8UF9BaKjxxqmDgF0XaH7dJG1LEx_AA== +gAAAAABmiGBeHTV3hklgTW2zdzuUIhhptx5hFFQkOuSJGDDFrqa-EvQM9m85QOtvdaapAZ7T9VDBugZk5OGM_MQr3PgH1uxtoA== +gAAAAABmiGBekcytpYfddImZACFJ2Gdmodr1JBQ5-hWAQwfpHMe0p0kdnoulEZh_BtWiV43qBomFfo13Xi6YPt-57jpoS_fXXQ== +gAAAAABmiGBe9DeqZFC2ImX4vpBuoA43oftxH3372G98Na9V0u0q-Rfmmfvkf3S8osgBfwQmPQh_VkTASttBlYgZR19A_ijJVQ== +gAAAAABmiGBe12el2Q7LMDwXDiSv-1zEaWJurFTIm511H7fXVmPR5q8H_wJjHdDxYv2x8N3JsalGuh7g4_OQZVntQVuZRt9Dgg== +gAAAAABmiGBexaQmgCKkVpP4oeZbGgBwz-4QdbR9VpIg2rMbDMlxxgD1s61Ps8bUGFb9CSy0fKaN7YOZfsfVc5kWmKAXM-ZQrg== +gAAAAABmiGBeIShjv9ZgAMXJzEIgZG_k0E4P63HB4OosbAEXnsZglYp3BL6Lfp_gsCvDOibipowoLE9bRLDCM9a6bnS1FHPe-w== +gAAAAABmiGBemNkvc_zd-Ignvo0hbp65JWctJTae0yxRe-jTGAnFfEHuf3ne3GrDijyjE6yOYShdu0HJwiFZ7SGwN6RnzEQLSg== +gAAAAABmiGBe_m93N4cuKOfYjH_FEsjeD0WEsRIzfe16r_w0pi2M1dYzfkJlfu-QCSfZA4CllE5rsgMS4AK-wXEvRD3c9aa60Q== +gAAAAABmiGBea7Z0Mn4HoT0u0jdzcfsi-ZSuLqvuvsQGokkHrFN9xTKUOGKy3mt56PigeDW3QO9v7kXX-piZMxbB7-3lZjR12A== +gAAAAABmiGBeUc86QwIoOQior8bSDbqq5bOcldHwM42_Mn1kylO9tWwTsTD5Vyb9KbT-LMlwXVs_JdzERE-QPSr9NOk63kcGfw== +gAAAAABmiGBey4wXPm_zRlPJMko6DZFbf0prCGhT8ZlPtvOJ_OqWRbWRdi9su3uBF-DKB2xqnA2CYXuRQLedb3GcoRlM9FmRug== +gAAAAABmiGBeNEbOmK0ZjCRn1lKViedDxY1DLQue9dMshgO3w6N-MHIHJqSeSby5XMIl52hM1PF2EeiIU-oCytoKJnmysvEMUA== +gAAAAABmiGBebsZIk75_eNbPhtgEyqWUQqozxZzOLtEx4rY_Ts6x8Hy6OXWpwQTfDaHMgGvzI0zjG7JD5D8xkwEGk9TrbILbGg== +gAAAAABmiGBed3P9LP2XUyQmMqOsfgd1aTdpqQfvSOZGO_rnKqidO79HdRHWHcqCbKXLv8asOvwKYtCTFGhkKOce64eBVDiowg== +gAAAAABmiGBexl4iai6_Le3Scd84J7nv4iGCCaXPSTAugbA5ReGNqbaWBt5iqeRJt2wKns76dCFvygSdVr48erFCP1GtJfzefg== +gAAAAABmiGBeHbOUjc0VBNxxaWVnPnfwQl4tYosP4ZadVRCU3pTofOQrRDl4Yw8blCZGDZC5N7_mu4SMQ9PqyC7jrE3mF8B00A== +gAAAAABmiGBendqbvTJ6PMRvFxwLyoOQNrdaAz3GQzPAUFFlpe3XVofMP6SCR143NR60dms6XGuBAI6NfXFsE-9ApI_rLz007w== +gAAAAABmiGBej6aGyN5xZ7HMiQ166J2UVM4dWxNg9ZNdaGcE9if0QO-EO_4PQ47oHPhcev9YAfsFs7nGrtB4lDmnRxgTFykXlg== +gAAAAABmiGBe9mwN-NwDVLWwCHR4Pk6sKvLssrs8eMCWdLumKmsgs8HpYkTI1pdxf-T_WFMKEVWOSa80_i7_C3TCdBAeGqXINw== +gAAAAABmiGBeKdG87FUw9nCDno_LzkYE1_npOPsKr-GnOKw9Wl6FFTAPHUi_UforcPRy3c9jZ9GsukkMLTSBrlQ-2qWPMriihA== +gAAAAABmiGBe_YC7bNDSAM2VShglash712cXq0gyLI_SOCmL8GmsGsN6htksjutOKrWko51f_rPiPquwWCLPiZMy1TBYM_o3wA== +gAAAAABmiGBeux4zYQaVPwSukoXiZ306ctICDzFy6TrswbpJ_eoM5RsmC8rLb1uSS6BqHfB2xvTQp86Alv3HFUjhqNhW7txX7A== +gAAAAABmiGBe8SRs2qtWFOzfg_fsxuzpMGcmynQBf5ewERp7RMaxh5dLMeNHzg_c1enoVO_B8yC9eABQgzhnNjhVur3OF7a-ag== +gAAAAABmiGBeRrBfV6UPNHvI16AAPQ5qD3TCXGZqN4hpeJOMffTuifSFoO2FnqD2sW1itDr9yYYbwAeg6D43XLadR0E5vGQ5rA== +gAAAAABmiGBezlGR-RIigHXyxIvh0LMqqRslQVkAT3zOhtd92Ic0_Sn4YJNpBT2iIOBealiYr9aLjLOXrupg-ctzgZxdYbxEYQ== +gAAAAABmiGBeok3ptnUxj4jT2iNN6pN1pHarHAFbYONJfq3dJXyNS-V04mpy-ASpETJhVqvd4yXqIMMIyOOMT7z5sOZTAfQCxg== +gAAAAABmiGBe4pIVucPnDujegjvAE6hSGwQmH5K5waTHsH4TT-Pzlgh3hZR7T-4bn6ZasPa49QazOjTGB1-LQpSWwjOQZzbIRg== +gAAAAABmiGBeRLJFrM1lpFPGSjmKgPFLvwYzWqHo7VOX4SBtmCj9vjSfUQ2YldwPUw9BU4NcKopX8fBglgbAt7mbQIZJJUzgGQ== +gAAAAABmiGBeyiwBCgCxOIX4jFoMtAVRpk4YiDvPDmym8Yt0wrY3xLBmOXoJpR38EUe050Ue_TuvXpCrv3rIqdSxyAGlcBT9xQ== +gAAAAABmiGBez4uDP-C7_eHS2FBCJcELHB2jmS0YdkBDcC-5yyv6qMLEGAvq5Fwu24Jl1Ses6GJ06rvIsaKPex-f9GR1Ok688g== +gAAAAABmiGBe2IhQNbEtzGThVQqDyYmLbSzYvjluDXEqDZ1cJ-W8W0FvDy8WYDcdOEckXA2qcaqgW891lVt1a-Ag9y-x9cOv9Q== +gAAAAABmiGBeNue5LnAzFuUJJqWpH9b3eDQ_-OHKzP9SRWBq1ziQnkRDZIczfMcgiUDC-FtEZd4KtKx2q1NUzmFMEMFGINxoew== +gAAAAABmiGBeRwxsQvki0wchQrFSiQYfx1EEWyeQRY1_QLve7SVrrTAHJNsDYc_Ukd3gYaOwHik8cDo1P3uW3QocveKhh4tqqw== +gAAAAABmiGBeYAt6Rm1sBhdjvVpbINFenM9ibxbJCt7G66Nuh4KOskYNqFj1rOmMFOgx2NJKnhST284E85sMaDyoPsY1X2KkDA== +gAAAAABmiGBer2fAvPOL8pvD_6qqtfxALjikN_Phz7z_QkKSn72N6i5giFgBz-8G7jWninRuKK8YarXVD63bSpmO6tUI3Fqvrg== +gAAAAABmiGBensdSs1E6eq1jvYJCTiuIn8fozM76xHnVZnSvOdjnodRR4mg9EcxThtb8msIjGYXQO3nBL65gNL3OhV4vPsvjbg== +gAAAAABmiGBeLToU73rGQEpBYuxGuR7qbKTV8cOkPocp6yuHL1a_e2tk5Ctm6AA2_QUklkZ44rk8-w5D4lrMvPB6p1F9TefRIg== +gAAAAABmiGBerm0abfRe96MpADs8SlNetoe2Tns3fbRvtsZ7-4_L549zmdjX3jpQgrg7Ky72366CTNJJRLFdYrBd1E50n0nT_g== +gAAAAABmiGBeGVZEll9cc03GgDn-lXdOdqtov1dNu4XeIaQCTWz4yV2FV00eg_nUzxRSpCnczly5KyVRX8lvOuc7p0V9jnnh5g== +gAAAAABmiGBel-7ZD14sHhTFcJJtixgmuR5LryvT_iTffEBNER2pjI8MTeu09WahuvD4XK0OXPgTAkgI2aYkg5Z0GtHeS3gZuw== +gAAAAABmiGBeAqockNltibw6NEWFfCZTpAObwthtoEXleSt5bTWp82MzpDQkeubvELY58vEjPXBPPAyciFdVClmGK_c_hF5cmQ== +gAAAAABmiGBeIg-HT8CHoUCK6DZQYNFQ8bDNcAkE1i0K1MBQJewgKBtiqMLmms_DQ6g9rPY1HOnC3chBzxaPNub696nEZgXmjg== +gAAAAABmiGBef4RIdvDHRkfc9rrm8Z-ca_IEqV1e5DSe7fL4ueMNt_D8XzXZRD0K96Q9mUCd3VDUH08n6rXviq-24CoKYjRdbA== +gAAAAABmiGBeIDs9L2Q0_fGbDyJaYchZD0ft32rgins-USDicuXUhHsULgc_ObD3atLOS3QCKnr30SNmWl6vFBjGr7TasrzHfw== +gAAAAABmiGBeKaVFgl44tcBwmeQO6C58EEj0OmiDfAhVLz4Lzqouo8bwPJT2TbxdNbnm5dyJVbreakpgVhXtsASFETkRNaRpvw== +gAAAAABmiGBeEFQsoQwYC-FgmPWCtUIytNXsvZ_pjGAzRsqqCzPnZwvXJ2LHmXD4XPNxgRjX8xPs2Hu6NZvVds2Y0c6zHUqltw== +gAAAAABmiGBeu_-GAe-GsS2NcvlT7kO0ObMgzJkvv8sKh7uZ4bMYiXG9COrs9WtpDxcEk3Dc_gwteOkmUjbH0hKXipEwmLi_EA== +gAAAAABmiGBewlW_6gVFFKi65HywAhJ7bl5EMbrlWxy_dtbZx-agn2aPJs9embZzEDBV-VGFo3t43nvOpirFkk8Epu1EmM9d5w== +gAAAAABmiGBedHCr6QdKngIVcMY3JNF5T-YRfDnvqoBOPAa2uM_Ra8hI0qdhJqMnWT4zPW-SbWXTzuvyk_HAlOfP4QHuvQ0DCA== +gAAAAABmiGBeAudgnlYElvlD4i77a-Nencbne2SV0MAPamLVGhjZJypXFV3Bp8qYkAf6drG1oK0lyRShYcIzIi5OHvcjF3YkIw== +gAAAAABmiGBejhSKOZUDpun9YcfN8RaGDuAs0bb5EnZ4hNx07cSVzMa0L4sa0Dr8sI_RkweMcqkyu5SpzOpHQz7pzSWU133KdQ== +gAAAAABmiGBekuxD8Um9QUlUJbDfDnD0LrdP2FDjhGYfzMA_bZk1B9zPiUSXWZ1MGYiGGifeZi1Bi05GLQVqd1RrKghaxGT67Q== +gAAAAABmiGBeVPBAOwK5atC0XcigtA1tDDlyYzB7t4jaH2EMcegy38tsIYvig4FXncne1Im6r4iuQ0xlqycp-3lvQ5TbC0ofuA== +gAAAAABmiGBehzZovJnfqU27lfXtkK0J_Mr58-HgMcv_jZIWX7MD4YulvoOcA0nMzFoC2AG9UNV35ioHAnJOyRhZeUxzeKc_mA== +gAAAAABmiGBe_MAXBrQrL4-8lwsCcQWBnLoOZhzvmPET8HenppfgPqMCjoA8iH9oelsxsRAKnuu531CsjuWAN3lrk3kML6AjQQ== +gAAAAABmiGBe7SclAu6-Ej_QKAqNI1j076rDrtTxyPoodvdUNc6wFkmiQMgB8Wnep-jh9USmVTNf3xLDtTkESWvaKi389LMz7g== +gAAAAABmiGBeAexOEyaxQkPfhio7Ku3hWrsUYtq3h10kzIgqNRFPe7Hf5qx5JwIP6Iw20oiRihGmpAbCrtj5DnH58yMUYyARDg== +gAAAAABmiGBeA01RT2Gv4wunnAdcEXgjEdGfPml8L1chMKVteh4ETLG__1vmMjlylRJd_duASyymcPAVRKGbliCdCT6bNsQNng== +gAAAAABmiGBeQwxwXIwe92jm_ti8E_Q-hneMkHXK0cyJTirp7DHEkEshkxM4HacICVaGRJ0teQ4BRCVmNrNLDTwP9KiAFSYtlg== +gAAAAABmiGBejTB8C55VArGvejJzipT6NT1c8DutiDICTlV1P8JAwiyz3T1IBlutirXL39d216ZcyMtUYxrpOxVEbk92N_WeWA== +gAAAAABmiGBeLtS8VgP_PIBqT2exmtET6jj_lhpdL-qzolFtJ3pWUEXR7WLfcXu9-vsXOnrwgYxXjHsFB_pFgAUkYOFWbgN5wQ== +gAAAAABmiGBe06x5AZsswb3e-gORZ4_I8wzL8IlI90hJylk-fs2IlBiKRqv0UI8RxvncQELiBcseTLTxpAwxeHb3tT75TcCqMA== +gAAAAABmiGBeT2ClmE02iROcOXC_YrQOya_2OZu04nIV0q4nLnUCtE1_QD88vudAUV4wqjKq211x0_moGz81yGhH0HUHzQOniw== +gAAAAABmiGBecAOu9n3rX7TAaoSvkNS24lxumeebT-92yH-TQLBScy2Qv--5MrhI8ohe5Az4okdY9NbQnYBI2nJDVU7l-2ccvw== +gAAAAABmiGBeBu1wJLSnvBhZDpS6iMEHC9oDjSyItY4NEuDzwOYyhVerY26fjXOuRtGED2_NXGRiD_t31QT8evNZOCC4cXXDqw== +gAAAAABmiGBekmNfazsSiK8pXdjbWttSd9IGiFc-VAAwP4p2AN_j8QkqoamZuUVzxP8VrVRDd8RI038xH5xTjUtv3fFWZocUxQ== +gAAAAABmiGBeVzEtbmNqI7CDg8K0A7aT9U3-9ly32_c-vHPdw_U5SFC_30DQ3huH3kf_D7jQCLDoFJzFTlSTBw_2-82MWemSlQ== +gAAAAABmiGBejbeqrR0FrkyQkpsU9pDw4expVHaTuE4VFOUbykMj3KIZ7SBx30BqffPMMZqAhwpuNbIHeVZpGr_0RgHpTrEBog== +gAAAAABmiGBeMw-OE-AS7nQDxEixUHu0he4WZ7W4Lp8iLYALiPEh5ELQnRHK9blGTkkQ3zljZcB8wBap8fF7CAFU9dH9LNpo2A== +gAAAAABmiGBebVn-mEieiBnk6-qHtMH3Zv85jPXG4zRUWhYEVMQLizHziBRW4gBYo_sEZUbfWrFKvydDASxyMIaDrHHRrZHQyw== +gAAAAABmiGBeIrd8LgnGqKHuVL7URqRa8bKgO1uTg4N8D7bZ7BxDMXN7pDTseka2qDtJ9TiChWE6_qtxYj8uNwa2ksTiZeLRxQ== diff --git a/data/wordlist.key b/data/wordlist.key new file mode 100644 index 0000000..aa643af --- /dev/null +++ b/data/wordlist.key @@ -0,0 +1 @@ +noJII7Djv1uQXw1hxEoHxe0LJ2P21uQJ8WryKMPPNb8= \ No newline at end of file diff --git a/main.py b/main.py index f82e873..b8b47fe 100644 --- a/main.py +++ b/main.py @@ -95,6 +95,11 @@ class Selena(discord.Client): knucklebones_setup(self) logging.info("Knucklebones module loaded") + if config['modules']['wordle']['enabled']: + from modules.games.wordle import setup as wordle_setup + wordle_setup(self) + logging.info("Wordle module loaded") + if config['modules']['profiles']['enabled']: from modules.user.profiles import Profiles profiles = Profiles(self) diff --git a/modules/games/wordle.py b/modules/games/wordle.py new file mode 100644 index 0000000..e5a9693 --- /dev/null +++ b/modules/games/wordle.py @@ -0,0 +1,166 @@ +import discord +import random +import logging +import sqlite3 +from datetime import datetime +from discord.ext import tasks +from discord import app_commands +from cryptography.fernet import Fernet + + +class WordleGame: + def __init__(self, user_id, guild_id, target_word): + self.user_id = user_id + self.guild_id = guild_id + self.target_word = target_word + self.guesses = [] + self.max_attempts = 6 + + def make_guess(self, guess): + if len(guess) != 5 or not guess.isalpha(): + raise ValueError("Invalid guess. Must be a 5-letter word.") + + feedback = ["⬜"] * 5 + for i, char in enumerate(guess): + if char == self.target_word[i]: + feedback[i] = "🟩" + elif char in self.target_word: + feedback[i] = "🟨" + + self.guesses.append((guess, "".join(feedback))) + return feedback + + def is_game_over(self): + return len(self.guesses) >= self.max_attempts or any(guess == self.target_word for guess, _ in self.guesses) + + def is_winner(self): + return any(guess == self.target_word for guess, _ in self.guesses) + + def render_game(self): + game_board = "\n".join([f"{guess}: {feedback}" for guess, feedback in self.guesses]) + return f"```\n{game_board}\n```" + + +class Wordle: + def __init__(self, bot): + self.bot = bot + self.games = {} + self.logger = logging.getLogger('Wordle') + self.logger.setLevel(logging.DEBUG) + handler = logging.FileHandler(filename='log/selena.log', encoding='utf-8', mode='w') + handler.setFormatter(logging.Formatter('%(asctime)s:%(levelname)s:%(name)s:%(message)s')) + self.logger.addHandler(handler) + self.db_path = 'data/selena.db' + + # Load the word list + self.load_word_list() + self.ensure_table_exists() + + def load_word_list(self): + with open('data/wordlist.key', 'rb') as key_file: + key = key_file.read() + cipher_suite = Fernet(key) + + with open('data/encrypted_word_list.bin', 'rb') as f: + encrypted_words = f.read().splitlines() + + self.word_list = [cipher_suite.decrypt(word).decode() for word in encrypted_words] + + def ensure_table_exists(self): + conn = sqlite3.connect(self.db_path) + cursor = conn.cursor() + cursor.execute(""" + CREATE TABLE IF NOT EXISTS wordle_games ( + user_id TEXT NOT NULL, + guild_id TEXT NOT NULL, + date TEXT NOT NULL, + target_word TEXT NOT NULL, + guesses TEXT, + PRIMARY KEY (user_id, guild_id, date) + ); + """) + conn.commit() + conn.close() + + def setup(self, tree: app_commands.CommandTree): + @tree.command(name="start_wordle", description="Start a new game of Wordle") + async def start_wordle_command(interaction: discord.Interaction): + user_id = str(interaction.user.id) + guild_id = str(interaction.guild.id) + date_str = datetime.utcnow().strftime('%Y-%m-%d') + + # Check if the user has already played today's game + if self.has_played_today(user_id, guild_id, date_str): + await interaction.response.send_message("You have already played today's Wordle. Try again tomorrow!", ephemeral=True) + return + + target_word = random.choice(self.word_list) + game = WordleGame(user_id, guild_id, target_word) + self.games[user_id] = game + + # Save the game to the database + self.save_game(user_id, guild_id, date_str, target_word) + + await interaction.response.send_message(f"New game of Wordle started!\n{game.render_game()}\nMake your guess using /guess_wordle [word]") + + @tree.command(name="guess_wordle", description="Make a guess in your Wordle game") + async def guess_wordle_command(interaction: discord.Interaction, guess: str): + user_id = str(interaction.user.id) + game = self.games.get(user_id) + if not game: + await interaction.response.send_message("You don't have an active game. Start one using /start_wordle.", ephemeral=True) + return + + try: + feedback = game.make_guess(guess.lower()) + if game.is_game_over(): + if game.is_winner(): + await self.bot.profiles.record_win(user_id, str(interaction.guild.id), "wordle") + await interaction.response.send_message(f"Congratulations! You guessed the word {game.target_word}!\n{game.render_game()}") + else: + await self.bot.profiles.record_loss(user_id, str(interaction.guild.id), "wordle") + await interaction.response.send_message(f"Game over! The word was {game.target_word}.\n{game.render_game()}") + del self.games[user_id] + else: + await interaction.response.send_message(f"{game.render_game()}\nYour guess: {guess}\nFeedback: {''.join(feedback)}") + except ValueError as e: + await interaction.response.send_message(str(e), ephemeral=True) + + @tree.command(name="end_wordle", description="End your current game of Wordle") + async def end_wordle_command(interaction: discord.Interaction): + user_id = str(interaction.user.id) + if user_id in self.games: + del self.games[user_id] + await interaction.response.send_message("Your game has been ended.") + else: + await interaction.response.send_message("You don't have an active game to end.", ephemeral=True) + + if not tree.get_command("start_wordle"): + tree.add_command(start_wordle_command) + + if not tree.get_command("guess_wordle"): + tree.add_command(guess_wordle_command) + + if not tree.get_command("end_wordle"): + tree.add_command(end_wordle_command) + + def has_played_today(self, user_id, guild_id, date_str): + conn = sqlite3.connect(self.db_path) + cursor = conn.cursor() + cursor.execute("SELECT 1 FROM wordle_games WHERE user_id = ? AND guild_id = ? AND date = ?", (user_id, guild_id, date_str)) + result = cursor.fetchone() + conn.close() + return result is not None + + def save_game(self, user_id, guild_id, date_str, target_word): + conn = sqlite3.connect(self.db_path) + cursor = conn.cursor() + cursor.execute("INSERT INTO wordle_games (user_id, guild_id, date, target_word) VALUES (?, ?, ?, ?)", (user_id, guild_id, date_str, target_word)) + conn.commit() + conn.close() + + +def setup(bot): + wordle = Wordle(bot) + wordle.setup(bot.tree) + bot.wordle_module = wordle diff --git a/requirements.txt b/requirements.txt index 47ab153..196ca85 100644 --- a/requirements.txt +++ b/requirements.txt @@ -12,6 +12,7 @@ charset-normalizer==3.3.2 click==8.1.7 colorama==0.4.6 com2ann==0.3.0 +cryptography==42.0.8 discord.py==2.3.2 ffmpeg-python==0.2.0 frozenlist==1.4.1