2016-05-23 21:18:31 +02:00
|
|
|
<!DOCTYPE html>
|
|
|
|
<html lang="fr">
|
|
|
|
<head>
|
|
|
|
<meta charset="UTF-8">
|
|
|
|
<meta name="viewport" content="width=device-width, initial-scale=1">
|
|
|
|
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
|
|
|
<meta name="author" content="Gnieark" />
|
2016-06-28 14:17:50 +02:00
|
|
|
<title>ConnectFour's Ludus</title>
|
2016-05-23 21:18:31 +02:00
|
|
|
<style type="text/css">
|
2016-05-24 20:48:31 +02:00
|
|
|
body{width:100%; font-size:100%; line-height:140%; word-wrap:break-word; text-rendering:optimizelegibility;
|
|
|
|
margin:0 auto; font-family : "lucida grande", "gill sans", arial, sans-serif; left:auto;}
|
|
|
|
header{ background-color:#A60800; width: 100%; overflow: hidden; height: auto;}
|
|
|
|
header h1{display: block; font-size:300%; color:#FFF;float: left; margin-left: 5%;}
|
|
|
|
header nav{display: block; width: 45%; color:#FFF; float: right;}
|
|
|
|
#menus{ margin-left: 50px; width:100%; display: table;}
|
|
|
|
#menus a{color: #fff; display: table-cell; text-decoration: none;text-align: center;border-radius: 15px 15px 0px 0px;}
|
|
|
|
#menus a.selected{color:#202020; background-color:#fff;}
|
|
|
|
footer{height: 70px; display: block; color: #343638; font-size: 11pt; line-height: 15pt; margin: 0; padding-top: 15pt;
|
|
|
|
overflow-x: hidden; box-sizing: border-box; background-image: -webkit-linear-gradient(top, #f5f5f5,#e9e9e9);
|
|
|
|
border-top: 1px solid #bebebe; color: #999; font-size: 12px; line-height: 1.5em; text-align: center;width: 100%;}
|
|
|
|
footer a {margin:0px 15px 0px 15px; color: #666;text-decoration: none; font-weight: normal;}
|
|
|
|
#languages{float: right; text-align: right;}
|
|
|
|
section{margin: 0 auto; width: 90%;}
|
|
|
|
article{float: right; width:70%;}
|
|
|
|
aside{float:left; width: 28%; border-right: 1px dashed green;}
|
|
|
|
aside table {width: 90%;}
|
2016-06-28 14:36:28 +02:00
|
|
|
aside table tr td{width: 33%;}
|
2016-06-28 14:36:00 +02:00
|
|
|
aside table tr td input, aside table tr td select {width: 100%;}
|
2016-05-23 21:18:31 +02:00
|
|
|
.center{text-align: center;}
|
|
|
|
aside p img{ width: 100%; max-width:342px;}
|
2016-06-28 14:30:44 +02:00
|
|
|
form textarea, form input, form select {width:100%;}
|
2016-05-23 21:18:31 +02:00
|
|
|
form input[type=checkbox], form input[type=radio] { width:15px; }
|
2016-05-24 20:48:31 +02:00
|
|
|
form label {float:left; width:40%; margin-right:0.5em;
|
|
|
|
padding-top:0.2em; text-align:right;}
|
|
|
|
pre{ font-style: normal;font-size: 16px; margin-left: 32px;font-family: Consolas, "Times New Roman", Verdana;
|
|
|
|
border-left: 4px solid #CCC; padding-left: 8px;}
|
|
|
|
.battleGrid{display:table-cell; padding-left:10px; border-collapse:collapse; margin: 20px 20px 20px 20px;}
|
|
|
|
.battleGrid tr{}
|
2016-06-07 23:43:52 +02:00
|
|
|
.battleGrid td{border: 1px dashed green; text-align: center; font-weight: bold;width:2em; height: 2em; vertical-align: middle;}
|
2016-05-24 20:48:31 +02:00
|
|
|
.winCase{background-color:red;}
|
2016-05-27 22:38:24 +02:00
|
|
|
.hidden{display: none;}
|
2016-05-28 15:05:15 +02:00
|
|
|
#logs{font-size: 70%;}
|
2016-05-24 20:48:31 +02:00
|
|
|
</style>
|
|
|
|
|
|
|
|
<script>
|
2016-06-06 23:37:13 +02:00
|
|
|
var board=[["","","","","","",""],
|
2016-05-26 00:00:54 +02:00
|
|
|
["","","","","","",""],
|
|
|
|
["","","","","","",""],
|
|
|
|
["","","","","","",""],
|
|
|
|
["","","","","","",""],
|
|
|
|
["","","","","","",""]];
|
|
|
|
var currentPlayer=1;
|
2016-06-07 13:24:48 +02:00
|
|
|
var gameId="0";
|
2016-05-27 22:38:24 +02:00
|
|
|
|
2016-06-07 23:42:01 +02:00
|
|
|
function wins(player){
|
|
|
|
addLog('player ' + player + ' wins');
|
|
|
|
}
|
2016-05-24 20:48:31 +02:00
|
|
|
function createElem(type,attributes){
|
|
|
|
var elem=document.createElement(type);
|
|
|
|
for (var i in attributes)
|
|
|
|
{elem.setAttribute(i,attributes[i]);}
|
|
|
|
return elem;
|
|
|
|
}
|
2016-05-28 15:03:50 +02:00
|
|
|
function addLog(message){
|
|
|
|
var p=createElem('p');
|
|
|
|
p.innerHTML=message;
|
|
|
|
document.getElementById('logs').appendChild(p);
|
|
|
|
}
|
2016-05-24 20:48:31 +02:00
|
|
|
function changePlayerType(player,newValue){
|
|
|
|
if(newValue == "bot"){
|
|
|
|
document.getElementById('url' + player).disabled="";
|
|
|
|
}else{
|
|
|
|
document.getElementById('url' + player).disabled="disabled";
|
2016-05-23 21:18:31 +02:00
|
|
|
}
|
|
|
|
}
|
2016-05-26 00:00:54 +02:00
|
|
|
function playingAT(col){
|
2016-05-27 22:38:24 +02:00
|
|
|
//hide buttons
|
|
|
|
document.getElementById("playerButtons").setAttribute("class", "hidden");
|
|
|
|
|
2016-05-26 00:00:54 +02:00
|
|
|
if(currentPlayer == 1){
|
2016-05-27 22:38:24 +02:00
|
|
|
var symbol= "X";
|
2016-05-26 00:00:54 +02:00
|
|
|
}else{
|
2016-05-27 22:38:24 +02:00
|
|
|
var symbol="O";
|
2016-05-26 00:00:54 +02:00
|
|
|
}
|
2016-05-27 22:38:24 +02:00
|
|
|
|
2016-06-08 15:41:04 +02:00
|
|
|
if(board[5][col]!== ""){
|
|
|
|
addLog('Player ' + currentPlayer + ', symbol ' + symbol + ' wants to play on column ' + col + ' but that column is already full. He loses.');
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2016-05-27 22:38:24 +02:00
|
|
|
//find the first line empty
|
2016-05-26 00:00:54 +02:00
|
|
|
var i=0;
|
2016-06-07 23:22:18 +02:00
|
|
|
for(i = 0; i < 6 , board[i][col] !== ""; i++){
|
2016-05-27 22:38:24 +02:00
|
|
|
//nothing juste a counter
|
2016-05-26 00:00:54 +02:00
|
|
|
}
|
2016-06-07 23:22:18 +02:00
|
|
|
board[i][col]=symbol;
|
2016-05-26 00:00:54 +02:00
|
|
|
document.getElementById('td' + col + '_' + i).innerHTML = symbol;
|
2016-05-28 15:05:15 +02:00
|
|
|
addLog('player ' + currentPlayer + ', symbol ' + symbol + ' played col ' + col);
|
2016-05-29 17:27:07 +02:00
|
|
|
|
|
|
|
//does he win?
|
|
|
|
var x=col;
|
|
|
|
var y=i;
|
|
|
|
var searchValue="";
|
2016-06-07 13:28:54 +02:00
|
|
|
for (var k=0; k < 4; k++){
|
2016-05-29 17:27:07 +02:00
|
|
|
searchValue +=symbol;
|
|
|
|
}
|
|
|
|
|
|
|
|
//horizontaly
|
|
|
|
var line="";
|
|
|
|
for (var k=0; k < 7; k++){
|
2016-06-07 23:22:18 +02:00
|
|
|
if(board[y][k] == ""){
|
2016-05-29 17:27:07 +02:00
|
|
|
line += " ";
|
|
|
|
}else{
|
2016-06-07 23:22:18 +02:00
|
|
|
line += board[y][k];
|
2016-05-29 17:27:07 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
if (line.indexOf(searchValue) > -1){
|
|
|
|
wins(currentPlayer);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
//verticaly
|
|
|
|
var line="";
|
|
|
|
for (var k=0; k < 6; k++){
|
2016-06-07 23:22:18 +02:00
|
|
|
if(board[k][x] == ""){
|
2016-05-29 17:27:07 +02:00
|
|
|
line += " ";
|
|
|
|
}else{
|
2016-06-07 23:22:18 +02:00
|
|
|
line += board[k][x];
|
2016-05-29 17:27:07 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
if (line.indexOf(searchValue) > -1){
|
|
|
|
wins(currentPlayer);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2016-06-07 22:06:23 +02:00
|
|
|
//diagonal \
|
2016-06-07 15:27:05 +02:00
|
|
|
/*
|
2016-06-07 23:46:52 +02:00
|
|
|
* diagonal is an affin function:
|
|
|
|
* y=-x+b
|
2016-06-07 22:06:23 +02:00
|
|
|
*/
|
|
|
|
//find b
|
2016-06-07 23:40:07 +02:00
|
|
|
var b = parseInt(y + x);
|
2016-06-07 22:06:23 +02:00
|
|
|
if (b < 6){
|
|
|
|
//first point of the diagonal has x=0;
|
|
|
|
var kx = 0;
|
|
|
|
var ky = b; //:aga:
|
|
|
|
}else{
|
|
|
|
//first point of the diagonal has y=5
|
|
|
|
var kx = b - 5;
|
|
|
|
var ky = 5;
|
|
|
|
}
|
|
|
|
var line="";
|
2016-06-07 23:17:01 +02:00
|
|
|
var lx , ly;
|
|
|
|
for (lx = kx, ly = ky; (lx < 7) && (ly > -1); lx++ , ly-- ){
|
2016-06-07 23:22:18 +02:00
|
|
|
if( board[ly][lx] == ""){
|
2016-06-07 22:06:23 +02:00
|
|
|
line += " ";
|
|
|
|
}else{
|
2016-06-07 23:22:18 +02:00
|
|
|
line += board[ly][lx];
|
2016-06-07 22:06:23 +02:00
|
|
|
}
|
|
|
|
}
|
2016-05-29 17:27:07 +02:00
|
|
|
|
2016-06-07 22:06:23 +02:00
|
|
|
if (line.indexOf(searchValue) > -1){
|
|
|
|
wins(currentPlayer);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
//diagonal / affin function like y=x+b
|
2016-06-07 23:40:07 +02:00
|
|
|
b = parseInt(y - x);
|
2016-06-07 22:06:23 +02:00
|
|
|
if( b > -1){
|
|
|
|
//first point has x=0
|
|
|
|
kx = 0;
|
|
|
|
ky = b
|
|
|
|
|
|
|
|
}else{
|
|
|
|
//first point has y=0
|
|
|
|
ky = 0;
|
|
|
|
kx = -b;
|
|
|
|
}
|
|
|
|
|
|
|
|
var line="";
|
2016-06-07 23:13:32 +02:00
|
|
|
var lx , ly;
|
|
|
|
for (lx = kx , ly = ky ; (lx < 7) && (ly < 6) ; lx++ , ly++){
|
2016-06-07 23:22:18 +02:00
|
|
|
if( board[ly][lx] == ""){
|
2016-06-07 22:06:23 +02:00
|
|
|
line += " ";
|
|
|
|
}else{
|
2016-06-07 23:22:18 +02:00
|
|
|
line += board[ly][lx];
|
2016-06-07 22:06:23 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (line.indexOf(searchValue) > -1){
|
|
|
|
wins(currentPlayer);
|
|
|
|
return;
|
|
|
|
}
|
2016-06-08 15:41:04 +02:00
|
|
|
|
|
|
|
//if it was the last cell
|
|
|
|
var full=true;
|
|
|
|
for (var i = 0; i < 7; i ++){
|
|
|
|
if( board[5][i] == "" ){
|
2016-06-08 15:42:47 +02:00
|
|
|
full = false;
|
2016-06-08 15:41:04 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
if (full){
|
|
|
|
addLog('match nul');
|
|
|
|
return;
|
|
|
|
}
|
2016-06-07 22:06:23 +02:00
|
|
|
|
2016-05-27 22:38:24 +02:00
|
|
|
//change player
|
|
|
|
if(currentPlayer == 1){
|
|
|
|
play(2);
|
|
|
|
}else{
|
|
|
|
play(1);
|
|
|
|
}
|
2016-05-26 00:00:54 +02:00
|
|
|
}
|
|
|
|
function play(player){
|
2016-05-27 22:38:24 +02:00
|
|
|
currentPlayer=player;
|
2016-05-26 00:00:54 +02:00
|
|
|
if(document.getElementById("player" + player + "Type").value == "bot"){
|
|
|
|
//call bot url
|
2016-05-27 22:38:24 +02:00
|
|
|
if(currentPlayer == 1){
|
|
|
|
var symbol= "X";
|
|
|
|
}else{
|
|
|
|
var symbol="O";
|
2016-05-26 00:00:54 +02:00
|
|
|
}
|
2016-06-07 13:24:48 +02:00
|
|
|
var arrToSend= {
|
|
|
|
"game-id": "" + gameId,
|
|
|
|
"action" : "play-turn",
|
2016-06-12 00:08:54 +02:00
|
|
|
"game" : "connectFour",
|
2016-06-07 13:24:48 +02:00
|
|
|
"players" : 2,
|
2016-06-07 23:22:18 +02:00
|
|
|
"board" : board,
|
2016-06-07 13:24:48 +02:00
|
|
|
"you" : symbol,
|
|
|
|
"player-index" : player-1
|
|
|
|
};
|
2016-06-07 12:30:45 +02:00
|
|
|
|
2016-05-28 14:55:30 +02:00
|
|
|
var xhr = new XMLHttpRequest();
|
2016-06-07 13:24:48 +02:00
|
|
|
xhr.open("POST", document.getElementById('url' + player).value, false);
|
|
|
|
xhr.setRequestHeader("Content-Type", "application/json");
|
|
|
|
xhr.send(JSON.stringify(arrToSend) );
|
2016-06-07 23:51:09 +02:00
|
|
|
addLog('Message send to player ' + player + ': ' +JSON.stringify(arrToSend) );
|
2016-06-07 13:24:48 +02:00
|
|
|
if(xhr.status == 200) {
|
|
|
|
try{
|
|
|
|
var reponse = JSON.parse(xhr.responseText);
|
|
|
|
var colTarget= reponse['play'];
|
|
|
|
}catch(e){
|
|
|
|
addLog('player ' + player + ' made a non confom response: ' + xhr.responseText);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
var t = new RegExp('^[0-6]$');
|
|
|
|
if (t.test(colTarget)){
|
2016-06-24 14:26:12 +02:00
|
|
|
addLog('His rsponse is:' + xhr.responseText);
|
2016-06-07 13:24:48 +02:00
|
|
|
playingAT(colTarget);
|
|
|
|
}else{
|
|
|
|
addLog ('bot response must be a digit betwin 0 and 7, witch indicate the conumn number where he wants play. Voici sa réponse: "' + colTarget + '"' );
|
|
|
|
}
|
|
|
|
}else{
|
|
|
|
addLog('le bot ' + player + ' does not respond. ' + xhr.status);
|
|
|
|
return;
|
|
|
|
}
|
2016-05-27 22:38:24 +02:00
|
|
|
}else{
|
|
|
|
//wait for human response, show buttons
|
|
|
|
document.getElementById("playerButtons").setAttribute("class", "");
|
2016-05-26 00:00:54 +02:00
|
|
|
}
|
2016-05-23 21:18:31 +02:00
|
|
|
|
2016-05-24 20:48:31 +02:00
|
|
|
}
|
|
|
|
function startGame(){
|
|
|
|
//empty div
|
2016-06-07 13:24:48 +02:00
|
|
|
while (document.getElementById("fightResult").firstChild) {
|
|
|
|
document.getElementById("fightResult").removeChild(document.getElementById("fightResult").firstChild);
|
|
|
|
}
|
2016-06-07 23:22:18 +02:00
|
|
|
//create board
|
|
|
|
var table=createElem('table',{'class':'battleGrid', 'id': 'board'});
|
2016-06-08 15:47:53 +02:00
|
|
|
for (var i=5; i > -1; i--){
|
2016-05-24 20:48:31 +02:00
|
|
|
var tr=createElem('tr');
|
|
|
|
for (var j=0;j<7; j++){
|
|
|
|
var td=createElem('td',{'id': 'td' + j + '_' + i});
|
|
|
|
tr.appendChild (td);
|
|
|
|
}
|
|
|
|
|
|
|
|
table.appendChild(tr);
|
|
|
|
}
|
|
|
|
document.getElementById('fightResult').appendChild(table);
|
|
|
|
var divLogs=createElem("div",{"id":"logs"});
|
2016-05-27 22:38:24 +02:00
|
|
|
document.getElementById('fightResult').appendChild(divLogs);
|
|
|
|
var newTr=createElem('tr',{'id':'playerButtons','class':'hidden'});
|
|
|
|
for(var i = 0; i < 7; i++){
|
|
|
|
var newTd=createElem('td');
|
|
|
|
var button=createElem('input',{'type':'button','value': i, 'onclick': "playingAT('" + i + "');"});
|
|
|
|
newTd.appendChild(button);
|
|
|
|
newTr.appendChild(newTd);
|
|
|
|
}
|
|
|
|
|
2016-06-07 23:22:18 +02:00
|
|
|
document.getElementById('board').appendChild(newTr);
|
2016-05-27 22:38:24 +02:00
|
|
|
|
2016-06-06 23:37:13 +02:00
|
|
|
board=[["","","","","","",""],
|
2016-05-27 22:38:24 +02:00
|
|
|
["","","","","","",""],
|
|
|
|
["","","","","","",""],
|
|
|
|
["","","","","","",""],
|
|
|
|
["","","","","","",""],
|
|
|
|
["","","","","","",""]];
|
2016-06-07 13:24:48 +02:00
|
|
|
gameId=Math.floor((Math.random() * 10000) + 1);
|
2016-06-06 23:37:13 +02:00
|
|
|
//send init messages
|
|
|
|
for (var p = 1; p < 3 ; p++){
|
|
|
|
|
|
|
|
if(document.getElementById("player" + p + "Type").value == "bot"){
|
|
|
|
var xhr = new XMLHttpRequest();
|
|
|
|
xhr.open("POST", document.getElementById('url' + p).value, false);
|
|
|
|
xhr.setRequestHeader("Content-Type", "application/json");
|
2016-06-12 00:08:54 +02:00
|
|
|
xhr.send(' {"game-id":"' + gameId + '","action":"init","game":"connectFour","players":2,"board":"","player-index":' + (p - 1) +'}');
|
2016-06-07 12:30:45 +02:00
|
|
|
if(xhr.status == 200) {
|
2016-06-12 00:08:54 +02:00
|
|
|
addLog('Message d\'init envoyé au bot player ' + p + ' {"game-id":"' + gameId + '","action":"init","game":"connectFour","players":2,"board":"","player-index":' + (p - 1) +'} <br/> il a répondu ' + xhr.responseText );
|
2016-06-07 12:30:45 +02:00
|
|
|
}else{
|
|
|
|
addLog('player ' + p + ' n est pas joignable ' + xhr.status);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
2016-06-06 23:37:13 +02:00
|
|
|
}
|
2016-05-27 22:38:24 +02:00
|
|
|
play(1);
|
2016-05-24 20:48:31 +02:00
|
|
|
}
|
|
|
|
</script>
|
2016-05-23 21:18:31 +02:00
|
|
|
</head>
|
|
|
|
<body>
|
|
|
|
<header>
|
2016-06-26 00:13:21 +02:00
|
|
|
<h1>ConnectFour's Ludus</h1>
|
2016-05-23 21:18:31 +02:00
|
|
|
</header>
|
|
|
|
<section>
|
2016-06-26 00:13:21 +02:00
|
|
|
<p>Here you can test and fix your bot, against himself, against human or against any other bot if you know the URL.
|
|
|
|
<br/>No scoring here, it's a Ludus (gladiators training center).</p>
|
|
|
|
|
2016-05-23 21:18:31 +02:00
|
|
|
<aside>
|
|
|
|
<h2>Configure the test</h2>
|
2016-05-24 20:48:31 +02:00
|
|
|
<table>
|
|
|
|
<tr>
|
|
|
|
<td>Player 1</td>
|
2016-05-26 00:00:54 +02:00
|
|
|
<td><select id="player1Type" name="player1Type" onchange="changePlayerType(1,this.value);">
|
2016-05-24 20:48:31 +02:00
|
|
|
<option value="bot">bot</option>
|
|
|
|
<option value="human">human</option>
|
|
|
|
</select>
|
|
|
|
</td>
|
2016-06-28 14:29:34 +02:00
|
|
|
|
|
|
|
</tr>
|
|
|
|
<tr>
|
|
|
|
<td colspan="2">
|
2016-06-07 16:56:18 +02:00
|
|
|
<input id="url1" type="text" name="player1URL" placeholder="url du bot http://localhost" value="https://ias.tinad.fr/StupidIAconnectFour.php"/>
|
2016-05-24 20:48:31 +02:00
|
|
|
</td>
|
|
|
|
</tr>
|
2016-06-28 14:29:34 +02:00
|
|
|
|
|
|
|
|
2016-05-24 20:48:31 +02:00
|
|
|
<tr>
|
|
|
|
<td>Player 2</td>
|
|
|
|
<td>
|
2016-05-26 00:00:54 +02:00
|
|
|
<select id="player2Type" name="player2Type" onchange="changePlayerType(2,this.value);">
|
2016-05-24 20:48:31 +02:00
|
|
|
<option value="human">human</option>
|
|
|
|
<option value="bot">bot</option>
|
|
|
|
</select>
|
|
|
|
</td>
|
2016-06-28 14:29:34 +02:00
|
|
|
</tr>
|
|
|
|
<tr>
|
|
|
|
<td colspan="2">
|
2016-06-07 16:56:18 +02:00
|
|
|
<input id="url2" type="text" name="player2URL" placeholder="url du bot http://localhost" disabled value="https://ias.tinad.fr/StupidIAconnectFour.php"/>
|
2016-05-24 20:48:31 +02:00
|
|
|
</td>
|
|
|
|
</tr>
|
2016-06-28 14:29:34 +02:00
|
|
|
|
2016-05-24 20:48:31 +02:00
|
|
|
</table>
|
2016-05-23 21:18:31 +02:00
|
|
|
<p><input type="button" onclick="startGame()" value="Fight"/></p>
|
|
|
|
</aside>
|
2016-05-24 20:48:31 +02:00
|
|
|
<article id="fightResult">
|
|
|
|
</article>
|
2016-05-23 21:18:31 +02:00
|
|
|
</section>
|
|
|
|
<footer>
|
|
|
|
<a href="/p/About">About</a><a href="https://github.com/gnieark/botsArena">Bots'Arena source code</a><a href="/p/legals">Mentions légales</a>
|
|
|
|
</footer>
|
|
|
|
</body>
|
2016-06-07 16:56:18 +02:00
|
|
|
</html>
|