Merge branch 'master' of https://codefirst.iut.uca.fr/git/Crypteam/Cryptid into todoS5
@ -0,0 +1,7 @@
|
|||||||
|
const ADRESSE_WEBSERVER = "http://localhost:3002"
|
||||||
|
|
||||||
|
const ADRESSE_DBSERVER = "http://localhost:3003"
|
||||||
|
|
||||||
|
const ADRESSE_WEBSITE = ""
|
||||||
|
|
||||||
|
export {ADRESSE_DBSERVER, ADRESSE_WEBSERVER, ADRESSE_WEBSITE}
|
@ -0,0 +1,52 @@
|
|||||||
|
import React, { useState } from 'react';
|
||||||
|
import '../Pages/Profile.css'
|
||||||
|
import dl from '../res/icon/download.png'
|
||||||
|
import defaultImg from '../res/img/Person.png'
|
||||||
|
import { useAuth } from '../Contexts/AuthContext';
|
||||||
|
|
||||||
|
//@ts-ignore
|
||||||
|
const ProfilePDP = () => {
|
||||||
|
const [selectedFile, setSelectedFile] = useState(null);
|
||||||
|
|
||||||
|
|
||||||
|
const {user} = useAuth()
|
||||||
|
// @ts-ignores
|
||||||
|
const handleFileChange = (event) => {
|
||||||
|
let file = event.target.files[0];
|
||||||
|
|
||||||
|
setSelectedFile(file);
|
||||||
|
if (file) {
|
||||||
|
const pdpUrl = URL.createObjectURL(file);
|
||||||
|
if (user!=null){
|
||||||
|
user.profilePicture = pdpUrl
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className='mainPDPContainer'>
|
||||||
|
{selectedFile ? (
|
||||||
|
<div >
|
||||||
|
{/* @ts-ignore */}
|
||||||
|
{/* <p>Selected File: {selectedFile.name}</p> */}
|
||||||
|
<img src={URL.createObjectURL(selectedFile)} alt="Preview" className='imgContainer' width='100px' height='100px' />
|
||||||
|
</div>
|
||||||
|
) : (
|
||||||
|
<div >
|
||||||
|
<img src={user?.profilePicture} alt="Preview" className='imgContainer' width='100px' height='100px' />
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
<div className="parent">
|
||||||
|
<div className="file-upload">
|
||||||
|
<img src={dl} alt="upload" width='35px' height='35px'/>
|
||||||
|
{/* <h6>Cliquer ici pour ajouter une image</h6> */}
|
||||||
|
{/* <p>Taille recommandée : 100px</p> */}
|
||||||
|
<input type="file" accept="image/*" onChange={handleFileChange}/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{/* <input type="file" accept="image/*" onChange={handleFileChange} /> */}
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default ProfilePDP;
|
@ -0,0 +1,14 @@
|
|||||||
|
async function loadImageAsync(url: string): Promise<string> {
|
||||||
|
try {
|
||||||
|
const response = await fetch(url);
|
||||||
|
const blob = await response.blob();
|
||||||
|
|
||||||
|
// Faire quelque chose avec le blob, par exemple, créer une URL blob
|
||||||
|
const blobUrl = URL.createObjectURL(blob);
|
||||||
|
return blobUrl
|
||||||
|
} catch (error) {
|
||||||
|
throw new Error("Erreur lors du chargement de l'image :");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export {loadImageAsync}
|
@ -0,0 +1,123 @@
|
|||||||
|
.mainContainer{
|
||||||
|
display: flex;
|
||||||
|
/* flex-direction: column; */
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
margin: 50px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.mainPDPContainer{
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
border: 2px solid whitesmoke;
|
||||||
|
border-radius: 15px;
|
||||||
|
|
||||||
|
background-color: white;
|
||||||
|
|
||||||
|
margin: 10px;
|
||||||
|
|
||||||
|
min-height: 250px;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*Lpart*/
|
||||||
|
|
||||||
|
.imgContainer{
|
||||||
|
border: 5px solid black;
|
||||||
|
border-radius: 50px;
|
||||||
|
margin: 15px;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*Rpart*/
|
||||||
|
|
||||||
|
.Rpart{
|
||||||
|
|
||||||
|
min-width: 40%;
|
||||||
|
min-height: 250px;
|
||||||
|
margin: 20px;
|
||||||
|
padding: 20px;
|
||||||
|
|
||||||
|
background-color: white;
|
||||||
|
|
||||||
|
border: solid 1px whitesmoke;
|
||||||
|
border-radius: 15px;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
.username-display{
|
||||||
|
display: flex;
|
||||||
|
}
|
||||||
|
|
||||||
|
.editbutton{
|
||||||
|
border-color: white;
|
||||||
|
background-color: white;
|
||||||
|
border: none;
|
||||||
|
|
||||||
|
margin-left: 15px;
|
||||||
|
height: 25px;
|
||||||
|
width: 25px;
|
||||||
|
}
|
||||||
|
.inputpseudo{
|
||||||
|
display: 'flex';
|
||||||
|
justify-content: 'flex-start';
|
||||||
|
align-items: 'center';
|
||||||
|
flex-direction: 'row';
|
||||||
|
|
||||||
|
width: 20vw;
|
||||||
|
padding: 5;
|
||||||
|
|
||||||
|
border:none;
|
||||||
|
border-bottom: solid 2px gray;
|
||||||
|
border-radius: 5;
|
||||||
|
|
||||||
|
font-size: 40px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.bottom{
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
justify-content: end;
|
||||||
|
align-items: end;
|
||||||
|
|
||||||
|
height: 100px;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*File upload*/
|
||||||
|
.parent {
|
||||||
|
/* width: 250px; */
|
||||||
|
/* margin: auto; */
|
||||||
|
margin: 2rem;
|
||||||
|
background: #ffffff;
|
||||||
|
border-radius: 25px;
|
||||||
|
/* box-shadow: 7px 20px 20px rgb(210, 227, 244); */
|
||||||
|
}
|
||||||
|
.file-upload {
|
||||||
|
text-align: center;
|
||||||
|
border: 3px dashed rgb(210, 227, 244);
|
||||||
|
/* padding: 1.5rem; */
|
||||||
|
position: relative;
|
||||||
|
cursor: pointer;
|
||||||
|
width: 100px;
|
||||||
|
height: 50px;
|
||||||
|
|
||||||
|
}
|
||||||
|
.file-upload p {
|
||||||
|
font-size: 0.5rem;
|
||||||
|
/* margin-top: 10px; */
|
||||||
|
color: #bbcada;
|
||||||
|
}
|
||||||
|
.file-upload input {
|
||||||
|
display: block;
|
||||||
|
height: 100%;
|
||||||
|
width: 100%;
|
||||||
|
position: absolute;
|
||||||
|
top: 0;
|
||||||
|
bottom: 0;
|
||||||
|
left: 0;
|
||||||
|
right: 0;
|
||||||
|
opacity: 0;
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
@ -0,0 +1,194 @@
|
|||||||
|
import React, { useEffect, useState } from 'react';
|
||||||
|
import ProfilePDP from '../Components/ProfilePDP';
|
||||||
|
|
||||||
|
import SessionService from '../services/SessionService';
|
||||||
|
import { PlayerProps } from '../types/Player';
|
||||||
|
import { delay, update } from 'lodash';
|
||||||
|
import { socket } from '../SocketConfig';
|
||||||
|
import AuthService from '../services/AuthService';
|
||||||
|
|
||||||
|
|
||||||
|
/* Style */
|
||||||
|
import './Profile.css'
|
||||||
|
import Edit from "../res/icon/edit-pen.png"
|
||||||
|
import Coche from '../res/icon/coche.png'
|
||||||
|
import Cancel from '../res/icon/cancel.png'
|
||||||
|
|
||||||
|
/* Model */
|
||||||
|
import User from '../model/User';
|
||||||
|
|
||||||
|
/* Context */
|
||||||
|
import { useAuth } from '../Contexts/AuthContext';
|
||||||
|
|
||||||
|
/* Boostrap */
|
||||||
|
import Button from 'react-bootstrap/Button';
|
||||||
|
import Alert from 'react-bootstrap/Alert';
|
||||||
|
import Modal from 'react-bootstrap/Modal';
|
||||||
|
import Form from 'react-bootstrap/Form';
|
||||||
|
import { useNavigate } from 'react-router-dom';
|
||||||
|
|
||||||
|
//@ts-ignore
|
||||||
|
const Profile = () => {
|
||||||
|
|
||||||
|
const navigate = useNavigate();
|
||||||
|
//let player;
|
||||||
|
const {user, logout} = useAuth()
|
||||||
|
|
||||||
|
// let pseudoNotNull;
|
||||||
|
// if(user?.pseudo != null){
|
||||||
|
// pseudoNotNull = user.pseudo;
|
||||||
|
// }
|
||||||
|
|
||||||
|
const [editingUsername, setEditingUsername] = useState(false);
|
||||||
|
const [newUsername, setNewUsername] = useState(user?.pseudo);
|
||||||
|
|
||||||
|
//@ts-ignore
|
||||||
|
const onUsernameChange = (newUsername) => {
|
||||||
|
if(user?.pseudo != null){
|
||||||
|
SessionService.UpdatePseudo(user.pseudo, newUsername)
|
||||||
|
user.pseudo = newUsername;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const handleUsernameChange = () => {
|
||||||
|
// Maj du pseudo
|
||||||
|
onUsernameChange(newUsername);
|
||||||
|
|
||||||
|
// Désactiver le mode d'édition
|
||||||
|
setEditingUsername(false);
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
//* Gestion Modal de suppression :
|
||||||
|
const [showDeleteModal, setShowDeleteModal] = useState(false);
|
||||||
|
|
||||||
|
const handleShowDeleteModal = () => {
|
||||||
|
setShowDeleteModal(true);
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleCloseDeleteModal = () => {
|
||||||
|
setShowDeleteModal(false);
|
||||||
|
};
|
||||||
|
|
||||||
|
//* Confirmation avec la phrase :
|
||||||
|
const [confirmationPhrase, setConfirmationPhrase] = useState('');
|
||||||
|
|
||||||
|
const [showWrong, setShowWrong] = useState(false);
|
||||||
|
|
||||||
|
//@ts-ignore
|
||||||
|
const handleConfirmationPhraseChange = (e) => {
|
||||||
|
setConfirmationPhrase(e.target.value);
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleDeleteAccount = () => {
|
||||||
|
// Verification de la phrase
|
||||||
|
if (confirmationPhrase.toLowerCase() === 'supprimer mon compte') {
|
||||||
|
console.log('Compte supprimé !');
|
||||||
|
console.log(user);
|
||||||
|
|
||||||
|
if(user!= null){
|
||||||
|
const pseudo = user.pseudo;
|
||||||
|
AuthService.delAccount(pseudo);
|
||||||
|
AuthService.logout();
|
||||||
|
logout();
|
||||||
|
}
|
||||||
|
else{
|
||||||
|
console.error("l'utilisateur ne peut pas être null")
|
||||||
|
}
|
||||||
|
handleCloseDeleteModal();
|
||||||
|
|
||||||
|
navigate("/play")
|
||||||
|
|
||||||
|
} else {
|
||||||
|
console.error('Phrase de confirmation incorrecte.');
|
||||||
|
setShowWrong(true);
|
||||||
|
setTimeout(async () => {
|
||||||
|
setShowWrong(false);
|
||||||
|
}, 3000);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<center><h1>Mon Compte</h1></center>
|
||||||
|
<div className='mainContainer'>
|
||||||
|
<div>
|
||||||
|
<ProfilePDP/>
|
||||||
|
</div>
|
||||||
|
<div className='Rpart'>
|
||||||
|
{editingUsername ? (
|
||||||
|
<div className='username-edit'>
|
||||||
|
<input
|
||||||
|
type='text'
|
||||||
|
className='inputpseudo'
|
||||||
|
value={newUsername}
|
||||||
|
onChange={(e) => setNewUsername(e.target.value)}
|
||||||
|
/>
|
||||||
|
<button className='editbutton' onClick={handleUsernameChange}>
|
||||||
|
<img src={Coche} alt='edit' width='25' height='25'/>
|
||||||
|
</button>
|
||||||
|
<button className='editbutton' onClick={() => setEditingUsername(false)}>
|
||||||
|
<img src={Cancel} alt='edit' width='25' height='25'/>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
) : (
|
||||||
|
<div className='username-display'>
|
||||||
|
<h1>{user?.pseudo}</h1>
|
||||||
|
<button className='editbutton' onClick={() => setEditingUsername(true)}>
|
||||||
|
<img src={Edit} alt='edit' width='25' height='25'/>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
<hr/>
|
||||||
|
{!editingUsername ? (
|
||||||
|
<Button variant="secondary">Modifier le mot de passe</Button>
|
||||||
|
) : (
|
||||||
|
<Alert key='info' variant='info' style={{width:'100%'}}>
|
||||||
|
Vous êtes en mode "édition".
|
||||||
|
</Alert>
|
||||||
|
)}
|
||||||
|
<div className='bottom'>
|
||||||
|
<>
|
||||||
|
<Button variant="danger" onClick={handleShowDeleteModal}>Supprimer</Button>
|
||||||
|
|
||||||
|
<Modal show={showDeleteModal} onHide={handleCloseDeleteModal}>
|
||||||
|
<Modal.Header closeButton>
|
||||||
|
<Modal.Title>Confirmation de suppression</Modal.Title>
|
||||||
|
</Modal.Header>
|
||||||
|
<Modal.Body>
|
||||||
|
<p>
|
||||||
|
Pour confirmer la suppression de votre compte, veuillez
|
||||||
|
entrer la phrase : "supprimer mon compte".
|
||||||
|
</p>
|
||||||
|
<Form.Control
|
||||||
|
type='text'
|
||||||
|
placeholder='Entrez la phrase de confirmation'
|
||||||
|
value={confirmationPhrase}
|
||||||
|
onChange={handleConfirmationPhraseChange}
|
||||||
|
/>
|
||||||
|
{
|
||||||
|
showWrong &&
|
||||||
|
<Alert key='infomodel' variant='danger' style={{width:'100%'}}>
|
||||||
|
La phrase de confirmation est incorrecte.
|
||||||
|
</Alert>
|
||||||
|
}
|
||||||
|
</Modal.Body>
|
||||||
|
<Modal.Footer>
|
||||||
|
<Button variant='secondary' onClick={handleCloseDeleteModal}>
|
||||||
|
Annuler
|
||||||
|
</Button>
|
||||||
|
<Button variant='danger' onClick={handleDeleteAccount}>Supprimer mon compte</Button>
|
||||||
|
</Modal.Footer>
|
||||||
|
</Modal>
|
||||||
|
</>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default Profile;
|
Before Width: | Height: | Size: 13 KiB After Width: | Height: | Size: 13 KiB |
Before Width: | Height: | Size: 254 KiB After Width: | Height: | Size: 254 KiB |
Before Width: | Height: | Size: 26 KiB After Width: | Height: | Size: 26 KiB |
Before Width: | Height: | Size: 12 KiB After Width: | Height: | Size: 12 KiB |
Before Width: | Height: | Size: 25 KiB After Width: | Height: | Size: 25 KiB |
@ -1,6 +1,6 @@
|
|||||||
import { io } from "socket.io-client";
|
import { io } from "socket.io-client";
|
||||||
|
import { ADRESSE_WEBSERVER } from "./AdressSetup";
|
||||||
|
|
||||||
|
const socket = io(ADRESSE_WEBSERVER);
|
||||||
const socket = io("http://172.20.10.4:3002");
|
|
||||||
|
|
||||||
export {socket}
|
export {socket}
|
@ -0,0 +1,74 @@
|
|||||||
|
import SessionService from "../../services/SessionService";
|
||||||
|
import { socket } from "../../SocketConfig";
|
||||||
|
import User from "../User";
|
||||||
|
import IUserService from "./IUserService";
|
||||||
|
|
||||||
|
class DbUserService implements IUserService{
|
||||||
|
async fetchUserInformation(): Promise<[User | null, boolean]> {
|
||||||
|
try {
|
||||||
|
const sessionData = await SessionService.getSession();
|
||||||
|
|
||||||
|
// Vérifie si il y a une session
|
||||||
|
if (sessionData.user) {
|
||||||
|
// Il y a une session on récupère les infos du joueur
|
||||||
|
const updatedPlayer: User = new User(socket.id, sessionData.user.pseudo, sessionData.user.profilePicture, {
|
||||||
|
nbGames: sessionData.user.soloStats.nbGames,
|
||||||
|
bestScore: sessionData.user.soloStats.bestScore,
|
||||||
|
avgNbTry: sessionData.user.soloStats.avgNbTry,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
nbGames: sessionData.user.onlineStats.nbGames,
|
||||||
|
nbWins: sessionData.user.onlineStats.nbWins,
|
||||||
|
ratio: sessionData.user.onlineStats.ratio,
|
||||||
|
})
|
||||||
|
return [updatedPlayer, true]
|
||||||
|
} else {
|
||||||
|
// Pas de session on génère un guest random
|
||||||
|
const guestPlayer: User = new User(socket.id, 'Guest_' + Math.floor(Math.random() * 1000000), '',
|
||||||
|
{
|
||||||
|
nbGames: 0,
|
||||||
|
bestScore: 0,
|
||||||
|
avgNbTry: 0,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
nbGames: 0,
|
||||||
|
nbWins: 0,
|
||||||
|
ratio: 0,
|
||||||
|
})
|
||||||
|
return [guestPlayer, false]
|
||||||
|
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.error(error);
|
||||||
|
return [null, false]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async updateSoloStats(pseudo: string, nbGames: number, bestScore: number, avgNbTry: number): Promise<void> {
|
||||||
|
try {
|
||||||
|
const result = await SessionService.updateSoloStats(pseudo, nbGames, bestScore, avgNbTry);
|
||||||
|
if (result) {
|
||||||
|
console.log("Stats solo updated");
|
||||||
|
} else {
|
||||||
|
console.log("Stats solo not updated");
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.error(error);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async updateOnlineStats(pseudo: string, nbGames: number, bestScore: number, ratio: number): Promise<void> {
|
||||||
|
try {
|
||||||
|
const result = await SessionService.updateOnlineStats(pseudo, nbGames, bestScore, ratio);
|
||||||
|
if (result) {
|
||||||
|
console.log("Stats online updated");
|
||||||
|
} else {
|
||||||
|
console.log("Stats online not updated");
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.error(error);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export default DbUserService
|
@ -0,0 +1,10 @@
|
|||||||
|
import User from "../User";
|
||||||
|
|
||||||
|
interface IUserService{
|
||||||
|
fetchUserInformation(): Promise<[User | null, boolean]>
|
||||||
|
updateSoloStats(pseudo: string, nbGames: number, bestScore: number, avgNbTry: number): Promise<void>
|
||||||
|
updateOnlineStats(pseudo: string, nbGames: number, bestScore: number, ratio: number): Promise<void>
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
export default IUserService
|
@ -0,0 +1,12 @@
|
|||||||
|
import IUserService from "./IUserService";
|
||||||
|
|
||||||
|
class Manager{
|
||||||
|
|
||||||
|
public userService: IUserService
|
||||||
|
|
||||||
|
constructor(userService: IUserService){
|
||||||
|
this.userService = userService
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export default Manager
|
After Width: | Height: | Size: 1010 B |
After Width: | Height: | Size: 302 B |
After Width: | Height: | Size: 613 B |
@ -0,0 +1,17 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
|
||||||
|
node server/server.js &
|
||||||
|
|
||||||
|
node src/server/server.js
|
||||||
|
|
||||||
|
if lsof -Pi :3002 -sTCP:LISTEN -t >/dev/null; then
|
||||||
|
# Tuer le processus associé au port
|
||||||
|
pid=$(lsof -Pi :3002 -sTCP:LISTEN -t)
|
||||||
|
kill -9 $pid
|
||||||
|
fi
|
||||||
|
|
||||||
|
if lsof -Pi :3003 -sTCP:LISTEN -t >/dev/null; then
|
||||||
|
# Tuer le processus associé au port
|
||||||
|
pid=$(lsof -Pi :3003 -sTCP:LISTEN -t)
|
||||||
|
kill -9 $pid
|
||||||
|
fi
|
@ -1,3 +0,0 @@
|
|||||||
\relax
|
|
||||||
\@writefile{toc}{\contentsline {paragraph}{Première énigme}{2}{}\protected@file@percent }
|
|
||||||
\gdef \@abspage@last{2}
|
|
@ -1,132 +0,0 @@
|
|||||||
\documentclass[11pt]{article}
|
|
||||||
\usepackage{fullpage}
|
|
||||||
\usepackage{times}
|
|
||||||
\usepackage{tikz}
|
|
||||||
\usepackage{paralist}
|
|
||||||
\usetikzlibrary {shapes.multipart}
|
|
||||||
\newcommand{\Basketball}{\includegraphics[width=.5cm]{ballon-de-basket.png}}
|
|
||||||
\newcommand{\Football}{\includegraphics[width=.4cm]{ballon-de-foot.png}}
|
|
||||||
\newcommand{\Bowling}{\includegraphics[width=.5cm]{bowling.png}}
|
|
||||||
\newcommand{\Baseball}{\includegraphics[width=.5cm]{baseball.png}}
|
|
||||||
\newcommand{\Tennis}{\includegraphics[width=.5cm]{tennis.png}}
|
|
||||||
\begin{document}
|
|
||||||
\thispagestyle{empty}
|
|
||||||
Voici le graphe de SocialGraphe
|
|
||||||
\begin{center}
|
|
||||||
\begin{tikzpicture}[scale=.9]
|
|
||||||
\node[draw, circle split] (0) at (0,0) { Alexander \nodepart{lower} \Football{} \Bowling{}};
|
|
||||||
\node[draw, circle split] (1) at (4,0) { Wyatt \nodepart{lower} \Baseball{} \Tennis{}};
|
|
||||||
\node[draw, circle split] (2) at (8,0) { Mia \nodepart{lower} \Basketball{}};
|
|
||||||
\node[draw, circle split] (3) at (12,0) { William \nodepart{lower} \Baseball{} \Football{}};
|
|
||||||
\node[draw, circle split] (4) at (16,0) { Zoey \nodepart{lower} \Basketball{} \Bowling{} \Tennis{}};
|
|
||||||
\node[draw, circle split] (5) at (0,4) { Isabella \nodepart{lower} \Tennis{}};
|
|
||||||
\node[draw, circle split] (6) at (4,4) { Abigail \nodepart{lower} \Baseball{}};
|
|
||||||
\node[draw, circle split] (7) at (8,4) { Savannah \nodepart{lower} \Bowling{} \Basketball{} \Football{}};
|
|
||||||
\node[draw, circle split] (8) at (12,4) { Peyton \nodepart{lower} \Football{}};
|
|
||||||
\node[draw, circle split] (9) at (16,4) { Alice \nodepart{lower} \Tennis{} \Baseball{}};
|
|
||||||
\node[draw, circle split] (10) at (0,8) { Sophia \nodepart{lower} \Bowling{} \Basketball{} \Bowling{}};
|
|
||||||
\node[draw, circle split] (11) at (4,8) { Layla \nodepart{lower} \Tennis{} \Baseball{} \Football{}};
|
|
||||||
\node[draw, circle split] (12) at (8,8) { Ava \nodepart{lower} \Basketball{}};
|
|
||||||
\node[draw, circle split] (13) at (12,8) { Harper \nodepart{lower} \Bowling{}};
|
|
||||||
\node[draw, circle split] (14) at (16,8) { Sebastian \nodepart{lower} \Tennis{} \Basketball{} \Baseball{}};
|
|
||||||
\node[draw, circle split] (15) at (0,12) { Michael \nodepart{lower} \Football{}};
|
|
||||||
\node[draw, circle split] (16) at (4,12) { Natalie \nodepart{lower} \Bowling{} \Football{} \Baseball{}};
|
|
||||||
\node[draw, circle split] (17) at (8,12) { Penelope \nodepart{lower} \Basketball{}};
|
|
||||||
\node[draw, circle split] (18) at (12,12) { Lily \nodepart{lower} \Tennis{} \Tennis{}};
|
|
||||||
\node[draw, circle split] (19) at (16,12) { Eleanor \nodepart{lower} \Football{}};
|
|
||||||
\node[draw, circle split] (20) at (0,16) { Henry \nodepart{lower} \Bowling{} \Basketball{}};
|
|
||||||
\node[draw, circle split] (21) at (4,16) { Claire \nodepart{lower} \Baseball{} \Basketball{}};
|
|
||||||
\node[draw, circle split] (22) at (8,16) { Caleb \nodepart{lower} \Baseball{}};
|
|
||||||
\node[draw, circle split] (23) at (12,16) { Charlotte \nodepart{lower} \Bowling{} \Football{} \Tennis{}};
|
|
||||||
\node[draw, circle split] (24) at (16,16) { Luke \nodepart{lower} \Football{}};
|
|
||||||
\node[draw, circle split] (25) at (0,20) { Connor \nodepart{lower} \Baseball{} \Tennis{}};
|
|
||||||
\node[draw, circle split] (26) at (4,20) { Aiden \nodepart{lower} \Basketball{} \Bowling{} \Tennis{}};
|
|
||||||
\node[draw, circle split] (27) at (8,20) { Aurora \nodepart{lower} \Football{}};
|
|
||||||
\node[draw, circle split] (28) at (12,20) { Nathan \nodepart{lower} \Bowling{} \Baseball{}};
|
|
||||||
\node[draw, circle split] (29) at (16,20) { Aurora \nodepart{lower} \Basketball{}};
|
|
||||||
\draw (0) -- (11);
|
|
||||||
\draw (0) -- (13);
|
|
||||||
\draw (0) -- (18);
|
|
||||||
\draw (1) -- (13);
|
|
||||||
\draw (1) -- (24);
|
|
||||||
\draw (2) -- (22);
|
|
||||||
\draw (2) -- (16);
|
|
||||||
\draw (2) -- (9);
|
|
||||||
\draw (2) -- (6);
|
|
||||||
\draw (3) -- (4);
|
|
||||||
\draw (3) -- (20);
|
|
||||||
\draw (4) -- (28);
|
|
||||||
\draw (4) -- (3);
|
|
||||||
\draw (5) -- (17);
|
|
||||||
\draw (5) -- (15);
|
|
||||||
\draw (5) -- (24);
|
|
||||||
\draw (6) -- (2);
|
|
||||||
\draw (7) -- (17);
|
|
||||||
\draw (7) -- (24);
|
|
||||||
\draw (7) -- (22);
|
|
||||||
\draw (7) -- (11);
|
|
||||||
\draw (8) -- (25);
|
|
||||||
\draw (8) -- (21);
|
|
||||||
\draw (8) -- (24);
|
|
||||||
\draw (8) -- (11);
|
|
||||||
\draw (9) -- (2);
|
|
||||||
\draw (10) -- (25);
|
|
||||||
\draw (10) -- (26);
|
|
||||||
\draw (10) -- (27);
|
|
||||||
\draw (11) -- (0);
|
|
||||||
\draw (11) -- (7);
|
|
||||||
\draw (11) -- (8);
|
|
||||||
\draw (12) -- (20);
|
|
||||||
\draw (12) -- (27);
|
|
||||||
\draw (13) -- (0);
|
|
||||||
\draw (13) -- (1);
|
|
||||||
\draw (14) -- (15);
|
|
||||||
\draw (15) -- (5);
|
|
||||||
\draw (15) -- (14);
|
|
||||||
\draw (15) -- (20);
|
|
||||||
\draw (15) -- (17);
|
|
||||||
\draw (16) -- (2);
|
|
||||||
\draw (16) -- (26);
|
|
||||||
\draw (17) -- (5);
|
|
||||||
\draw (17) -- (7);
|
|
||||||
\draw (17) -- (15);
|
|
||||||
\draw (17) -- (20);
|
|
||||||
\draw (18) -- (0);
|
|
||||||
\draw (19) -- (23);
|
|
||||||
\draw (20) -- (3);
|
|
||||||
\draw (20) -- (12);
|
|
||||||
\draw (20) -- (15);
|
|
||||||
\draw (20) -- (17);
|
|
||||||
\draw (21) -- (8);
|
|
||||||
\draw (22) -- (2);
|
|
||||||
\draw (22) -- (7);
|
|
||||||
\draw (22) -- (23);
|
|
||||||
\draw (23) -- (19);
|
|
||||||
\draw (23) -- (22);
|
|
||||||
\draw (24) -- (1);
|
|
||||||
\draw (24) -- (5);
|
|
||||||
\draw (24) -- (7);
|
|
||||||
\draw (24) -- (8);
|
|
||||||
\draw (25) -- (8);
|
|
||||||
\draw (25) -- (10);
|
|
||||||
\draw (26) -- (10);
|
|
||||||
\draw (26) -- (16);
|
|
||||||
\draw (26) -- (29);
|
|
||||||
\draw (27) -- (10);
|
|
||||||
\draw (27) -- (12);
|
|
||||||
\draw (28) -- (4);
|
|
||||||
\draw (29) -- (26);
|
|
||||||
\end{tikzpicture}
|
|
||||||
\end{center}
|
|
||||||
|
|
||||||
|
|
||||||
\paragraph{Première énigme}
|
|
||||||
Trouver qui est le coupable avec les indices suivants.
|
|
||||||
\begin{compactitem}
|
|
||||||
\item Indice 1 : Le suspect pratique au moins du Baseball et/ou du Basketball .
|
|
||||||
\item Indice 2 : Le suspect pratique 2 ou 1 sport(s).
|
|
||||||
\item Indice 3 : Le suspect a les cheveux Roux ou Blond .
|
|
||||||
\item Indice 4 : Le suspect a au moins un ami avec les cheveux Roux .
|
|
||||||
\end{compactitem}
|
|
||||||
% Solution : Nathan
|
|
||||||
\end{document}
|
|