Le lien n'a pas l'air de fonctionner...ou c'est mon neurone qui n'est pas bien.
Si tu as le temps de nous faire un chti'te exemple de client ce serait pas mal.
Merci
Le lien n'a pas l'air de fonctionner...ou c'est mon neurone qui n'est pas bien.
Si tu as le temps de nous faire un chti'te exemple de client ce serait pas mal.
Merci
Bonjour, inutile d'aller sur l'adresse http://www.wowar.fr/web.py avec le navigateur, vous aurez une erreur 400, il faut passer par du XML-RPC pour appeler les fonctions.
Je n'ai testé qu'avec du python pour le moment, avec xmlrpclib:
votre_password est à changer avec votre propre password.
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4 import xmlrpclib s = xmlrpclib.ServerProxy("http://www.wowar.fr/web.py") s.login("votre_password")
J'essayerais avec d'autre langage dès que possible, si il y en a qui test avec d'autre langage je suis preneur aussi
Bonjour,
J'ai réalisé un client Java en ligne de commande qui accède au serveur.
Toutes les fonctions fonctionnes correctement.
Mais je propose quelques modifications par rapport aux messages échangés :
Dans un premier temps, il faut modifier la commande "fire" qui retourne -1 quand on ne touche pas.
Personnellement, j'ai un traitement générique pour tout les commandes et cela entre en conflit avec ma vérification :
Donc, je ne sais pas si j'ai pu tiré ou si j'ai juste tiré dans le vent.
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37 private static final int SUCCESS = 0; private static final int ERROR = -1; private static final int DENY = -5; private static final int DEAD = -10; private Object makeAction(String action) { Object[] params = new Object[]{id,pass}; Object result = null; try { result = client.execute( action, params ); } catch (XmlRpcException e) { // TODO Auto-generated catch block e.printStackTrace(); } if(result instanceof Integer){ Integer value=(Integer) result; switch (value) { case SUCCESS: System.out.println("commande work"); break; case ERROR: System.out.println("an error append"); break; case DENY: System.out.println("wrong pass or id"); break; case DEAD: System.out.println("this tank is dead"); break; default: break; } } return result; }
Dans un second temps,
Il serait utile d'ajouter certains commandes, en vue du débugage :
myPosition(id,password): retourne la position en x,y et l'orientation (format à définir)
myOrientation(id, password): retourne l'orientation (format à définir)
playerCount(): retourne le nombre de tank présent.
logout(id, password): détruit totalement le tank.
Afin de réalisé une interface de gestion joueur/admin, il me faudrait des information supplémentaire :
La taille de la zone de jeu (si finit) ou ses bornes.
Il faudrait aussi des commendes admin du type :
move(id,passworkDev,x,y)
playersPosition(passworkDev): retourne un tableau de position des tanks en présence.
Je pense qu'il serait cool d'avoir des noms pour les tanks, au niveau affichage ça rend toujours mieux.
Je donne le code de ma classe métier :
Cordialment,
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130 import java.net.MalformedURLException; import java.net.URL; import org.apache.xmlrpc.XmlRpcException; import org.apache.xmlrpc.client.XmlRpcClient; import org.apache.xmlrpc.client.XmlRpcClientConfigImpl; public class Tank { private static final String SERVER_ADRESS = "http://www.wowar.fr/web.py"; private static final int HIT = 0; private static final int SUCCESS = 0; private static final int ERROR = -1; private static final int DENY = -5; private static final int DEAD = -10; private static final String FIRE = "fire"; private static final String TURN_RIGHT = "turnRight"; private static final String TURN_LEFT = "turnLeft"; private static final String WATCH = "watch"; private static final String MY_HEALTH = "myHealth"; private static final String LOGIN = "login"; private String id; private String pass; private int health = 0; private XmlRpcClient client; public Tank(String pass) { this.pass = pass; client = new XmlRpcClient(); XmlRpcClientConfigImpl config = new XmlRpcClientConfigImpl(); try { config.setServerURL(new URL(SERVER_ADRESS)); config.setEnabledForExtensions(true); client.setConfig(config); } catch (MalformedURLException e) { // TODO Auto-generated catch block e.printStackTrace(); } } public void login() { Object result = makeAction(LOGIN); if (result != null) { if (result instanceof String) { id = (String) result; return; } } throw new Error("The tank can't login"); } private Object makeAction(String action) { Object[] params = new Object[] { id, pass }; Object result = null; try { result = client.execute(action, params); } catch (XmlRpcException e) { // TODO Auto-generated catch block e.printStackTrace(); } if (result instanceof Integer) { Integer value = (Integer) result; switch (value) { case SUCCESS: System.out.println("commande work"); break; case ERROR: System.out.println("an error append"); break; case DENY: System.out.println("wrong pass or id"); break; case DEAD: System.out.println("this tank is dead"); break; default: break; } } return result; } public int Health() { Object result = makeAction(MY_HEALTH); if (result != null) { if (result instanceof Integer) { health = (Integer) result; return health; } } throw new Error("The tank can't access health"); } public void watch() { Object result = makeAction(WATCH); if (result != null) { Object[] seeing = (Object[]) result; for (Object value : seeing) { if (value instanceof Integer) { System.out.println(value); } } } } public void turnRight() { makeAction(TURN_RIGHT); } public void turnLeft() { makeAction(TURN_LEFT); } public boolean fire() { Object result = makeAction(FIRE); if (result instanceof Integer) { Integer value = (Integer) result; if(value==HIT){ return true; } } return false; } }
K
Super K
Je vais mettre tout ça en oeuvre dès ce soir. Peut être que après je partagerais le code source du moteur pour avancer plus vite si il y a des intéressé par ce projet, dailleurs si quelqu'un est intéressé pour écrire un site web frontale pour permettre de regarder ce qui ce passe sur le plateau faut pas hésiter.
Merci encore K
ça avance ça avance..
correction :
watch : bug sur une des positions.
Ajout :
myPosition(id,password): retourne [x,y]
myOrientation(id, password): retourne l'orientation avec une lettre {'N','S','E','O'}
playerCount(): retourne le nombre de tank présent.
logOut(id, password): détruit totalement le tank.
Help(): renvoie un tableau avec les commandes possibles
nbKill(id,password): retourne le nombre de kill
Modification :
Fire renvoie 5 si vous avez tuer le robot, et incrémente votre nombre de kill
Fire renvoie -3 si ça n'a pas toucher de Robot
Cool !
Je vais pouvoir faire mumuse avec une belle interface avec tout ça !
K
Voila vers quoi le projet devrais se porter à terme :
Plusieurs grille seront disponible pour tester sont IA, et le jeux en lui même devrais se voir améliorer : objet sur la grille, piège à poser, règle temporel.. etc
Le but étant de proposer chaque jour ou chaque semaine des combats sur une grille "officiel", avec classement des meilleurs IA. Cette grille ne devraient pas dépasser les 10x10 cases opposera de deux à huit robot. Le but étant de survivre le plus longtemps possible et avoir le plus de kill possible.
Le protocole de communication étant en XML il n'y à aucune restriction de langage, pour peux qu'il puisse communiquer en XML-RPC.
un listing basique des actions effectué dans la grille est disponible ici :
http://wowar.fr/history.py
Il sera amélioré très bientôt avec de l'ajax pour ne pas a avoir a recharger la page.
Bonjour,
Alors je me suis aussi attaqué à ce sujet, en essayant de créer la machine de guerre ultime
Pour ce faire, je me suis pour le moment appliqué à avoir un "moule opérationnel" réalisé en F#.
Je tiens à préciser que je suis encore pas mal débutant aussi bien en F# qu'en programmation fonctionnelle en général (d'autant plus qu'en ce qui concerne ce projet j'ai opté pour une approche fonctionnelle/objet F# étant un langage .Net on peut jouer sur les deux tableaux).
Donc aficionados de la programmation fonctionnelle pardonnez-moi en avance
Note: j'utilise également un découpage en fichiers, d'où la présence de modules.
Tout d'abord pour la liaison XML-RPC (que je ne connaissais pas vraiment il faut le dire) j'ai utilisé la libraire XML-RPC.NET en me basant sur cet exemple
Concrètement, il faut définir une Interface, dont les méthodes respectent les signatures des méthodes offertes par le service, méthodes marquées par l'attribut XmlRpcMethod qui précise le nom de la méthode du service à laquelle elle est mappée ; l'interface elle-même utilisant un attribut pour mapper l'url du service, ce qui donne dans mon cas:
Donc la méthode myHealth du service sera mappée à la méthode MyHealth de l'interface qui a pour signature string * string -> int soit une fonction prenant un tuple de string et renvoyant un entier et même chose pour les autres.
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24 namespace Wowar module WebService = open CookComputing.XmlRpc //XML-RPC.NET Copyright © 2006 Charles Cook [<XmlRpcUrl("http://www.wowar.fr/web.py")>] type IWowarService = [<XmlRpcMethod("myHealth")>] abstract MyHealth : string * string -> int [<XmlRpcMethod("nbKill")>] abstract NbKill : string * string -> int [<XmlRpcMethod("myPosition")>] abstract MyPosition : string * string -> int array [<XmlRpcMethod("myOrientation")>] abstract MyOrientation : string * string -> string [<XmlRpcMethod("watch")>] abstract Watch : string * string -> int array [<XmlRpcMethod("playerCount")>] abstract PlayerCount : unit -> int [<XmlRpcMethod("help")>] abstract Help : unit -> string array [<XmlRpcMethod("login")>] abstract Login : string -> string [<XmlRpcMethod("logOut")>] abstract Logout : string * string -> unit [<XmlRpcMethod("move")>] abstract Move : string * string -> int [<XmlRpcMethod("turnLeft")>] abstract TurnLeft : string * string -> int [<XmlRpcMethod("turnRight")>] abstract TurnRight : string * string -> int [<XmlRpcMethod("fire")>] abstract Fire : string * string -> int
À partir de là il suffit de créer un proxy utilisant cette interface et d'appeler ses méthodes.
Néanmoins, j'ai personnellement choisi (j'ai un lourd passif en objet ) de faire une classe représentant un robot de base qui se contente d'utiliser les méthodes du service:
Alors que j'explique un peu, Je définis un type classe avec deux constructeurs, le premier avec id, password pour récupérer son robot, le second avec seulement le password qui va créer l'id grâce au service login et appeler le constructeur précédent.
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40 namespace Wowar module BotBase = open WebService open CookComputing.XmlRpc //XML-RPC.NET Copyright © 2006 Charles Cook type Bot(id, password) = static let proxy = XmlRpcProxyGen.Create<IWowarService>() static let getHelp = proxy.Help() |> Array.reduce(fun acc cur -> acc + "\n" + cur) let call proxyMethod = proxyMethod(id, password) new(password) = Bot(proxy.Login password, password) member this.Id = id member this.HP = call proxy.MyHealth member this.KillCount = call proxy.NbKill member this.Position = let pos = call proxy.MyPosition in pos.[0], pos.[1] member this.Direction = call proxy.MyOrientation member this.Neighborhood = call proxy.Watch static member PlayerCount = proxy.PlayerCount() static member Help = getHelp member this.Logout() = call proxy.Logout abstract member Move : unit -> int default this.Move() = call proxy.Move abstract member Left : unit -> int default this.Left() = call proxy.TurnLeft abstract member Right : unit -> int default this.Right() = call proxy.TurnRight abstract member Shoot : unit -> int default this.Shoot() = call proxy.Fire override this.ToString() = sprintf "Id: %s ; HP: %d ; Kills: %d ; %A - %s ; %A" this.Id this.HP this.KillCount this.Position this.Direction this.Neighborhood
L'élément clef ici, c'est le proxy (que j'ai mis statique) il va wrapper mon interface afin que j'utilise ses méthodes qui seront ensuite transférées au service web.
J'ai également un "champ" statique qui récupère le tableau de string de l'aide et concatène ses éléments pour que se soit fait une fois pour toute.
J'ai aussi une petite méthode utilitaire "call" qui prend en paramètre une fonction et applique cette fonction sur le couple (id,password), ce n'est pas indispensable, plutôt un sucre syntaxique ici
Ensuite je définis les membres (aussi bien propriétés (par défaut en lecture seule) que méthodes) qui se contentent d'appeler la méthode du proxy qui va bien
Je vais détailler un peu le membre Position car la syntaxe que déconcerter
l'appel à la méthode du proxy renvoie un tableau d'entiers, que je stocke dans une variable créée "on-the-fly" pos dont j'extrais les deux premiers éléments en tant que tuple (la virgule séparant les deux) ça me permet ainsi
Code : Sélectionner tout - Visualiser dans une fenêtre à part member this.Position = let pos = call proxy.MyPosition in pos.[0], pos.[1]
une autre manière de l'écrire peut être plus compréhensible serait celle-ci
Pour le moment je ne sais pas encore si transformer un tableau en couple va m'être utile
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3 member this.Position = let pos = call proxy.MyPosition (pos.[0], pos.[1])
Viennent ensuite le nombre de joueur et l'aide que j'ai décidé de mettre en statique également, l'aide se contenant de récupérer la variable définie en début (et ainsi d'éviter un appel au service)
Viennent enfin les méthodes que j'appellerai "d'action", la syntaxe un peu lourdingue (^^) est en fait la manière de définir une méthode (ou propriété) abstraite (ou virtuelle si vous préférez) il s'agit des lignes du type:
et on pourrait en rester là, seulement je veux quand même avoir un comportement (par défaut) dans cette classe, d'où les lignes qui les accompagnent et dans une classe dérivée de celle-ci je pourrai redéfinir ces membres, de la même manière qu'est redéfinie la méthode ToString() (héritée de Object)
Code : Sélectionner tout - Visualiser dans une fenêtre à part abstract member <Name> : <signature>
Voici le code principal, j'expliquerai un peu ensuite:
Alors en premier j'ai une directive, bon c'est pas vraiment important là mais pour faire court, je peux soit lancer l'exécution en mode console comme une application C# ou VB.Net ou je peux utiliser l'interpréteur interactif type REPL (Read Evaluate Print Loop). Dans mon cas si je passe par l'interpréteur je lance un fichier de script (.fsx) qui va se charger de loader les fichiers et d'établir les références aux dll dont j'ai besoin
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18 #if INTERACTIVE #load "interactive.fsx" #endif open Wowar.BotBase open Util let simpleBot = new Bot(id, password) let overridedBot = { new Bot(id, password) with override this.Move() = let result = base.Move() display this result }
Suite à ça j'ouvre mon module (ainsi qu'un module Utilitaire, qui me sert à récupérer mon id/password dans un fichier de config et définit aussi une méthode Display qui affiche un robot dans une version plus "light" que le ToString qui demande quand même 5 appels au service)
Pour avoir un robot j'ai juste à l'instance comme on le ferait dans n'importe quel autre langage (à la syntaxe près).
La seconde construction est plus intéressante, elle me permet de redéfinir le comportement des propriétés/méthodes virtuelles à la déclaration, pratique pour tester sans avoir à écrire une classe dérivée complète.
Voilà j'ai fait le tour, j'en profite pour préciser qu'il faut prendre mes explications avec des pincettes, je découvre aussi le langage donc je dis peut-être des bétises sur certains points.
Cordialement !
Je t'avais dit de passer vite fait, pas d'ecrire un mémoire
Bonjour !
Le projet à maintenant un site web : wowar.fr
Avant de commencer à proposer des matchs, voici les points qui reste à traiter :
- Ajout de toute les commande et exemple sur le site web
- Règle temporel à implémenter.
- Ajout de 3 cases bonus sur la grille :
# bonus de vie : si vous allez sur la case, votre vie maximum augmente de 10pts, utilisable toute les 2 minutes.
# régénération de vie : si vous allez sur la case, votre vie revient au maximum, utilisable toute les minutes.
# bonus d'attaque : si vous allez sur cette case, vous attaqué avec +5pts
- Ajout d'items sur la grille, que vous pouvez stoquer dans un sac a dos.
- Ajout d'un radar utilisable toutes les 2 minutes, vous permet de visualiser l'ensemble de la grille.
- Les items devrons apparaitre aléatoirement sur la grille, avec un maximum de 10 items sur la grille en même temps.
- items :
# mine, à poser sur la grille : si un robot adverse passe dessus, il perds la moiter de ces points de vie.
# potion : régénère 25 pts de vie.
# boussole : la boussole à le même effet que le radar, utilisable quand vous voulez.
# SteathBoy : permet de devenir invisible pendant 30 secondes
- mettre a disposition un grille de test, avec une fonction qui fait apparaître une IA avec un niveau de 1 à 10.
Suite à une réorganisation du code source, quelques changement sur les code-retours :
- RET_ERROR_ON_FUNCTION = -10
La fonction demandé n'a pas pu être réalisé.- RET_LOGIN_FAIL = -20
paramètre login ou mot de passe incorecte- RET_SUCCES = 0
la fonction à été réalisé correctement- RET_IS_BLOCKED = -30
impossible d'avancer, il y a un robot devant.- RET_MISS = -5
le tire a bien été effectué mais il n'a rien touché- RET_KILL = 5
La cible n'a plus de HP- RET_WALL = -40
impossible d'avancer, il y à un mur devant- RET_TOO_FAST = -50
La règle temporel n'est pas respecté, vous avez été trop vite.
La règle temporel est de 2 secondes, si vous effectuer deux actions en moins de deux secondes d'intervalle, vous aurez -50 en retour.
Vous perdez du temps ^^Envoyé par LittleWhite
vous pouvez attendre 1 jour sans faire d'action, j'impose une laps de temps minimum pour mettre l’accent sur l’intelligence et non sur les performances.
Bizarre ... cela veut dire que je peux faire une IA parfaite (hypothetiquement) en testant tous les cas un par un, toutes les possibilites et vous me laisser librement le faire, alors que les autres chercheront peut etre a faire une IA rapide (et donc possiblement utilisable dans les Jeux Videos).
Je dis cela car dans MarioAI (qui est un concours de creation d'intelligencce artificielle), il y a un temps maximum (40ms) et pas de temps minimum.
De plus, si je suis machiavelique (et je le suis pour prouver que c'est un probleme ), je vais creer une IA d'attente pour bloquer toutes les parties de votre Jeu (MUAHAHAHAHA )
Je peux descendre le temps minimum, par exemple à 100ms, ça assure une cohérence en terme de performance/intelligence, après.. ça peux changer quand on va commencer à tester avec des matchs. mettre une borne maximum techniquement c'est compliqué, et je préfère laisser libre choix au développeur.. le jeux se tourne plus vers de la stratégie et donc des coup parfait il n'y en aura pas, c'est la stratégie globale du robot qui doit être bonne et non une infinité de coup parfait qui n'a pas de sens en terme de stratégie.
j'ai pas compris pour l'IA d'attente ? si votre robot ne bouge pas il sera détruit par un autre forcement, non ?
Alors je n'ai pas du tout comprendre.
Les IA bougent tous les 2 secondes. Une fois ces 2 secondes passes, l'IA peut rejouer. Si une IA ne fait rien pendant 2 secondes ... alors bah ... elle a perdu du temps et pendant ce temps ... les autres auront pu faire autre chose.
Ai-je bien decrit la situation ?
Car dans ce cas la, il y a ... d'apres mon point de vue, un temps maximum... qui est actuellement de 2 secondes par mouvement.
non, les robots sont bien asynchrone, ils bougent indépendamment des autres robots.
Pour l'instant, chaque robot, indépendamment des autres, peux donner un ordre toute les 2 secondes, 2 secondes étant le temps minimum entre deux action pour un robot.
Exemple :
Robot 1 : [Action][--2s--]---[Action][--2s--][Action][--2s--]------[action]
Robot 2 : -----[Action][--2s--]-----[Action][--2s--]------[action]---------
Les commandes d'observation :
savoir sa position, son orientation ou savoir ce qu'il y a autour de nous est ils assujetti à ce temps de refroidissement ?
Personnellement, un temps entre 0.5 et 2 secondes me sembles correct. Si on prend pas en considération les commandes "passives".
Bonjour,
J'ai quelques question au niveau des règles :
- Quelle est la portée du tir ? Est-ce que le tir touche tous les robots placés dans la ligne de mon viseur ?
- Est-ce que les actions de type "myHealth", "watch"... coûtent du temps ? (c'est à dire, est-ce qu'on doit les exécuter toutes les 2 secondes et remplacent-elles une action normale ?)
Sinon, j'essaierai sans doute ce soir de lancer un robot sur la grille.
Partager