added control example
This commit is contained in:
parent
afbc38d602
commit
7bacd3555e
3 changed files with 430 additions and 0 deletions
80
examples/browser/control.html
Normal file
80
examples/browser/control.html
Normal file
|
@ -0,0 +1,80 @@
|
|||
<!doctype html>
|
||||
|
||||
<html lang="en">
|
||||
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
|
||||
<title>Jocly Game Control</title>
|
||||
<meta name="description" content="Jocly Game Control">
|
||||
<meta name="author" content="Jocly">
|
||||
|
||||
<link rel="stylesheet" href="css/control-styles.css">
|
||||
|
||||
</head>
|
||||
|
||||
<body>
|
||||
|
||||
<div id="container">
|
||||
<div id="applet">
|
||||
<div id="progress-bar"></div>
|
||||
</div>
|
||||
<div id="controls">
|
||||
<div id="game-title" style="display: none;" class="box">Jocly Game</div>
|
||||
<div id="game-status" style="display: none;" class="box">Status</div>
|
||||
<div id="mode-panel" style="display: none;" class="box">
|
||||
<h3>Controls</h3>
|
||||
<button id="restart">Restart game</button><br/><br/>
|
||||
<button id="takeback">Take back</button><br/><br/>
|
||||
<select id="mode">
|
||||
<option value="self-self">Self / Self</option>
|
||||
<option value="self-comp">Self / Computer</option>
|
||||
<option value="comp-self">Computer / Self</option>
|
||||
<option value="comp-comp">Computer / Computer</option>
|
||||
</select><br/><br/>
|
||||
<label id="level-a" for="select-level-PLAYER_A">Computer(A) level<br/>
|
||||
<select id="select-level-a"></select><br/><br/>
|
||||
</label>
|
||||
<label id="level-b" for="select-level-b">Computer(B) level<br/>
|
||||
<select id="select-level-b"></select><br/><br/>
|
||||
</label>
|
||||
<button id="fullscreen" style="display: none;">Full screen</button><br/><br/>
|
||||
</div>
|
||||
<div id="options" style="display: none;" class="box">
|
||||
<h3>Options</h3>
|
||||
<select id="options-skin"></select><br/><br/>
|
||||
<label id="options-notation" for="options-notation-input">
|
||||
<input id="options-notation-input" type="checkbox"/> Notation<br/>
|
||||
</label>
|
||||
<label id="options-moves" for="options-moves-input">
|
||||
<input id="options-moves-input" type="checkbox"/> Show possible moves<br/>
|
||||
</label>
|
||||
<label id="options-autocomplete" for="options-autocomplete-input">
|
||||
<input id="options-autocomplete-input" type="checkbox"/> Auto-complete moves<br/>
|
||||
</label>
|
||||
<label id="options-sounds" for="options-sounds-input">
|
||||
<input id="options-sounds-input" type="checkbox"/> Sounds<br/>
|
||||
</label>
|
||||
</div>
|
||||
<div id="links">
|
||||
<a href="https://github.com/mi-g/jocly">Jocly on Github</a> -
|
||||
<a href="javascript:void(0)" id="other-games">Other Jocly games</a>
|
||||
</div>
|
||||
</div>
|
||||
<div id="games" style="display:none">
|
||||
<div id="close-games">
|
||||
<span></span>
|
||||
</div>
|
||||
<div id="game-list"></div>
|
||||
</div>
|
||||
|
||||
|
||||
</div>
|
||||
|
||||
<script src="../../dist/browser/jocly.js"></script>
|
||||
<script src="https://code.jquery.com/jquery-3.2.1.min.js" integrity="sha256-hwg4gsxgFZhOsEEamdOYGBf13FyQuiTwlAQgxVSNgt4="
|
||||
crossorigin="anonymous"></script>
|
||||
<script src="js/control.js"></script>
|
||||
</body>
|
||||
|
||||
</html>
|
99
examples/browser/css/control-styles.css
Normal file
99
examples/browser/css/control-styles.css
Normal file
|
@ -0,0 +1,99 @@
|
|||
* {
|
||||
box-sizing: border-box;
|
||||
}
|
||||
html,body {
|
||||
height: 100%;
|
||||
margin: 0;
|
||||
}
|
||||
#container {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
display: table;
|
||||
table-layout: fixed;
|
||||
}
|
||||
#applet {
|
||||
display: table-cell;
|
||||
width: 60%;
|
||||
height: 100%;
|
||||
position: relative;
|
||||
}
|
||||
#controls {
|
||||
display: table-cell;
|
||||
width: 33%;
|
||||
vertical-align: top;
|
||||
padding: 0 .5em 0 .5em;
|
||||
}
|
||||
.box {
|
||||
background-color: #f0f0f0;
|
||||
border: 2px solid #e0e0e0;
|
||||
border-radius: 1em;
|
||||
padding: 1em;
|
||||
margin: 8px 0 8px 0;
|
||||
}
|
||||
#progress-bar {
|
||||
height: 5px;
|
||||
background-color: rgba(0,255,0,.3);
|
||||
transition: width .5s;
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
z-index: 10;
|
||||
display: none;
|
||||
}
|
||||
#game-title {
|
||||
background-color: #0f0f0f;
|
||||
color: #fff;
|
||||
font-weight: bold;
|
||||
text-align: center;
|
||||
}
|
||||
#game-status {
|
||||
}
|
||||
#links {
|
||||
text-align: center;
|
||||
}
|
||||
#games {
|
||||
display: table-cell;
|
||||
width: 33%;
|
||||
vertical-align: top;
|
||||
padding: 0;
|
||||
position: relative;
|
||||
}
|
||||
#close-games {
|
||||
text-align: right;
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
border-bottom: 1px solid #eee;
|
||||
background-color: #fff;
|
||||
}
|
||||
#close-games {
|
||||
font-size: 16pt;
|
||||
padding: 6px;
|
||||
cursor: pointer;
|
||||
}
|
||||
#game-list {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
Xfloat: right;
|
||||
overflow-y: auto;
|
||||
Xborder: 1px solid #eee;
|
||||
margin: 0px;
|
||||
padding: 40px 8px 8px 8px;
|
||||
}
|
||||
|
||||
.game-descr {
|
||||
background-repeat: no-repeat;
|
||||
background-position: left center;
|
||||
background-size: 32px;
|
||||
cursor: pointer;
|
||||
padding: 4px 4px 4px 40px;
|
||||
}
|
||||
|
||||
.game-descr:hover {
|
||||
background-color: #eee;
|
||||
}
|
||||
|
||||
.game-descr-name {
|
||||
font-weight: bold;
|
||||
}
|
251
examples/browser/js/control.js
Normal file
251
examples/browser/js/control.js
Normal file
|
@ -0,0 +1,251 @@
|
|||
|
||||
/*
|
||||
* Displays winner
|
||||
*/
|
||||
function NotifyWinner(winner) {
|
||||
var text = "Draw";
|
||||
if(winner==Jocly.PLAYER_A)
|
||||
text = "A wins";
|
||||
else if(winner==Jocly.PLAYER_B)
|
||||
text = "B wins";
|
||||
$("#game-status").text(text);
|
||||
}
|
||||
|
||||
/*
|
||||
* Run the game
|
||||
*/
|
||||
function RunMatch(match, progressBar) {
|
||||
function NextMove() {
|
||||
// whose turn is it ?
|
||||
match.getTurn()
|
||||
.then((player) => {
|
||||
// display whose turn
|
||||
$("#game-status").text(player==Jocly.PLAYER_A?"A playing":"B playing");
|
||||
var mode = $("#mode").val();
|
||||
// first make sure there is no user input or machine search in progress
|
||||
var promise = match.abortUserTurn() // just in case one is running
|
||||
.then( () => {
|
||||
return match.abortMachineSearch(); // just in case one is running
|
||||
});
|
||||
if((player==Jocly.PLAYER_A && (mode=="self-self" || mode=="self-comp")) ||
|
||||
(player==Jocly.PLAYER_B && (mode=="self-self" || mode=="comp-self")))
|
||||
// user to play
|
||||
promise = promise.then( () => {
|
||||
// reques user input
|
||||
return match.userTurn()
|
||||
})
|
||||
else {
|
||||
// machine to play
|
||||
if(progressBar) {
|
||||
progressBar.style.display = "block";
|
||||
progressBar.style.width = 0;
|
||||
}
|
||||
promise = promise.then( () => {
|
||||
return match.getConfig();
|
||||
})
|
||||
.then( (config) => {
|
||||
// get machine level
|
||||
var which = player==Jocly.PLAYER_A ? "a" : "b";
|
||||
var levelIndex = $("#select-level-"+which).val();
|
||||
var level = {
|
||||
maxDepth: -1, // kind of random
|
||||
}
|
||||
if(levelIndex>=0)
|
||||
level = config.model.levels[levelIndex];
|
||||
// start machine search
|
||||
return match.machineSearch({
|
||||
level: level,
|
||||
progress: (progress) => {
|
||||
if (progressBar)
|
||||
progressBar.style.width = progress + "%";
|
||||
}
|
||||
})
|
||||
})
|
||||
.then((result) => {
|
||||
// at this point we know the machine move but it has not been played yet
|
||||
// let's play that move
|
||||
return match.playMove(result.move);
|
||||
});
|
||||
}
|
||||
|
||||
promise.then(() => {
|
||||
// is game over ?
|
||||
return match.getFinished()
|
||||
})
|
||||
.then((result) => {
|
||||
if (result.finished)
|
||||
NotifyWinner(result.winner);
|
||||
else
|
||||
NextMove();
|
||||
})
|
||||
.catch((e)=>{
|
||||
console.warn("Turn aborted:",e);
|
||||
})
|
||||
.then(() => {
|
||||
if (progressBar)
|
||||
progressBar.style.display = "none";
|
||||
});
|
||||
})
|
||||
}
|
||||
NextMove();
|
||||
}
|
||||
|
||||
$(document).ready(function () {
|
||||
var progressBar = document.getElementById("progress-bar");
|
||||
var m = /\?game=([^&]+)/.exec(window.location.href);
|
||||
var gameName = m && m[1] || "classic-chess";
|
||||
var elementId = "applet";
|
||||
var area = document.getElementById(elementId);
|
||||
|
||||
Jocly.createMatch(gameName).then((match) => {
|
||||
// get game configuration to setup control UI
|
||||
match.getConfig()
|
||||
.then( (config) => {
|
||||
$("#game-title").show().text(config.model["title-en"]);
|
||||
$("#close-games span").show().text("<< Back to "+config.model["title-en"]);
|
||||
$("#game-status").show();
|
||||
|
||||
var viewOptions = config.view;
|
||||
// fills Skins dropdown with available skins
|
||||
viewOptions.skins.forEach(function(skin) {
|
||||
$("<option/>").attr("value",skin.name).text(skin.title).appendTo($("#options-skin"));
|
||||
});
|
||||
$("#options").show();
|
||||
// get options for the game view
|
||||
match.getViewOptions()
|
||||
.then( (options) => {
|
||||
$("#options-skin").show().val(options.skin);
|
||||
if(options.sounds!==undefined)
|
||||
$("#options-sounds").show().children("input").prop("checked",options.sounds);
|
||||
$("#options-notation").hide();
|
||||
if(options.notation!==undefined)
|
||||
$("#options-notation").show().children("input").prop("checked",options.notation);
|
||||
$("#options-moves").hide();
|
||||
if(options.showMoves!==undefined)
|
||||
$("#options-moves").show().children("input").prop("checked",options.showMoves);
|
||||
$("#options-autocomplete").hide();
|
||||
if(options.autocomplete!==undefined)
|
||||
$("#options-autocomplete").show().children("input").prop("checked",options.autocomplete);
|
||||
|
||||
$("#options").on("change",function() {
|
||||
var opts={};
|
||||
if($("#options-skin").is(":visible"))
|
||||
opts.skin=$("#options-skin").val();
|
||||
if($("#options-notation").is(":visible"))
|
||||
opts.notation=$("#options-notation-input").prop("checked");
|
||||
if($("#options-moves").is(":visible"))
|
||||
opts.showMoves=$("#options-moves-input").prop("checked");
|
||||
if($("#options-autocomplete").is(":visible"))
|
||||
opts.autoComplete=$("#options-autocomplete-input").prop("checked");
|
||||
if($("#options-sounds").is(":visible"))
|
||||
opts.sounds=$("#options-sounds-input").prop("checked");
|
||||
// changed options, tell Jocly about it
|
||||
match.setViewOptions(opts)
|
||||
.then( () => {
|
||||
RunMatch(match,progressBar);
|
||||
})
|
||||
});
|
||||
|
||||
// the match need to be attached to a DOM element for displaying the board
|
||||
match.attachElement(area)
|
||||
.then( () => {
|
||||
RunMatch(match,progressBar);
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
// configure computer levels
|
||||
["a","b"].forEach( (which) => {
|
||||
$("#level-"+which).hide();
|
||||
$("<option/>").attr("value","-1").text("Random").appendTo($("#select-level-"+which));
|
||||
config.model.levels.forEach( (level, index) => {
|
||||
$("<option/>").attr("value",index).text(level.label).appendTo($("#select-level-"+which));
|
||||
});
|
||||
$("#select-level-"+which).val(0);
|
||||
});
|
||||
|
||||
// dropdown to change the players (user/machine)
|
||||
$("#mode-panel").on("change", () => {
|
||||
switch($("#mode").val()) {
|
||||
case "self-self": $("#level-a,#level-b").hide(); break;
|
||||
case "comp-comp": $("#level-a,#level-b").show(); break;
|
||||
case "self-comp": $("#level-a").hide(); $("#level-b").show(); break;
|
||||
case "comp-self": $("#level-b").hide(); $("#level-a").show(); break;
|
||||
}
|
||||
RunMatch(match,progressBar);
|
||||
});
|
||||
$("#mode").val("self-comp").trigger("change");
|
||||
|
||||
$("#restart").on("click",function() {
|
||||
// restart match from the beginning
|
||||
match.rollback(0)
|
||||
.then( () => {
|
||||
RunMatch(match,progressBar);
|
||||
});
|
||||
});
|
||||
|
||||
$("#takeback").on("click",function() {
|
||||
match.getPlayedMoves()
|
||||
.then( (playedMoves) => {
|
||||
// we want to go back to the last user move
|
||||
var mode = $("#mode").val();
|
||||
var lastUserMove = -1;
|
||||
if(
|
||||
((playedMoves.length % 2 == 1) && (mode=="self-self" || mode=="self-comp")) ||
|
||||
((playedMoves.length % 2 == 0) && (mode=="self-self" || mode=="comp-self"))
|
||||
)
|
||||
lastUserMove = playedMoves.length - 1;
|
||||
else if(
|
||||
((playedMoves.length % 2 == 1) && (mode=="self-self" || mode=="comp-self")) ||
|
||||
((playedMoves.length % 2 == 0) && (mode=="self-self" || mode=="self-comp"))
|
||||
)
|
||||
lastUserMove = playedMoves.length - 2;
|
||||
if(lastUserMove>=0)
|
||||
match.rollback(lastUserMove)
|
||||
.then( () => {
|
||||
RunMatch(match,progressBar);
|
||||
});
|
||||
|
||||
});
|
||||
});
|
||||
|
||||
if(area.requestFullscreen)
|
||||
$("#fullscreen").show().on("click",function() {
|
||||
area.requestFullscreen();
|
||||
});
|
||||
|
||||
$("#links").on("click",()=>{
|
||||
$("#controls").hide();
|
||||
$("#games").show();
|
||||
});
|
||||
|
||||
$("#close-games span").on("click",()=>{
|
||||
$("#controls").show();
|
||||
$("#games").hide();
|
||||
});
|
||||
|
||||
// list all available games
|
||||
Jocly.listGames()
|
||||
.then( (games)=>{
|
||||
for(let gameName in games) {
|
||||
var game = games[gameName];
|
||||
$("<div>")
|
||||
.addClass("game-descr")
|
||||
.css({
|
||||
backgroundImage: "url('"+game.thumbnail+"')"
|
||||
})
|
||||
.append($("<div>").addClass("game-descr-name").text(game.title))
|
||||
.append($("<div>").addClass("game-descr-summary").text(game.summary))
|
||||
.bind("click",()=>{
|
||||
var url0 = window.location;
|
||||
var url = url0.origin + url0.pathname + "?game=" + gameName;
|
||||
window.open(url);
|
||||
}).appendTo($("#game-list"));
|
||||
}
|
||||
});
|
||||
|
||||
$("#mode-panel").show();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
Loading…
Reference in a new issue