358 lines
13 KiB
Python
358 lines
13 KiB
Python
from flask_login import UserMixin
|
|
from werkzeug.security import generate_password_hash, check_password_hash
|
|
from flask_sqlalchemy import SQLAlchemy
|
|
from sqlalchemy.orm import relationship
|
|
import random
|
|
from belote_jeu import cards, N_PLAYERS, colors, winner, N_TURN
|
|
|
|
db = SQLAlchemy()
|
|
|
|
levels_users = {'Inactive':0, 'Simple user':1, 'Can create games':2, 'Can manage games':8, 'Can manage simple users': 9, 'Admin':10}
|
|
|
|
#######################################################################
|
|
# User class #
|
|
#######################################################################
|
|
|
|
class User(UserMixin, db.Model):
|
|
"""Model for user accounts."""
|
|
|
|
__tablename__ = 'users'
|
|
|
|
login = db.Column(db.String(100),
|
|
primary_key=True)
|
|
name = db.Column(db.String(100),
|
|
nullable=False,
|
|
unique=False)
|
|
password = db.Column(db.String(100),
|
|
primary_key=False,
|
|
unique=False,
|
|
nullable=False)
|
|
level = db.Column(db.Integer, default=1)
|
|
last_login = db.Column(db.DateTime)
|
|
|
|
def set_password(self, password):
|
|
"""Create hashed password."""
|
|
self.password = generate_password_hash(password, method='sha256')
|
|
|
|
def check_password(self, password):
|
|
"""Check hashed password."""
|
|
return check_password_hash(self.password, password)
|
|
|
|
def get_id(self):
|
|
return self.login
|
|
|
|
def __repr__(self):
|
|
return '<User {}>'.format(self.login)
|
|
|
|
#######################################################################
|
|
# Game class #
|
|
#######################################################################
|
|
|
|
class Game(db.Model):
|
|
__tablename__ = 'games'
|
|
|
|
id = db.Column(db.Integer,
|
|
primary_key=True)
|
|
name = db.Column(db.String(200))
|
|
players = relationship("Player")
|
|
turn = db.Column(db.Integer, default=-8)
|
|
atout = db.Column(db.String(1))
|
|
preneur = db.Column(db.String(100))
|
|
admin = db.Column(db.String(100), db.ForeignKey('users.login'))
|
|
cards_to_distribute = db.Column(db.String(200))
|
|
first_player = db.Column(db.Integer)
|
|
start = db.Column(db.Boolean, default=False)
|
|
last_played = db.Column(db.String(20))
|
|
played = db.Column(db.String(20))
|
|
fixplayers = db.Column(db.Boolean, default=False)
|
|
points_0 = db.Column(db.Integer, default=0)
|
|
points_1 = db.Column(db.Integer, default=0)
|
|
cumul_0 = db.Column(db.Integer, default=0)
|
|
cumul_1 = db.Column(db.Integer, default=0)
|
|
partie = db.Column(db.Integer, default=1)
|
|
distributeur = db.Column(db.Integer, default=0)
|
|
|
|
def start_game(self, ordered_players):
|
|
# Ordering players
|
|
if self.fixplayers and not self.start:
|
|
i=0
|
|
if ordered_players is not None:
|
|
for op in ordered_players:
|
|
player = Player.query.filter_by(game=self.id, user=op).first()
|
|
if player is not None:
|
|
player.nr = i
|
|
i+=1
|
|
for p in self.players:
|
|
if p.nr is None or p.nr<0:
|
|
p.nr = i
|
|
i+=1
|
|
db.session.commit()
|
|
|
|
self.start = True
|
|
self.first_player = 0
|
|
self.distribute()
|
|
db.session.commit()
|
|
return True
|
|
return False
|
|
|
|
def fix_players(self):
|
|
if self.can_start():
|
|
self.fixplayers = True
|
|
db.session.commit()
|
|
|
|
def distribute(self):
|
|
___cartes = random.sample(cards, k=len(cards))
|
|
for i in range(len(self.players)):
|
|
self.players[i].cards = ','.join(___cartes[5*i:5*(i+1)])
|
|
self.played = ___cartes[5*(i+1)]
|
|
self.cards_to_distribute = ','.join(___cartes[5*(i+1)+1:])
|
|
|
|
def authorized(self, user):
|
|
for p in self.players:
|
|
if user.login == p.user:
|
|
return True
|
|
return False
|
|
|
|
def isadmin(self, user):
|
|
return user.login == self.admin
|
|
|
|
def serialize_state_anonymous(self):
|
|
r = {}
|
|
r['players'] = self.get_ordered_players()
|
|
r['playersinfo'] = {}
|
|
for p in self.players:
|
|
r['playersinfo'][p.user] = User.query.get(p.user).name
|
|
r['atout'] = self.atout
|
|
r['preneur'] = self.preneur
|
|
r['last_played'] = self.last_played.split(',') if self.last_played is not None else []
|
|
r['played'] = self.played.split(',') if self.played is not None else []
|
|
r['turn'] = self.turn
|
|
r['first_player'] = self.first_player
|
|
r['points'] = [self.points_0, self.points_1]
|
|
r['cumul'] = [self.cumul_0, self.cumul_1]
|
|
r['partie'] = self.partie
|
|
r['admin'] = self.admin
|
|
return r
|
|
|
|
def serialize_state(self, user):
|
|
r = self.serialize_state_anonymous()
|
|
r['nr'] = self.get_nr(user)
|
|
cards = self.get_player(user).cards
|
|
r['cards'] = cards.split(',') if cards is not None else []
|
|
return r
|
|
|
|
def get_ordered_players(self):
|
|
r = {}
|
|
for p in self.players:
|
|
r[p.nr] = p.user
|
|
r2 = []
|
|
for i in range(N_PLAYERS):
|
|
r2.append(r[i] if i in r else None)
|
|
return r2
|
|
|
|
def get_nr(self, user):
|
|
p = self.get_player(user)
|
|
if p is not None :
|
|
return p.nr
|
|
else:
|
|
return -1
|
|
|
|
def get_player(self, user):
|
|
if not isinstance(user, str):
|
|
user = user.login
|
|
return Player.query.filter_by(game=self.id, user=user).first()
|
|
|
|
def can_join(self, user):
|
|
if self.authorized(user):
|
|
return True
|
|
if not self.fixplayers and len(self.players) < N_PLAYERS:
|
|
return True
|
|
return False
|
|
|
|
def can_start(self):
|
|
if len(self.players)==N_PLAYERS:
|
|
return True
|
|
return False
|
|
|
|
def join(self, user):
|
|
if not self.fixplayers and not self.authorized(user):
|
|
p = Player(game=self.id, user=user.login)
|
|
db.session.add(p)
|
|
db.session.commit()
|
|
|
|
def leave(self, user):
|
|
if not self.fixplayers:
|
|
for p in self.players:
|
|
if isinstance(user, str) and user != self.admin or hasattr(user, 'login') and user.login != self.admin:
|
|
if isinstance(user, str) and user == p.user or hasattr(user, 'login') and user.login == p.user:
|
|
db.session.delete(p)
|
|
db.session.commit()
|
|
return True
|
|
return False
|
|
|
|
def get_players(self):
|
|
r = []
|
|
for p in self.players:
|
|
user = User.query.get(p.user)
|
|
r.append({'username':user.login, 'name':user.name})
|
|
return r
|
|
|
|
def tour_choix(self, atout, user):
|
|
if (self.turn + self.first_player) % N_PLAYERS == self.get_nr(user):
|
|
self.turn += 1
|
|
if atout is not None and atout in colors:
|
|
self.atout = atout
|
|
self.preneur = user.login
|
|
self.turn = 0
|
|
self.distribute_restant()
|
|
db.session.commit()
|
|
return True
|
|
return False
|
|
|
|
def distribute_restant(self):
|
|
todistribute = self.cards_to_distribute.split(',')
|
|
for pn in self.get_ordered_players():
|
|
p = self.get_player(pn)
|
|
if pn == self.preneur:
|
|
p.cards += ',' + ','.join(todistribute[:2])
|
|
p.cards += ',' + self.played
|
|
todistribute = todistribute[2:]
|
|
else:
|
|
p.cards += ',' + ','.join(todistribute[:3])
|
|
todistribute = todistribute[3:]
|
|
self.cards_to_distribute = ''
|
|
self.played = None
|
|
|
|
def tour_jeu(self, carte, user):
|
|
if (self.turn + self.first_player) % N_PLAYERS == self.get_nr(user):
|
|
winnr = -1
|
|
self.turn += 1
|
|
if self.played is None or self.played == '':
|
|
self.played = carte
|
|
else:
|
|
self.played += ',' + carte
|
|
if self.turn % N_PLAYERS == 0 :
|
|
winnr, points = winner(self.played, self.atout)
|
|
if (self.first_player + winnr)%2 == 0:
|
|
self.points_0 += points
|
|
else:
|
|
self.points_1 += points
|
|
self.last_played = self.played
|
|
if len(self.cards_to_distribute)>1:
|
|
self.cards_to_distribute += ','
|
|
self.cards_to_distribute += self.played
|
|
self.played = None
|
|
self.first_player = (self.first_player + winnr)%4
|
|
|
|
if self.turn == N_TURN*N_PLAYERS: # Dix de der, chute, belote et capote !
|
|
# Dix de der
|
|
if self.first_player%2 == 0:
|
|
self.points_0 += 10
|
|
else:
|
|
self.points_1 += 10
|
|
|
|
# Belote possible
|
|
winnr = self.distributeur
|
|
belote =-1
|
|
belote_0 = 0
|
|
belote_1 = 0
|
|
ccc = self.cards_to_distribute.split(',')
|
|
for i in range(N_TURN):
|
|
cccc = ccc[i*N_PLAYERS:(i+1)*N_PLAYERS]
|
|
if 'R'+self.atout in cccc:
|
|
if belote>=0:
|
|
if (cccc.index('R'+self.atout) + winnr)%4 == belote %4:
|
|
if belote %2 ==0:
|
|
self.points_0 += 20
|
|
belote_0 = 20
|
|
else:
|
|
self.points_1 += 20
|
|
belote_1 = 20
|
|
else:
|
|
belote = winnr + cccc.index('R'+self.atout)
|
|
if 'D'+self.atout in cccc:
|
|
if belote>=0:
|
|
if (cccc.index('D'+self.atout) + winnr)%4 == belote %4:
|
|
if belote %2 ==0:
|
|
self.points_0 += 20
|
|
else:
|
|
self.points_1 += 20
|
|
else:
|
|
belote = winnr + cccc.index('D'+self.atout)
|
|
win, xxx = winner(cccc, self.atout)
|
|
winnr = win+winnr
|
|
|
|
# Capote
|
|
if self.points_0 >= 162 or self.points_1 >= 162:
|
|
winequipe = 0 if self.points_0 >= 162 else 1
|
|
# Capote possible.
|
|
winnr = self.distributeur
|
|
ccc = self.cards_to_distribute.split(',')
|
|
for i in range(N_TURN):
|
|
win, xxx = winner(ccc[i*N_PLAYERS:(i+1)*N_PLAYERS], self.atout)
|
|
winnr = win+winnr
|
|
if winnr % 2 != winequipe:
|
|
break
|
|
else:
|
|
if winequipe == 0:
|
|
self.points_0 += 90
|
|
else:
|
|
self.points_1 += 90
|
|
|
|
# Chute
|
|
if self.get_player(self.preneur).nr %2 ==0 and self.points_0 < self.points_1:
|
|
self.points_0 = belote_0
|
|
self.points_1 = 162 + belote_1
|
|
if self.get_player(self.preneur).nr %2 ==1 and self.points_1 < self.points_0:
|
|
self.points_0 = 162 + belote_0
|
|
self.points_1 = belote_1
|
|
|
|
# Retirer la carte du jeu !
|
|
p = self.get_player(user)
|
|
ccc = p.cards
|
|
ccc = ccc.split(',')
|
|
ccc.remove(carte)
|
|
p.cards = ','.join(ccc)
|
|
db.session.commit()
|
|
return True, winnr
|
|
return False, -1
|
|
|
|
def restart_jeu(self):
|
|
if (self.turn==0 and (self.atout=='' or self.atout is None)) or self.turn==N_TURN*N_PLAYERS:
|
|
if self.turn>0:
|
|
self.partie +=1
|
|
self.turn = -8
|
|
self.atout = None
|
|
self.preneur = None
|
|
self.last_played = None
|
|
self.played = None
|
|
self.cumul_0 += self.points_0
|
|
self.cumul_1 += self.points_1
|
|
self.points_0 = 0
|
|
self.points_1 = 0
|
|
if self.distributeur <3:
|
|
self.distributeur += 1
|
|
else:
|
|
self.distributeur = 0
|
|
self.first_player = self.distributeur
|
|
self.distribute()
|
|
db.session.commit()
|
|
return True
|
|
return False
|
|
|
|
#######################################################################
|
|
# Player class #
|
|
#######################################################################
|
|
|
|
class Player(db.Model):
|
|
__tablename__ = 'players'
|
|
|
|
id = db.Column(db.Integer,
|
|
primary_key=True)
|
|
game = db.Column(db.Integer, db.ForeignKey('games.id'))
|
|
user = db.Column(db.String(100), db.ForeignKey('users.login'))
|
|
cards = db.Column(db.String(40))
|
|
nr = db.Column(db.Integer, default=-1)
|
|
|
|
|