Merge branch 'master' of https://github.com/jsmaniac/2011-m1s2-ter
This commit is contained in:
commit
e02b802ea8
|
@ -19,4 +19,6 @@
|
|||
|
||||
|
||||
<uses-permission android:name="android.permission.INTERNET"></uses-permission>
|
||||
|
||||
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"></uses-permission>
|
||||
</manifest>
|
||||
|
|
|
@ -1,8 +1,11 @@
|
|||
package org.pticlic;
|
||||
|
||||
import org.pticlic.games.BaseGame;
|
||||
import org.pticlic.model.Network;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.app.AlertDialog;
|
||||
import android.content.DialogInterface;
|
||||
import android.content.Intent;
|
||||
import android.content.SharedPreferences;
|
||||
import android.os.Bundle;
|
||||
|
@ -19,17 +22,23 @@ public class FrontPage extends Activity implements OnClickListener{
|
|||
public void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
setContentView(R.layout.frontpage);
|
||||
|
||||
|
||||
// Écoute des clics sur les différents boutons
|
||||
((ImageView)findViewById(R.id.prefs)).setOnClickListener(this);
|
||||
((ImageView)findViewById(R.id.play)).setOnClickListener(this);
|
||||
((ImageView)findViewById(R.id.infoButton)).setOnClickListener(this);
|
||||
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
protected void onStart() {
|
||||
super.onStart();
|
||||
|
||||
|
||||
if (Network.isConnected(this))
|
||||
System.out.println("Connecter");
|
||||
else
|
||||
System.out.println("Non Connecter");
|
||||
|
||||
// On récupère le nom du joueur des préférences.
|
||||
SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(this);
|
||||
String loginPref = sp.getString("login", "joueur");
|
||||
|
@ -44,14 +53,34 @@ public class FrontPage extends Activity implements OnClickListener{
|
|||
public void onClick(View v) {
|
||||
switch (v.getId()) {
|
||||
case (R.id.prefs) : startActivity(new Intent(this, Preference.class)); break;
|
||||
case (R.id.play) : startActivity(new Intent(this, BaseGame.class)); break;
|
||||
case (R.id.play) : checkNetworkConnection(BaseGame.class); break;
|
||||
case (R.id.infoButton) : startActivity(new Intent(this, Information.class)); break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@SuppressWarnings("rawtypes")
|
||||
private void checkNetworkConnection(Class c) {
|
||||
if (Network.isConnected(this)) {
|
||||
startActivity(new Intent(this, c));
|
||||
} else {
|
||||
AlertDialog.Builder builder = new AlertDialog.Builder(this);
|
||||
builder.setTitle(getString(R.string.app_name))
|
||||
.setIcon(android.R.drawable.ic_dialog_alert)
|
||||
.setMessage("Problème de connexion au serveur. Vérifiez que vous êtes connecté au réseau.")
|
||||
.setCancelable(false)
|
||||
.setNegativeButton("Ok", new DialogInterface.OnClickListener() {
|
||||
public void onClick(DialogInterface dialog, int id) {
|
||||
dialog.cancel();
|
||||
}
|
||||
});
|
||||
AlertDialog alert = builder.create();
|
||||
alert.show();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onBackPressed() {
|
||||
System.exit(0);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
|
|
@ -10,6 +10,8 @@ import org.pticlic.model.Network.Mode;
|
|||
import org.pticlic.model.Relation;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.app.AlertDialog;
|
||||
import android.content.DialogInterface;
|
||||
import android.content.Intent;
|
||||
import android.content.SharedPreferences;
|
||||
import android.os.Bundle;
|
||||
|
@ -39,12 +41,14 @@ import android.widget.TextView;
|
|||
* proposer celle qui lui semble le mieux approprier.
|
||||
*
|
||||
*/
|
||||
|
||||
public class BaseGame extends Activity implements OnClickListener, AnimationListener {
|
||||
private int currentWord = 0;
|
||||
private TextView currentWordTextView;
|
||||
private int nbWord = 0;
|
||||
private DownloadedGame game;
|
||||
private Match match;
|
||||
private Network network;
|
||||
|
||||
/** Called when the activity is first created. */
|
||||
@Override
|
||||
|
@ -60,6 +64,7 @@ public class BaseGame extends Activity implements OnClickListener, AnimationList
|
|||
|
||||
// On initialise la classe permettant la communication avec le serveur.
|
||||
Network network = new Network(serverURL, Mode.SIMPLE_GAME, id, passwd);
|
||||
|
||||
game = network.getGames(1);
|
||||
int nbrel = game.getNbRelation();
|
||||
nbWord = game.getNbWord();
|
||||
|
@ -68,14 +73,14 @@ public class BaseGame extends Activity implements OnClickListener, AnimationList
|
|||
match = new Match();
|
||||
match.setGame(game);
|
||||
|
||||
Relation r = Relation.getInstance();
|
||||
|
||||
// Boutons des relations
|
||||
ImageView r1 = ((ImageView)findViewById(R.id.relation1));
|
||||
ImageView r2 = ((ImageView)findViewById(R.id.relation2));
|
||||
ImageView r3 = ((ImageView)findViewById(R.id.relation3));
|
||||
ImageView r4 = ((ImageView)findViewById(R.id.relation4));
|
||||
|
||||
|
||||
Relation r = Relation.getInstance();
|
||||
|
||||
// TODO : Pour l'instant la poubelle ne fait rien. Il faudra certainement la ranger dans un categorie dans GamePlayed pour calculer le score.
|
||||
ImageView trash = ((ImageView)findViewById(R.id.trash));
|
||||
trash.setOnClickListener(this);
|
||||
|
@ -120,7 +125,7 @@ public class BaseGame extends Activity implements OnClickListener, AnimationList
|
|||
//On recupere le centre de mainWord pour l'animation de translation.
|
||||
TextView mainWord = (TextView)findViewById(R.id.mainWord);
|
||||
currentWordTextView = (TextView)findViewById(R.id.currentWord);
|
||||
|
||||
|
||||
// On defini un ensemble d'animation
|
||||
AnimationSet set = new AnimationSet(true);
|
||||
set.setDuration(1000);
|
||||
|
@ -187,18 +192,18 @@ public class BaseGame extends Activity implements OnClickListener, AnimationList
|
|||
|
||||
@Override
|
||||
public void onAnimationEnd(Animation animation) {
|
||||
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onAnimationRepeat(Animation animation) {
|
||||
// TODO Auto-generated method stub
|
||||
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onAnimationStart(Animation animation) {
|
||||
// TODO Auto-generated method stub
|
||||
|
||||
|
||||
}
|
||||
}
|
|
@ -1,10 +1,18 @@
|
|||
package org.pticlic.model;
|
||||
|
||||
import java.io.BufferedReader;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.InputStreamReader;
|
||||
import java.net.MalformedURLException;
|
||||
import java.net.URL;
|
||||
import java.net.URLConnection;
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.SharedPreferences;
|
||||
import android.net.ConnectivityManager;
|
||||
import android.preference.PreferenceManager;
|
||||
|
||||
import com.google.gson.Gson;
|
||||
import com.google.gson.stream.JsonReader;
|
||||
|
||||
|
@ -54,6 +62,55 @@ public class Network {
|
|||
this.passwd = passwd;
|
||||
}
|
||||
|
||||
/**
|
||||
* Permet de savoir si l'application a access a internet ou non
|
||||
*
|
||||
* @param context l'activite permettant de tester l'access a internet
|
||||
* @return <code>true</code> si on a access a internet <code>false</code> sinon
|
||||
*/
|
||||
public static boolean isConnected(Context context) {
|
||||
ConnectivityManager cm = (ConnectivityManager)context.getSystemService(Context.CONNECTIVITY_SERVICE);
|
||||
if (cm != null && (cm.getActiveNetworkInfo() == null
|
||||
|| !cm.getActiveNetworkInfo().isConnected())) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Permet de verifier que la combinaison login/mdp est correct
|
||||
*
|
||||
* @param context l'activite permettant de tester l'access a internet
|
||||
* @param id l'identifiant de l'utilisateur
|
||||
* @param passwd le mot de passe de l'utilisateur
|
||||
* @return <code>true</code> si la combinaison login/mdp est correct <code>false</code> sinon
|
||||
*/
|
||||
public static boolean isLoginCorrect(Context context, String id, String passwd) {
|
||||
SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(context);
|
||||
String serverURL = sp.getString(Constant.SERVER_URL, "http://dumbs.fr/~bbrun/pticlic.json");
|
||||
|
||||
URL url;
|
||||
boolean res = false;
|
||||
try {
|
||||
url = new URL(serverURL);
|
||||
URLConnection connection = url.openConnection();
|
||||
connection.addRequestProperty("action", "verifyAccess");
|
||||
connection.addRequestProperty("user", id);
|
||||
connection.addRequestProperty("passwd", passwd);
|
||||
|
||||
InputStream in = connection.getInputStream();
|
||||
BufferedReader buf = new BufferedReader(new InputStreamReader(in));
|
||||
res = Boolean.getBoolean(buf.readLine());
|
||||
|
||||
} catch (MalformedURLException e) {
|
||||
return false;
|
||||
} catch (IOException e) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
/**
|
||||
* Cette méthode permet de récupérer du serveur un certain nombre de parties.
|
||||
* @param nbGames Le nombre de parties que l'on veut récupérer.
|
||||
|
@ -171,12 +228,12 @@ public class Network {
|
|||
for (Integer i : game.getTrash()) {
|
||||
connection.addRequestProperty("trash[]", i.toString());
|
||||
}
|
||||
|
||||
|
||||
Gson gson = new Gson();
|
||||
JsonReader reader = new JsonReader(new InputStreamReader(connection.getInputStream(), "UTF-8"));
|
||||
|
||||
score = gson.fromJson(reader, TotalScore.class);
|
||||
|
||||
|
||||
|
||||
} catch (IOException e) {
|
||||
return score;
|
||||
|
|
|
@ -15,7 +15,7 @@ create table node(eid integer primary key autoincrement, name, type, weight);
|
|||
create table relation(rid integer primary key autoincrement, start, end, type, weight);
|
||||
create table type_node(name, num);
|
||||
create table type_relation(name, num, extended_name, info);
|
||||
create table user(login primary key, mail, hash_passwd);
|
||||
create table user(login primary key, mail, hash_passwd, score);
|
||||
create table game(gid integer primary key autoincrement, eid_central_word, relation_1, relation_2, difficulty);
|
||||
create table game_cloud(gid, num, difficulty, eid_word, totalWeight, probaR1, probaR2, probaR0, probaTrash);
|
||||
create table played_game(pgid integer primary key autoincrement, gid, login);
|
||||
|
|
|
@ -12,16 +12,16 @@ function mDie($err,$msg)
|
|||
exit;
|
||||
}
|
||||
|
||||
if (!$db = new SQLite3('db')) {
|
||||
if (!$db = new SQlite3($SQL_DBNAME)) {
|
||||
mDie(1,"Erreur lors de l'ouverture de la base de données SQLite3");
|
||||
}
|
||||
|
||||
function initdb() {
|
||||
global $db;
|
||||
$db->exec("insert into user(login, mail, hash_passwd) values('foo', 'foo@isp.com', '".md5('bar')."');");
|
||||
$db->exec("insert into user(login, mail, hash_passwd, score) values('foo', 'foo@isp.com', '".md5('bar')."', 0);");
|
||||
}
|
||||
|
||||
if ($do_initdb) initdb();
|
||||
if ($do_initdb) { initdb(); }
|
||||
|
||||
if(!isset($_GET['action']) || !isset($_GET['user']) || !isset($_GET['passwd']))
|
||||
mDie(2,"La requête est incomplète");
|
||||
|
@ -179,8 +179,6 @@ function create_game($cloudSize) {
|
|||
cg_insert($centerEid, $cloud, $r1, $r2, $totalDifficulty);
|
||||
}
|
||||
|
||||
//create_game(10);
|
||||
|
||||
function random_game() {
|
||||
global $db;
|
||||
return $db->querySingle("select gid from game where gid = (abs(random()) % (select max(gid) from game))+1 or gid = (select max(gid) from game where gid > 0) order by gid limit 1;");
|
||||
|
@ -196,15 +194,26 @@ function game2json($game_id) {
|
|||
echo "cloudsize:10,cloud:["; // TODO ! compter dynamiquement.
|
||||
|
||||
$res = $db->query("select eid_word,(select name from node where eid=eid_word) as name_word from game_cloud where gid = ".$game['gid'].";");
|
||||
$notfirst = false;
|
||||
while ($x = $res->fetchArray()) {
|
||||
echo "{id:".$x['eid_word'].",name:".$x['name_word']."}\n";
|
||||
if ($notfirst) { echo ","; } else { $notfirst=true; }
|
||||
echo "{id:".$x['eid_word'].",name:".$x['name_word']."}";
|
||||
}
|
||||
echo "]}";
|
||||
}
|
||||
|
||||
function main() {
|
||||
function main($action) {
|
||||
// Sinon tout est bon on effectu l'opération correspondant à la commande passée.
|
||||
if($action == 0) { // "Get partie"
|
||||
// TODO : en production, utiliser : header("Content-Type: application/json; charset=utf-8");
|
||||
header("Content-Type: text/plain; charset=utf-8");
|
||||
if ($action == 2) { // "Create partie"
|
||||
if(!isset($_GET['nb']) || !isset($_GET['mode']))
|
||||
mDie(2,"La requête est incomplète");
|
||||
$nbParties = intval($_GET['nb']);
|
||||
for ($i = 0; $i < $nbParties; $i++) {
|
||||
create_game(10);
|
||||
}
|
||||
} else if ($action == 0) { // "Get partie"
|
||||
if(!isset($_GET['nb']) || !isset($_GET['mode']))
|
||||
mDie(2,"La requête est incomplète");
|
||||
$nbGames = intval($_GET['nb']);
|
||||
|
@ -220,16 +229,26 @@ function main() {
|
|||
} else if($action == 1) { // "Set partie"
|
||||
// Requête sql d'ajout d'informations (et calcul de résultat).
|
||||
// TODO : nettoyer, finir
|
||||
$gid = $_GET['gid']; // TODO : vérifier qu'on a bien distribué cette partie à cet utilisateur, et qu'il n'y a pas déjà répondu (répercuter ça sur le random_game).
|
||||
$userReputation = 5; // TODO : un nombre entre 0 et 5 environ. Par ex. log(pointsUtilisateur) est un bon choix.
|
||||
|
||||
$gid = $_GET['gid'];
|
||||
|
||||
if(ĝid != $db->querySingle("SELECT gid FROM played_game WHERE login='".$user."'"))
|
||||
mdie(3,"Cette partie n'est associée à votre nom d'utilisateur");
|
||||
|
||||
$userReputation = log($db->querySingle("SELECT score FROM user WHERE login='".$user."'"));
|
||||
|
||||
$db->exec("begin transaction;");
|
||||
$db->exec("insert into played_game(pgid, gid, login) values (null, $gid, null);");
|
||||
$db->exec("INSERT INTO played_game(pgid, gid, login) VALUES (null, $gid, null);");
|
||||
$pgid = $db->lastInsertRowID();
|
||||
for ($i=0; $i < 10; $i++) {
|
||||
|
||||
for($i=0; $i < 10; $i++)
|
||||
{
|
||||
$x = $_GET['$i'];
|
||||
|
||||
// TODO : calculer le score. Score = proba[réponse de l'utilisateur]*coeff - proba[autres reponses]*coeff
|
||||
// TODO : adapter le score en fonction de la réputation de l'utilisateur (plus quand il est jeune, pour le motiver, par ex. avec un terme constant qu'on ajoute).
|
||||
$score = 1;
|
||||
|
||||
$db->exec("insert into played_game_cloud(pgid, gid, type, num, relation, weight, score) values($pgid, $gid, 1, ".$c['pos'].", $r1, ".($x*$userReputation).", ".$score.");");
|
||||
// TODO : game_cloud(probaR_x_) += $réputationJoueur * $coeff
|
||||
// TODO : game_cloud(totalWeight) += $réputationJoueur * $coeff (NOTE : même coeff que pour game_cloud(probaR_x_))
|
||||
|
@ -241,5 +260,7 @@ function main() {
|
|||
die("Commande inconnue");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
main($action);
|
||||
|
||||
?>
|
||||
|
|
|
@ -1,3 +1,24 @@
|
|||
- Une classe Constante pour toutes les constantes ("symboles" pour les paramètres, ...).
|
||||
- Boutons pour les différents modes de jeu directement sur la "page de garde".
|
||||
- Icônes : http://developer.android.com/guide/practices/ui_guidelines/icon_design.html
|
||||
|
||||
NOTES SUITE A LA REUNION
|
||||
- addiction -> IMPORTANT ... teasing socialisation
|
||||
- choix de la thématique : cadeau thématique
|
||||
- game with a purpose GWAP
|
||||
- espi
|
||||
- liberman (sp?)
|
||||
- indexation des images Google
|
||||
- code pour Google.com code.google.com/intl/fr~FR/apis/chart/index.html
|
||||
- qrcode
|
||||
- lire sur site pour installer appli
|
||||
- bêta testeurs externes
|
||||
- intuitivité
|
||||
- réflexion : intuitivité - prototypes -
|
||||
- bouton aide -> affiche les icônes en vertical + texte, il y a moins de place pour le mot du nuage, mais on peut continuer à jouer en cliquant sur ces "gros" boutons.
|
||||
- Modes de jeu supplémentaires payants par ex.
|
||||
|
||||
|
||||
POUR LAFOURCADE
|
||||
- lien : code.google.com/intl/fr~FR/apis/chart/index.html
|
||||
- note techniques exactes pour le serveur au LIRMM
|
||||
|
|
|
@ -60,6 +60,45 @@ Un grand nombre de développeurs ont créés des applications pour étendre la f
|
|||
|
||||
\section{Conception}
|
||||
|
||||
\begin{verbatim}
|
||||
NODE(EID integer primary key autoincrement, name string, #type (ref TYPE_NODE.num), weight);
|
||||
|
||||
RELATION(RID integer primary key autoincrement, #start (ref NODE.eid), #end (ref NODE.eid), #type (ref TYPE_RELATION.num), weight);
|
||||
|
||||
TYPE_NODE(NUM, name string);
|
||||
|
||||
TYPE_RELATION(NUM, name string, extended_name string, info string);
|
||||
|
||||
USER(LOGIN string primary key, mail string, hash_passwd string (md5sum du password), #score (contrainte : somme de tous les scores des PLAYED_GAME_CLOUD);
|
||||
|
||||
GAME(GID integer primary key autoincrement, #eid_central_word (ref NODE.eid, #relation_1 (ref RELATION.rid), #relation_2 ( (ref RELATION.rid), difficulty);
|
||||
|
||||
GAME_CLOUD(GID, NUM, difficulty, #eid_word(ref NODE.eid), totalWeight (contrainte : = somme des probas), probaR1 (contrainte : = somme des probas des PLAYED_GAME_CLOUD.weight avec la bonne relation et la même gid et num), probaR2 (idem), probaR0 (idem), probaTrash (idem));
|
||||
|
||||
PLAYED_GAME(PGID integer primary key autoincrement, #gid (ref GAME.gid), #login (ref USER.login);
|
||||
|
||||
PLAYED_GAME_CLOUD(#PGID (ref PLAYED_GAME.pgid), #GID (ref PLAYED_GAME.gid), NUM, type (contrainte : 0 = partie de référence, 1 = réponse d'un joueur), #relation (ref RELATION.rid), weight (contrainte : probabilité estimée de cette réponse pour les bots (robots), réputation du joueur sinon), score (score donné au joueur, 0 pour les bots);
|
||||
|
||||
**INT unless otherwise marked
|
||||
\end{verbatim}
|
||||
\begin{verbatim}
|
||||
create table node(eid integer primary key autoincrement, name, type, weight);
|
||||
create table relation(rid integer primary key autoincrement, start, end, type, weight);
|
||||
create table type_node(name, num);
|
||||
create table type_relation(name, num, extended_name, info);
|
||||
create table user(login primary key, mail, hash_passwd, score);
|
||||
create table game(gid integer primary key autoincrement, eid_central_word, relation_1, relation_2, difficulty);
|
||||
create table game_cloud(gid, num, difficulty, eid_word, totalWeight, probaR1, probaR2, probaR0, probaTrash);
|
||||
create table played_game(pgid integer primary key autoincrement, gid, login);
|
||||
create table played_game_cloud(pgid, gid, type, num, relation, weight, score);
|
||||
|
||||
create index i_relation_start on relation(start);
|
||||
create index i_relation_end on relation(end);
|
||||
create index i_relation_type on relation(type);
|
||||
create index i_relation_start_type on relation(start,type);
|
||||
create index i_relation_end_type on relation(end,type);
|
||||
\end{verbatim}
|
||||
|
||||
TODO: UML, diagrammes de classes, Use cases, etc...
|
||||
|
||||
|
||||
|
@ -87,6 +126,22 @@ TODO: UML, diagrammes de classes, Use cases, etc...
|
|||
\item Caractères non échappés dans le dump de la base.% gd
|
||||
\end{itemize}
|
||||
|
||||
\subsubsection{Itération 1, semaine 3}
|
||||
\begin{itemize}
|
||||
\item SQLite3 n'est pas capable d'utiliser un index pour la requête extérieure sur une requête du type
|
||||
\begin{verbatim}
|
||||
select * from (select * from table where condition) where condition
|
||||
\end{verbatim}
|
||||
Donc nécessité de ré-écrire certaines requêtes avec des jointures à priori beaucoup moins efficaces, mais qui le sont plus grâce aux index.
|
||||
\item SQLite3 tranforme les requêtes de la forme~:
|
||||
\begin{verbatim}
|
||||
select * from table limit 100 order by random();
|
||||
\end{verbatim}
|
||||
en une requête qui récupère tout le set de résultats, ajoute une colonne random(), prend les 100 premiers résultats et les trie. Mais cela
|
||||
l'oblige à récupérer tout le set de résultats, et calculer le random() pour chaque ligne, pour ensuite jeter tout ce qui dépasse la ligne
|
||||
100. Cela est évidemment très coûteux dans le cadre de requêtes avec beaucoup de résultats, et nous avons donc dû isoler la requête avec
|
||||
\verb!limit! de son \verb!order by! avec des «hacks» assez tordus.
|
||||
\end{itemize}
|
||||
|
||||
\section{Conclusions}
|
||||
|
||||
|
|
Loading…
Reference in New Issue
Block a user