Belote/db.py

361 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
r['distributeur'] = self.distributeur
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
belote_0 = 20
else:
self.points_1 += 20
belote_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)