mirror of
https://gitlab.com/oloturia/damastodon.git
synced 2025-01-08 22:47:14 +01:00
Merge branch 'connect4' into 'main'
Connect4 See merge request oloturia/damastodon!10
This commit is contained in:
commit
ce93acc6d2
4 changed files with 430 additions and 88 deletions
136
.gitignore
vendored
Normal file
136
.gitignore
vendored
Normal file
|
@ -0,0 +1,136 @@
|
||||||
|
TOKEN
|
||||||
|
TOKEN.LOCAL
|
||||||
|
TOKEN.OLD
|
||||||
|
DAMA.SECRET
|
||||||
|
DAMA.SECRET.LOCAL
|
||||||
|
DAMA.SECRET.OLD
|
||||||
|
|
||||||
|
# Byte-compiled / optimized / DLL files
|
||||||
|
__pycache__/
|
||||||
|
*.py[cod]
|
||||||
|
*$py.class
|
||||||
|
|
||||||
|
# C extensions
|
||||||
|
*.so
|
||||||
|
|
||||||
|
# Distribution / packaging
|
||||||
|
.Python
|
||||||
|
build/
|
||||||
|
develop-eggs/
|
||||||
|
dist/
|
||||||
|
downloads/
|
||||||
|
eggs/
|
||||||
|
.eggs/
|
||||||
|
lib/
|
||||||
|
lib64/
|
||||||
|
parts/
|
||||||
|
sdist/
|
||||||
|
var/
|
||||||
|
wheels/
|
||||||
|
pip-wheel-metadata/
|
||||||
|
share/python-wheels/
|
||||||
|
*.egg-info/
|
||||||
|
.installed.cfg
|
||||||
|
*.egg
|
||||||
|
MANIFEST
|
||||||
|
|
||||||
|
# PyInstaller
|
||||||
|
# Usually these files are written by a python script from a template
|
||||||
|
# before PyInstaller builds the exe, so as to inject date/other infos into it.
|
||||||
|
*.manifest
|
||||||
|
*.spec
|
||||||
|
|
||||||
|
# Installer logs
|
||||||
|
pip-log.txt
|
||||||
|
pip-delete-this-directory.txt
|
||||||
|
|
||||||
|
# Unit test / coverage reports
|
||||||
|
htmlcov/
|
||||||
|
.tox/
|
||||||
|
.nox/
|
||||||
|
.coverage
|
||||||
|
.coverage.*
|
||||||
|
.cache
|
||||||
|
nosetests.xml
|
||||||
|
coverage.xml
|
||||||
|
*.cover
|
||||||
|
*.py,cover
|
||||||
|
.hypothesis/
|
||||||
|
.pytest_cache/
|
||||||
|
|
||||||
|
# Translations
|
||||||
|
*.mo
|
||||||
|
*.pot
|
||||||
|
|
||||||
|
# Django stuff:
|
||||||
|
*.log
|
||||||
|
local_settings.py
|
||||||
|
db.sqlite3
|
||||||
|
db.sqlite3-journal
|
||||||
|
|
||||||
|
# Flask stuff:
|
||||||
|
instance/
|
||||||
|
.webassets-cache
|
||||||
|
|
||||||
|
# Scrapy stuff:
|
||||||
|
.scrapy
|
||||||
|
|
||||||
|
# Sphinx documentation
|
||||||
|
docs/_build/
|
||||||
|
|
||||||
|
# PyBuilder
|
||||||
|
target/
|
||||||
|
|
||||||
|
# Jupyter Notebook
|
||||||
|
.ipynb_checkpoints
|
||||||
|
|
||||||
|
# IPython
|
||||||
|
profile_default/
|
||||||
|
ipython_config.py
|
||||||
|
|
||||||
|
# pyenv
|
||||||
|
.python-version
|
||||||
|
|
||||||
|
# pipenv
|
||||||
|
# According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control.
|
||||||
|
# However, in case of collaboration, if having platform-specific dependencies or dependencies
|
||||||
|
# having no cross-platform support, pipenv may install dependencies that don't work, or not
|
||||||
|
# install all needed dependencies.
|
||||||
|
#Pipfile.lock
|
||||||
|
|
||||||
|
# PEP 582; used by e.g. github.com/David-OConnor/pyflow
|
||||||
|
__pypackages__/
|
||||||
|
|
||||||
|
# Celery stuff
|
||||||
|
celerybeat-schedule
|
||||||
|
celerybeat.pid
|
||||||
|
|
||||||
|
# SageMath parsed files
|
||||||
|
*.sage.py
|
||||||
|
|
||||||
|
# Environments
|
||||||
|
.env
|
||||||
|
.venv
|
||||||
|
env/
|
||||||
|
venv/
|
||||||
|
ENV/
|
||||||
|
env.bak/
|
||||||
|
venv.bak/
|
||||||
|
|
||||||
|
# Spyder project settings
|
||||||
|
.spyderproject
|
||||||
|
.spyproject
|
||||||
|
|
||||||
|
# Rope project settings
|
||||||
|
.ropeproject
|
||||||
|
|
||||||
|
# mkdocs documentation
|
||||||
|
/site
|
||||||
|
|
||||||
|
# mypy
|
||||||
|
.mypy_cache/
|
||||||
|
.dmypy.json
|
||||||
|
dmypy.json
|
||||||
|
|
||||||
|
# Pyre type checker
|
||||||
|
.pyre/
|
159
damastodon.py
159
damastodon.py
|
@ -2,6 +2,7 @@
|
||||||
|
|
||||||
from mastodon import Mastodon
|
from mastodon import Mastodon
|
||||||
import draughts_engine as dama
|
import draughts_engine as dama
|
||||||
|
import four_engine
|
||||||
import login
|
import login
|
||||||
import pickle
|
import pickle
|
||||||
import random
|
import random
|
||||||
|
@ -15,7 +16,10 @@ import logging
|
||||||
api_url = sys.argv[1]
|
api_url = sys.argv[1]
|
||||||
save_position = "/tmp/"
|
save_position = "/tmp/"
|
||||||
CLEANR = re.compile('<.*?>')
|
CLEANR = re.compile('<.*?>')
|
||||||
botname = "@damastodon "
|
#botname = "@damastodon "
|
||||||
|
botname = "@dama "
|
||||||
|
|
||||||
|
available_games = ("draughts","conn4")
|
||||||
|
|
||||||
#board appearence
|
#board appearence
|
||||||
frstrow = "🇻1️⃣ 2️⃣ 3️⃣ 4️⃣ 5️⃣ 6️⃣ 7️⃣ 8️⃣\n"
|
frstrow = "🇻1️⃣ 2️⃣ 3️⃣ 4️⃣ 5️⃣ 6️⃣ 7️⃣ 8️⃣\n"
|
||||||
|
@ -27,6 +31,9 @@ black_norm="◾ "
|
||||||
black_knight="⚫ "
|
black_knight="⚫ "
|
||||||
empty="🟦 "
|
empty="🟦 "
|
||||||
|
|
||||||
|
#conn4
|
||||||
|
conn4row = "1️⃣ 2️⃣ 3️⃣ 4️⃣ 5️⃣ 6️⃣ 7️⃣\n"
|
||||||
|
|
||||||
#logging config
|
#logging config
|
||||||
logging.basicConfig(filename="/tmp/dama.log",level=logging.DEBUG)
|
logging.basicConfig(filename="/tmp/dama.log",level=logging.DEBUG)
|
||||||
|
|
||||||
|
@ -34,45 +41,34 @@ def cleanHTML(raw):
|
||||||
cleanText = re.sub(CLEANR, '',raw)
|
cleanText = re.sub(CLEANR, '',raw)
|
||||||
return cleanText
|
return cleanText
|
||||||
|
|
||||||
def check_message(notification):
|
def lobby(notification,content,account,extension):
|
||||||
account = notification["account"]["acct"]
|
|
||||||
try:
|
|
||||||
content = cleanHTML(notification["status"]["content"])
|
|
||||||
except KeyError:
|
|
||||||
return
|
|
||||||
content = content[len(botname):]
|
|
||||||
saves = os.listdir(save_position)
|
|
||||||
if "help" in content.lower(): #Ask for help
|
|
||||||
mastodon.status_post("Hello @"+account+" \nchallenge an user by writing to me\nCHALL <USERNAME>\nEx. \"CHALL @someone@mastdn.inst.wxyz\"\nThe challenger takes WHITE and begins the match.\nFor movements and jumps, write the coords separated by spaces.\nEx. \"A4 B5\" (normal movement) or \"A4 C6 D8\" (double jump)\nQUIT ends the match.\nCommands are NOT case sensitive.",visibility="direct")
|
|
||||||
return
|
|
||||||
if not os.path.exists(save_position+account): #If there is no a savegame file, then lobby mode is activated
|
|
||||||
try:
|
try:
|
||||||
challenged = notification["status"]["mentions"][1]["acct"] #If there isn't another account cited, then the request is malformed
|
challenged = notification["status"]["mentions"][1]["acct"] #If there isn't another account cited, then the request is malformed
|
||||||
except:
|
except:
|
||||||
mastodon.status_post("Hello @"+account+" \n your request is not valid",visibility="direct")
|
mastodon.status_post("Hello @"+account+" \n your request is not valid",visibility="direct")
|
||||||
return
|
return
|
||||||
if content[:5].lower() == "chall": #Challenge someone, check if a savegame is already existing
|
|
||||||
file_save_white = [sv for sv in saves if account in sv]
|
if challenged == account: #The user tried to challenge him/herself
|
||||||
file_save_black = [sv for sv in saves if challenged in sv]
|
mastodon.status_post("Hello @"+account+"\n You can't challenge yourself",visibility="direct")
|
||||||
if len(file_save_white) > 0: #We are playing a match
|
|
||||||
mastodon.status_post("Hello @"+account+" \n you're already playing a match",visibility="direct")
|
|
||||||
return
|
return
|
||||||
elif len(file_save_black) > 0: #Our opponent is already playing with someone
|
|
||||||
|
if content.split(" ")[0].lower() == extension: #Challenge someone, check if a savegame is already existing
|
||||||
|
if os.path.exists(save_position+challenged+"."+extension):
|
||||||
mastodon.status_post("Hello @"+account+" \n the user you challenged is already playing a match",visibility="direct")
|
mastodon.status_post("Hello @"+account+" \n the user you challenged is already playing a match",visibility="direct")
|
||||||
return
|
return
|
||||||
else:
|
else:
|
||||||
with open(save_position+account,"wb") as f: #The request is valid, writes a savegame with the first element as False, that marks that the game isn't started yet
|
with open(save_position+account+"."+extension,"wb") as f: #The request is valid, writes a savegame with the first element as False, that marks that the game isn't started yet
|
||||||
pickle.dump("WAIT",f)
|
pickle.dump("WAIT",f)
|
||||||
ident = mastodon.status_post("Hello @"+challenged+" \n@"+account+" challenged you to a match of draughts! Answer \n@"+account+" OK\n to accept the chellenge or \n@"+account+" NO\n to cancel.",visibility="direct")
|
ident = mastodon.status_post("Hello @"+challenged+" \n@"+account+" challenged you to a match of "+extension+"! Reply \n @"+account+" OK "+extension.upper()+"\n to accept the challenge or \n@"+account+" NO "+extension.upper()+"\n to cancel.",visibility="direct")
|
||||||
return
|
return
|
||||||
elif content.split(" ")[1].lower() == "ok": #The opponent accepted the match
|
elif content.split(" ")[1].lower() == "ok" and content.split(" ")[2].lower() == extension: #The opponent accepted the match
|
||||||
try:
|
try:
|
||||||
challenger = notification["status"]["mentions"][1]["acct"]
|
challenger = notification["status"]["mentions"][1]["acct"]
|
||||||
except:
|
except:
|
||||||
mastodon.status_post("Hello @"+account+" \n your request is not valid",visibility="direct") #Somehow, the opponent answered with only one account
|
mastodon.status_post("Hello @"+account+" \n your request is not valid",visibility="direct") #Somehow, the opponent answered with only one account
|
||||||
return
|
return
|
||||||
try:
|
try:
|
||||||
with open(save_position+challenger,"rb") as f:
|
with open(save_position+challenger+"."+extension,"rb") as f:
|
||||||
start = pickle.load(f)
|
start = pickle.load(f)
|
||||||
except FileNotFoundError:
|
except FileNotFoundError:
|
||||||
mastodon.status_post("Hello @"+account+" \n unfortunately, your savegame is corrupted or missing",visibility="direct") #The file has moved or corrupted
|
mastodon.status_post("Hello @"+account+" \n unfortunately, your savegame is corrupted or missing",visibility="direct") #The file has moved or corrupted
|
||||||
|
@ -81,61 +77,126 @@ def check_message(notification):
|
||||||
if start != "WAIT":
|
if start != "WAIT":
|
||||||
mastodon.status_post("Hello @"+account+" \n your request is not valid",visibility="direct") #The user that challenged us is playing a game with someone else
|
mastodon.status_post("Hello @"+account+" \n your request is not valid",visibility="direct") #The user that challenged us is playing a game with someone else
|
||||||
return
|
return
|
||||||
os.symlink(save_position+challenger,save_position+account) #Linked the two savegames together
|
os.symlink(save_position+challenger+"."+extension,save_position+account+"."+extension) #Linked the two savegames together
|
||||||
|
|
||||||
|
|
||||||
|
if extension == "draughts": #Draughts init
|
||||||
board = dama.init_board()
|
board = dama.init_board()
|
||||||
with open(save_position+account,"wb") as f:
|
mastodon.status_post("◾: @"+account+" ◽: @"+challenger+" \nturn ◽\n"+dama.draw_checkerboard(board,space,white_norm,white_knight,black_norm,black_knight,empty,column,frstrow),visibility="direct")
|
||||||
|
elif extension == "conn4": #Conn4 init
|
||||||
|
board = four_engine.initChequerboard()
|
||||||
|
mastodon.status_post("⚪: @"+account+" \n⚫: @"+challenger+" \nturn ⚪\n"+four_engine.drawChequerboard(board,players=[white_knight,black_knight],space=empty,toprow=conn4row),visibility="direct")
|
||||||
|
with open(save_position+account+"."+extension,"wb") as f: #Writing the file with the status of the game
|
||||||
pickle.dump("START",f) #Now the game has started
|
pickle.dump("START",f) #Now the game has started
|
||||||
pickle.dump("@"+account,f)
|
pickle.dump("@"+account,f)
|
||||||
pickle.dump("@"+challenger,f)
|
pickle.dump("@"+challenger,f)
|
||||||
pickle.dump(False,f)
|
pickle.dump(False,f)
|
||||||
pickle.dump(board,f)
|
pickle.dump(board,f)
|
||||||
mastodon.status_post("◾: @"+account+" ◽: @"+challenger+" \nturn ◽\n"+dama.draw_checkerboard(board,space,white_norm,white_knight,black_norm,black_knight,empty,column,frstrow),visibility="direct")
|
|
||||||
return
|
return
|
||||||
elif content.split(" ")[1].lower() == "no": #The opponent refused the game
|
elif content.split(" ")[1].lower() == "no" and content.split(" ")[2].lower == extension: #The opponent refused the game
|
||||||
try:
|
try:
|
||||||
challenger = notification["status"]["mentions"][1]["acct"]
|
challenger = notification["status"]["mentions"][1]["acct"]
|
||||||
except:
|
except:
|
||||||
mastodon.status_post("Hello @"+account+" \n your request is not valid",visibility="direct") #Only one user in the message
|
mastodon.status_post("Hello @"+account+" \n your request is not valid",visibility="direct") #Only one user in the message
|
||||||
return
|
return
|
||||||
os.remove(save_position+challenger)
|
os.remove(save_position+challenger+"."+extension)
|
||||||
mastodon.status_post("@"+account+" you cancelled the challenge from @"+challenger,visibility="direct") #Game is cancelled, free to challenge someone else
|
mastodon.status_post("@"+account+" you cancelled the challenge from @"+challenger,visibility="direct") #Game is cancelled, free to challenge someone else
|
||||||
return
|
return
|
||||||
else:
|
else:
|
||||||
mastodon.status_post("Hello @"+account+" \nI can't understand your command or you're not in a match.\nWrite HELP to see the list of available commands.",visibility="direct") #Every other command for the lobby ends here
|
mastodon.status_post("Hello @"+account+" \nI can't understand your command or you're not in a match.\nWrite HELP to see the list of available commands.",visibility="direct") #Every other command for the lobby ends here
|
||||||
return
|
return
|
||||||
else: #We are in a game, so movements are parsed and lobby commands are disabled
|
|
||||||
with open(save_position+account,"rb") as f:
|
def load_status(account,extension,content):
|
||||||
|
with open(save_position+account+"."+extension,"rb") as f: #Open the status file - extension is the type of the game
|
||||||
try:
|
try:
|
||||||
start = pickle.load(f)
|
start = pickle.load(f)
|
||||||
except EOFError: # Something went very wrong, file is corrupt?
|
except EOFError: #Something wrong happened
|
||||||
mastodon.status_post("Hello @"+account+" \n unfortunately, your savegame is corrupted or missing",visibility="direct") #The file has been moved or is corrupted
|
mastodon.status_post("Hello @"+account+" \n unfortunately your savegame is corrupted or missing. The game is cancelled.",visibility="direct")
|
||||||
os.remove(save_position+account)
|
os.remove(save_position+account+"."+extension)
|
||||||
logging.warning("%s file corrupted",account)
|
logging.warning("% file corrupted or missing",account+"."+extension)
|
||||||
return
|
return False
|
||||||
if start: #The game is started, load other parameters
|
|
||||||
black = pickle.load(f)
|
player_1 = pickle.load(f) #Read status from file
|
||||||
white = pickle.load(f)
|
player_2 = pickle.load(f)
|
||||||
turn = pickle.load(f)
|
turn = pickle.load(f)
|
||||||
board = pickle.load(f)
|
board = pickle.load(f)
|
||||||
|
|
||||||
if (start == "WAIT"): #The game is not started yet
|
if (start == "WAIT"): #The game is not started yet
|
||||||
if "quit" in content.lower(): #Game withdrawn
|
if "quit" in content.lower(): #Game withdrawn
|
||||||
os.remove(save_position+account)
|
os.remove(save_position+account+"."+extension)
|
||||||
mastodon.status_post("Hello @"+account+" \nthe challenge has been withdrawn.",visibility="direct")
|
mastodon.status_post("Hello @"+account+" \nthe challenge has been withdrawn.",visibility="direct")
|
||||||
else: #Lobby is disabled if a challenge request is active
|
else: #Lobby is disabled if a challenge request is active
|
||||||
mastodon.status_post("Hello @"+account+" \nyou have already challenged someone, type QUIT to withdraw,",visibility="direct")
|
mastodon.status_post("Hello @"+account+" \nyou have already challenged someone, type QUIT to withdraw,",visibility="direct")
|
||||||
return
|
return False
|
||||||
if "quit" in content.lower(): #The game is quitted
|
if "quit" in content.lower(): #The game is quitted
|
||||||
os.remove(save_position+black[1:])
|
os.remove(save_position+player_1[1:]+"."+extension)
|
||||||
os.remove(save_position+white[1:])
|
os.remove(save_position+player_2[1:]+"."+extension)
|
||||||
mastodon.status_post(black+" "+white+" the match was cancelled.",visibility="direct")
|
mastodon.status_post(player_2+" "+player_1+" the match was cancelled.",visibility="direct")
|
||||||
|
return False
|
||||||
|
|
||||||
|
return True,player_1,player_2,turn,board
|
||||||
|
|
||||||
|
def check_message(notification):
|
||||||
|
account = notification["account"]["acct"]
|
||||||
|
try:
|
||||||
|
content = cleanHTML(notification["status"]["content"])
|
||||||
|
except KeyError:
|
||||||
return
|
return
|
||||||
|
content = content[len(botname):]
|
||||||
|
if "help" in content.lower(): #Ask for help
|
||||||
|
mastodon.status_post("Hello @"+account+" \nchallenge an user in a game of draughts by writing to me\nDRAUGHTS <USERNAME>\nEx. \"DRAUGHTS @someone@mastdn.inst.wxyz\"\nThe challenger takes WHITE and begins the match.\nFor movements and jumps, write the coords separated by spaces.\nEx. \"A4 B5\" (normal movement) or \"A4 C6 D8\" (double jump)\nQUIT ends the match.\nCommands are NOT case sensitive.\nTo challenge someone in a game of Connect 4 write CONN4 <USERNAME>.",visibility="direct")
|
||||||
|
return
|
||||||
|
|
||||||
|
|
||||||
|
#Conn4
|
||||||
|
if os.path.exists(save_position+account+".conn4"):
|
||||||
|
start,player_1,player_2,turn,board = load_status(account,"conn4",content)
|
||||||
|
if not(start):
|
||||||
|
return
|
||||||
|
|
||||||
|
if (player_2 == "@"+account and turn == 1) or (player_1 == "@"+account and turn == 0):
|
||||||
|
board,win = four_engine.dropChip(board,content.lower()[-1],turn+1)
|
||||||
|
if not(board):
|
||||||
|
mastodon.status_post("@"+account+" \nInvalid move.",visibility="direct")
|
||||||
|
return
|
||||||
|
else:
|
||||||
|
with open(save_position+account+".conn4","wb") as f:
|
||||||
|
pickle.dump("START",f)
|
||||||
|
turn = not turn
|
||||||
|
pickle.dump(player_1,f)
|
||||||
|
pickle.dump(player_2,f)
|
||||||
|
pickle.dump(turn,f)
|
||||||
|
pickle.dump(board,f)
|
||||||
|
if turn == 0: #the first is the current turn, the second is the last turn
|
||||||
|
colour = (white_knight,black_knight)
|
||||||
|
else:
|
||||||
|
colour = (black_knight,white_knight)
|
||||||
|
if win == 0:
|
||||||
|
mastodon.status_post("⚪: "+player_1+" \n⚫: "+player_2+" \nturn "+colour[0]+"\n"+four_engine.drawChequerboard(board,players=[white_knight,black_knight],space=empty,toprow=conn4row),visibility="direct")
|
||||||
|
return
|
||||||
|
else: #Someone won!
|
||||||
|
mastodon.status_post("⚪: "+player_1+" \n⚫: "+player_2+" \n"+colour[1]+" WINS!\n"+four_engine.drawChequerboard(board,players=[white_knight,black_knight],space=empty,toprow=conn4row),visibility="direct")
|
||||||
|
os.remove(save_position+player_1[1:]+".conn4")
|
||||||
|
os.remove(save_position+player_2[1:]+".conn4")
|
||||||
|
return
|
||||||
|
else: #We moved in a wrong turn
|
||||||
|
mastodon.status_post("@"+account+" \nIt's not your turn.",visibility="direct")
|
||||||
|
return
|
||||||
|
|
||||||
|
#Draughts
|
||||||
|
if os.path.exists(save_position+account+".draughts"): #We are in a game, so movements are parsed and lobby commands are disabled
|
||||||
|
start,black,white,turn,board = load_status(account,"conn4")
|
||||||
|
if not(start):
|
||||||
|
return
|
||||||
|
|
||||||
|
|
||||||
if (black == "@"+account and turn == 1) or (white == "@"+account and turn == 0): #Check if the turn is right
|
if (black == "@"+account and turn == 1) or (white == "@"+account and turn == 0): #Check if the turn is right
|
||||||
board = dama.valid_move(content.lower(),turn,board,inversion=True) #Function dama.valid_move parses the input for couples of letter and number
|
board = dama.valid_move(content.lower(),turn,board,inversion=True) #Function dama.valid_move parses the input for couples of letter and number
|
||||||
if board == -1: #We made an invalid move
|
if board == -1: #We made an invalid move
|
||||||
mastodon.status_post("@"+account+" \nInvalid move.",visibility="direct")
|
mastodon.status_post("@"+account+" \nInvalid move.",visibility="direct")
|
||||||
return
|
return
|
||||||
else:
|
else:
|
||||||
with open(save_position+account,"wb") as f: #Save the updated board
|
with open(save_position+account+".draughts","wb") as f: #Save the updated board
|
||||||
pickle.dump("START",f)
|
pickle.dump("START",f)
|
||||||
turn = not turn
|
turn = not turn
|
||||||
pickle.dump(black,f)
|
pickle.dump(black,f)
|
||||||
|
@ -155,14 +216,20 @@ def check_message(notification):
|
||||||
winner_t = "WHITE"
|
winner_t = "WHITE"
|
||||||
else:
|
else:
|
||||||
winner_t = "BLACK"
|
winner_t = "BLACK"
|
||||||
os.remove(save_position+black[1:])
|
os.remove(save_position+black[1:]+".draughts")
|
||||||
os.remove(save_position+white[1:])
|
os.remove(save_position+white[1:]+".draughts")
|
||||||
mastodon.status_post("◾: "+black+" ◽: "+white+"\n"+winner_t+" WINS!\n"+dama.draw_checkerboard(board,space,white_norm,white_knight,black_norm,black_knight,empty,column,frstrow),visibility="direct")
|
mastodon.status_post("◾: "+black+" ◽: "+white+"\n"+winner_t+" WINS!\n"+dama.draw_checkerboard(board,space,white_norm,white_knight,black_norm,black_knight,empty,column,frstrow),visibility="direct")
|
||||||
return
|
return
|
||||||
else: #We moved in a wrong turn
|
else: #We moved in a wrong turn
|
||||||
mastodon.status_post("@"+account+" \nIt's not your turn.",visibility="direct")
|
mastodon.status_post("@"+account+" \nIt's not your turn.",visibility="direct")
|
||||||
return
|
return
|
||||||
|
|
||||||
|
#Lobby
|
||||||
|
for game in available_games:
|
||||||
|
if game in content.lower():
|
||||||
|
if not os.path.exists(save_position+account+"."+game): #If there is no a savegame file, then lobby mode is activated
|
||||||
|
lobby(notification,content,account,game)
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
if api_url[:4] != "http":
|
if api_url[:4] != "http":
|
||||||
logging.error("Invalid address")
|
logging.error("Invalid address")
|
||||||
|
|
139
four_engine.py
Executable file
139
four_engine.py
Executable file
|
@ -0,0 +1,139 @@
|
||||||
|
#!/usr/bin/python3
|
||||||
|
|
||||||
|
def drawChequerboard(status,players=[],space="░",toprow="1234567"):
|
||||||
|
bstr = ""
|
||||||
|
bstr += toprow+"\n"
|
||||||
|
for row in status:
|
||||||
|
for cell in row:
|
||||||
|
if cell == 0:
|
||||||
|
bstr += space
|
||||||
|
else:
|
||||||
|
try:
|
||||||
|
bstr += players[cell-1]
|
||||||
|
except IndexError:
|
||||||
|
bstr += str(cell)
|
||||||
|
|
||||||
|
bstr += "\n"
|
||||||
|
return bstr
|
||||||
|
|
||||||
|
def initChequerboard(cols=7,rows=6):
|
||||||
|
board = list()
|
||||||
|
for row in range(rows):
|
||||||
|
board.append([0]*7)
|
||||||
|
return board
|
||||||
|
|
||||||
|
def dropChip(board,move_str,player):
|
||||||
|
failure = (False,0)
|
||||||
|
try:
|
||||||
|
move = int(move_str)-1
|
||||||
|
except ValueError:
|
||||||
|
return failure
|
||||||
|
if move < 0 or move >= len(board[0]):
|
||||||
|
return failure
|
||||||
|
free_space = -1
|
||||||
|
for row in board:
|
||||||
|
if row[move] != 0:
|
||||||
|
break
|
||||||
|
else:
|
||||||
|
free_space += 1
|
||||||
|
if free_space == -1:
|
||||||
|
return failure
|
||||||
|
board[free_space][move] = player
|
||||||
|
return board, checkFour(board,free_space,move)
|
||||||
|
|
||||||
|
def checkFour(board,row,col):
|
||||||
|
sumOr = lambda a,b : (a[0]+b[0], a[1]+b[1])
|
||||||
|
orients = { "N":(1,0),"S":(-1,0),"E":(0,1),"W":(0,-1) }
|
||||||
|
player = board[row][col]
|
||||||
|
points = 0
|
||||||
|
count = 0
|
||||||
|
count += countTokens(board,orients["N"],row,col)
|
||||||
|
count += countTokens(board,orients["S"],row,col)
|
||||||
|
if count >= 3:
|
||||||
|
points +=1
|
||||||
|
count = 0
|
||||||
|
count += countTokens(board,orients["E"],row,col)
|
||||||
|
count += countTokens(board,orients["W"],row,col)
|
||||||
|
if count >= 3:
|
||||||
|
points +=1
|
||||||
|
count = 0
|
||||||
|
count += countTokens(board,sumOr( orients["N"],orients["E"] ),row,col )
|
||||||
|
count += countTokens(board,sumOr( orients["S"],orients["W"] ),row,col )
|
||||||
|
if count >= 3:
|
||||||
|
points +=1
|
||||||
|
count = 0
|
||||||
|
count += countTokens(board,sumOr( orients["N"],orients["W"] ),row,col )
|
||||||
|
count += countTokens(board,sumOr( orients["S"],orients["E"] ),row,col )
|
||||||
|
if count >= 3:
|
||||||
|
points +=1
|
||||||
|
|
||||||
|
|
||||||
|
return points
|
||||||
|
|
||||||
|
def countTokens(board,check,row,col):
|
||||||
|
player = board[row][col]
|
||||||
|
offX = check[0]
|
||||||
|
offY = check[1]
|
||||||
|
count = 0
|
||||||
|
while True:
|
||||||
|
if row+offY < 0 or row+offY >= len(board[row])-1 or col+offX < 0 or col+offX > len(board) or (board[row+offY][col+offX] != player) :
|
||||||
|
break
|
||||||
|
else:
|
||||||
|
count += 1
|
||||||
|
offX += check[0]
|
||||||
|
offY += check[1]
|
||||||
|
return count
|
||||||
|
|
||||||
|
def checkPly(board,row,col,player):
|
||||||
|
if row < 0 or col < 0:
|
||||||
|
return False
|
||||||
|
try:
|
||||||
|
if board[row][col] == player:
|
||||||
|
return True
|
||||||
|
else:
|
||||||
|
return False
|
||||||
|
except IndexError:
|
||||||
|
return False
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
board = initChequerboard()
|
||||||
|
match = True
|
||||||
|
player = 1
|
||||||
|
points_1 = 0
|
||||||
|
points_2 = 0
|
||||||
|
while match:
|
||||||
|
print( drawChequerboard(board) )
|
||||||
|
|
||||||
|
print("Player 1:"+str(points_1))
|
||||||
|
print("Player 2:"+str(points_2))
|
||||||
|
move = input("Player "+str(player)+" turn:")
|
||||||
|
if move == "q":
|
||||||
|
print("quitting")
|
||||||
|
quit()
|
||||||
|
valid, point = dropChip(board,move,player)
|
||||||
|
if not(valid):
|
||||||
|
print("Invalid move")
|
||||||
|
else:
|
||||||
|
board = valid
|
||||||
|
if player == 2:
|
||||||
|
points_2 += point
|
||||||
|
player = 1
|
||||||
|
else:
|
||||||
|
points_1 += point
|
||||||
|
player = 2
|
||||||
|
match = False
|
||||||
|
for row in board:
|
||||||
|
for cell in row:
|
||||||
|
if cell == 0:
|
||||||
|
match = True
|
||||||
|
print("Match over")
|
||||||
|
print( drawChequerboard(board) )
|
||||||
|
print("Player 1 scored "+str(points_1)+" points")
|
||||||
|
print("Player 2 scored "+str(points_2)+" points")
|
||||||
|
if points_1 > points_2:
|
||||||
|
print("Player 1 won!")
|
||||||
|
elif points_2 > points_1:
|
||||||
|
print("Player 2 won!")
|
||||||
|
else:
|
||||||
|
print("Draw!")
|
2
login.py
2
login.py
|
@ -6,7 +6,7 @@ fileDir = fileDir +"/"
|
||||||
|
|
||||||
def login(url):
|
def login(url):
|
||||||
mastodon = Mastodon(
|
mastodon = Mastodon(
|
||||||
access_token = fileDir+"DAMA.SECRET",
|
access_token = fileDir+"DAMA.SECRET.LOCAL",
|
||||||
api_base_url = url
|
api_base_url = url
|
||||||
)
|
)
|
||||||
return mastodon
|
return mastodon
|
||||||
|
|
Loading…
Reference in a new issue