diff --git a/README.md b/README.md index 968014a..e61abdd 100644 --- a/README.md +++ b/README.md @@ -8,8 +8,8 @@ Zie [voorbeeld in video-formaat](sample/chess-gui.webm). - [x] Gebruikt AJAX (in JSON) voor elke valide zet(paar). - [x] Sessies voor onderbreking. - [x] Status messages. -- [ ] Duidelijke (en mooie) layout. -- [ ] In-game opties (die men op elk moment kan wijzigen). +- [x] Duidelijke (en mooie) layout. +- [x] In-game opties (die men op elk moment kan wijzigen). - [ ] Animatie van pionnen wanneer je ze sleept over het veld. - [ ] Modulariteit (met Roy/chess). - [ ] Veld voor weggewerkte pionnen. diff --git a/chess_gui/lib/chess_gui.pm b/chess_gui/lib/chess_gui.pm index 521eb96..62218be 100644 --- a/chess_gui/lib/chess_gui.pm +++ b/chess_gui/lib/chess_gui.pm @@ -718,7 +718,9 @@ my ($pval, $called_player, $reason, $session) = @_; # Arguments: (Value of all p } sub PROGRAM { +if (!defined($user_mode{$_[2]})) { # Default user mode. $user_mode{$_[2]} = 0; +} # if (!defined($user_mode)) { # print 'Please input your side:', "\n"; # foreach (@player) { @@ -742,7 +744,7 @@ $user_mode{$_[2]} = 0; # } # MATCH: while (1) { - my %diff; + my (%diff, $onlykingcanmove); $player_turn{$_[2]}++; # $player = ($player_turn+1) % 2; @@ -823,21 +825,25 @@ $user_mode{$_[2]} = 0; if ($matches == 0) { $counter{$_[2]}++; if ($counter{$_[2]} >= 2 && $player_turn{$_[2]} > 24) { # End the game if the same applies to the opponent (only the king can move), and $player_turn have passed. + $onlykingcanmove = 0; # @{$diff{'msg'}{'gstatus'}}[$player] = 'Only the kings can act. Stalemate...'; push @{$diff{$pplayer[$player]}{'status'}}, 4; - &POSTCHESS_CALC(&PRETTY_CALC(0, $player), 0, $_[2]); + if ($player == 1) { # Undefine once, for the last player. + &POSTCHESS_CALC(&PRETTY_CALC(0, $player), 0, $_[2]); + } # return; } } - if ($player_turn{$_[2]} >= $action_limit) { # TODO: Is this needed when we have @pseudoinfinite_loop_check? + if (!(defined($onlykingcanmove)) && $player_turn{$_[2]} >= $action_limit) { # TODO: Is this needed when we have @pseudoinfinite_loop_check? # @{$diff{'msg'}{'gstatus'}}[$player] = 'Total turn limit ' . ($player_turn*2) . ' reached: Stalemate...'; push @{$diff{$pplayer[$player]}{'status'}}, 3; - &POSTCHESS_CALC(&PRETTY_CALC(0, $player), 0, $_[2]); + if ($player == 1) { # Undefine once, for the last player. + &POSTCHESS_CALC(&PRETTY_CALC(0, $player), 0, $_[2]); + } # return; } - - if (($player_turn{$_[2]}*2+$player) % ($loop_limit+1) == 0) { # When player 0 is iterating through all chess possibilities in training mode, stop & do the usual decrement when both players have been doing the same four-turn loop at least three times successively. If we don't stop the program here but do stop the four-turn loop, player 1 might prioritize creating loops when breaking the loop would be a final blow for player 0. TODO: Alternatively, we might revert back here to some previous state... + elsif (($player_turn{$_[2]}*2+$player) % ($loop_limit+1) == 0) { # When player 0 is iterating through all chess possibilities in training mode, stop & do the usual decrement when both players have been doing the same four-turn loop at least three times successively. If we don't stop the program here but do stop the four-turn loop, player 1 might prioritize creating loops when breaking the loop would be a final blow for player 0. TODO: Alternatively, we might revert back here to some previous state... my ($evenval1, $unevenval1, $evenval2, $unevenval2); for (my $counter3 = 0; $#{$pseudoinfinite_loop_check{$_[2]}} >= $counter3; $counter3++) { if ($counter3 > 1) { @@ -873,7 +879,9 @@ $user_mode{$_[2]} = 0; } # @{$diff{'status'}}[$player] = 'Loop limit ' . $loop_limit . ' reached: Stalemate...'; push @{$diff{$pplayer[$player]}{'status'}}, 2; - &POSTCHESS_CALC(&PRETTY_CALC(0, $player), 0, $_[2]); + if ($player == 1) { # Undefine once, for the last player. + &POSTCHESS_CALC(&PRETTY_CALC(0, $player), 0, $_[2]); + } # return; } undef @{$pseudoinfinite_loop_check{$_[2]}}; @@ -943,11 +951,22 @@ get '/board/init' => sub { encode_json(\%default_iboard); }; -get '/move/:src/:dst/:stt' => sub { +get '/move/:src/:dst/:stt' => sub { # Logic. +#print route_parameters->get('src'), "\n"; my %diff = &PROGRAM(route_parameters->get('src'), route_parameters->get('dst'), route_parameters->get('stt')); # Includes player input. encode_json(\%diff); }; +get '/board/set/:setting/:stt' => sub { # Settings. +if (route_parameters->get('setting') eq 'Spectator') { + $user_mode{route_parameters->get('stt')} = -1; +} elsif (route_parameters->get('setting') eq 'White') { + $user_mode{route_parameters->get('stt')} = 0; +} elsif (route_parameters->get('setting') eq 'Black') { + $user_mode{route_parameters->get('stt')} = 1; +} +}; + get '/' => sub { send_file '/index.html'; }; diff --git a/chess_gui/public/css/index.css b/chess_gui/public/css/index.css index cbe268e..82cb43d 100644 --- a/chess_gui/public/css/index.css +++ b/chess_gui/public/css/index.css @@ -4,12 +4,44 @@ border-style: solid; overflow-x: scroll; scrollbar-width: none; + background: linear-gradient(to right,transparent 90%,#000),repeating-linear-gradient(90deg,#000 1px,transparent 9px); } #main { display: grid; } +html { + background: url(../i/bg.png); +} + +#notice, #warning { + position: absolute; + right: 2vmin; + top: 14vmin; + background-color: #e66d; +/* padding: 4px;*/ + text-align: center; + border-radius: 25%; + border-left-style: solid; + border-right-style: solid; + min-width: 178px; + box-shadow: inset 4px 4px 4px #bbbbbb; +} + +#warning { + right: 0; + top: 25%; + border-radius: 0; + width: 100%; + font-size: larger; + padding: 5px; +} + +h1 { + text-decoration-line: underline; +} + /* Chess board START */ #board a { @@ -20,19 +52,24 @@ display: flex; flex-flow: column-reverse; /* Order depends on player side #1/3 */ padding-left: 24px; - max-inline-size: 75vh; /* TODO: We don't use SVG for the chess pieces, so it might look pixelated on high-res. Wouldn't it be better to have a resizeable board? */ + max-inline-size: 356px; /* TODO: We don't use SVG for the chess pieces, so it might look pixelated on high-res. Wouldn't it be better to have a resizeable board? */ min-width: 178px; /* From this point onward the item list font size will be too large */ + /* From this point onward the pieces will seem pixelated */ + background-color: peru; + /*! margin-left: 24px; */ + box-shadow: 10px 10px 20px 10px; } .x-row { display: flex; flex-flow: row nowrap; /* Order depends on player side #2/3 */ - padding-left: 32px; + padding-left: 0; /*! min-width: 140px; */ } #y-co > li { flex: 1; + border-left-style: ridge; } #y-co > li:nth-child(2n) > .x-row > li:nth-child(2n) { @@ -56,21 +93,25 @@ /*}*/ #y-co:not(.x-row) { - border-style: solid; + border-style: groove; + border-width: thick; + border-color: tan; } #x-co { display: flex; - padding-top: 1em; + /*! padding-top: 1em; */ flex-flow: row nowrap; list-style-position: inside; list-style-type: upper-alpha; - padding-left: 32px; + padding-left: 0px; + height: 24px; + border-top-style: ridge; } #x-co > li { flex: 1 1 32px; - padding-top: 1em; + padding-top: 0.4em; } img { @@ -111,6 +152,7 @@ figure { display: flex; flex-flow: row; margin: 0 5px 0 5px; + border-radius: 5%; } figure img { @@ -145,16 +187,19 @@ dd.noimg { /* Display text of
and
at the same height when there's no i } .features > li { - padding: 10px; - flex: 0 1 auto; + flex: 1 1 89px; + border-left-style: solid; + border-color: white; } .features { display: flex; flex-flow: row wrap; - background-color: #5583; + background-color: #123; font-weight: bold; font-family: sans-serif; + text-align: center; + box-shadow: inset 10px 20px 10px #345; } .keys { @@ -191,6 +236,8 @@ ul.features > li:hover > ul > li { ul a { text-decoration: none; display: block; + height: inherit; + color: #dd6600; } .key > ul > li:nth-last-child(n+2) a { @@ -216,7 +263,13 @@ ul a { } a:hover { - color: green; + color: #ff22ff; + text-decoration: underline; +} + +.values > li > a:hover, .keys > li > a:hover { + background-color: #123; + box-shadow: inset 2px 4px 2px #345; } .option { @@ -226,4 +279,24 @@ a:hover { padding: 5px; } +.features > li > a { + padding: 8px; +} + /* Chess control panel END */ + +/* Status messages animation START */ + +@keyframes fadeOut { +to { +opacity: 0; +} +} + +@keyframes fadeIn { +to { +opacity: 1; +} +} + +/* Status messages animation END */ diff --git a/chess_gui/public/i/bg.png b/chess_gui/public/i/bg.png new file mode 100644 index 0000000..5ca25f1 Binary files /dev/null and b/chess_gui/public/i/bg.png differ diff --git a/chess_gui/public/js/dand.js b/chess_gui/public/js/dand.js index afa7231..1e384f2 100644 --- a/chess_gui/public/js/dand.js +++ b/chess_gui/public/js/dand.js @@ -13,6 +13,7 @@ var pp = ['White','Black']; var statusm = ['Your turn','Opponent\'s turn','Suggestion','You failed in deceiving your opponent.','You won','You lost','Stalemate','Confirmation','Notice','Connection lost','You resigned','Opponent resigned','Server maintenance']; var nrsuffix = ['st', 'nd', 'rd']; var defsuffix = 'th'; +var auto; //x = 25; //console.log(x.toString(36)); @@ -56,16 +57,35 @@ xhr.open('GET', 'move/' + drag + '/' + drop + '/' + localStorage.state, true); xhr.send(null); var h1TN = statusm[1]; +h1.innerHTML = h1TN; +I('notice').appendChild(h1); var h2TN = statusm[2]; h2.innerHTML = h2TN; -I('main').insertBefore(h2, I('board')); -h1.innerHTML = h1TN; -I('main').insertBefore(h1, h2); +//I('main').insertBefore(h2, I('board')); +I('notice').appendChild(h2); +//I('notice').removeAttribute('style'); +//I('notice').style.opacity = 1; // Cancel out previous animation. +//I('notice').style.animation = ''; // Cancel out previous animation. +//I('notice').style.opacity = 1; +I('notice').setAttribute('style', 'animation: fadeIn 0s ease-in-out 0s normal both;'); +//I('notice').setAttribute('style', 'animation: fadeOut 3s ease-in-out 0s normal both;'); +//I('notice').style.opacity = 1; // Cancel out previous animation. +//I('notice').animate({opacity: 0}, 3000, function() {console.log('lalalalala');}); +//console.log('lalalalala'); +//I('notice').style.animation = ''; // Cancel out previous animation. +//I('notice').style.opacity = 1; // Cancel out previous animation. +//I('notice').style.animation = ''; +//I('notice').style.animation = 'fadeOut 3s ease-in-out 0 1 normal forwards'; +//I('notice').style.opacity = 1; // Cancel out previous animation. +//I('notice').style.animation = ''; // Cancel out previous animation. +//I('notice').style.animation = 'fadeOut 3s ease-in-out 0s 1 normal forwards'; +//I('main').insertBefore(h1, h2); +//I('notice').appendChild(h1, h2); xhr.onload = function () { if (xhr.status === 200) { responseObject = JSON.parse(xhr.responseText); -if (responseObject.White.status[1] === 0 && responseObject.Black.status[1] === 0) { // Legal move(s)? +if (responseObject.White != null && responseObject.Black != null && responseObject.White.status[1] === 0 && responseObject.Black.status[1] === 0) { // Legal move(s)? count = 1; if (responseObject.White.status.length === 6) { if (responseObject.White.status[5] === 4) { @@ -80,15 +100,29 @@ var h2TN = 'Loop limit exceeded.'; } else if (responseObject.White.status[5] === 1) { var h1TN = statusm[4]; var h2TN = 'White took your king.'; +} else { +var rcodew = 0; } } else { var h1TN = statusm[0]; var h2TN = statusm[2]; +var rcodew = 0; } -h2.innerHTML = h2TN; -I('main').insertBefore(h2, I('board')); h1.innerHTML = h1TN; -I('main').insertBefore(h1, h2); +I('notice').appendChild(h1); +h2.innerHTML = h2TN; +//I('main').insertBefore(h2, I('board')); +I('notice').appendChild(h2); +//I('notice').style.opacity = 1; // Cancel out previous animation. +//I('notice').style.animation = ''; +I('notice').setAttribute('style', 'animation: fadeOut 3s ease-in-out 0s normal both;'); +//I('notice').animate({opacity: 0}, 3000, {opacity: 0}); +//I('notice').style.animation = ''; +//I('notice').style.animation = 'fadeOut 3s ease-in-out'; +//I('notice').style.opacity = 1; // Cancel out previous animation. +//I('notice').style.animation = ''; // Cancel out previous animation. +//I('notice').style.animation = 'fadeOut 3s ease-in-out 0s 1 normal forwards'; +//I('main').insertBefore(h1, h2); if (responseObject.Black.status.length === 6) { if (responseObject.Black.status[5] === 4) { @@ -103,11 +137,26 @@ var h2TN = 'Loop limit exceeded.'; } else if (responseObject.Black.status[5] === 1) { var h1TN = statusm[5]; var h2TN = 'Black took your king.'; +} else { +var rcodeb = 0; } -h2.innerHTML = h2TN; -I('main').insertBefore(h2, I('board')); h1.innerHTML = h1TN; -I('main').insertBefore(h1, h2); +I('notice').appendChild(h1); +h2.innerHTML = h2TN; +//I('main').insertBefore(h2, I('board')); +I('notice').appendChild(h2); +//I('notice').style.opacity = 1; // Cancel out previous animation. +//I('notice').style.animation = ''; +I('notice').setAttribute('style', 'animation: fadeOut 3s ease-in-out 0s normal both;'); +//I('notice').animate({opacity: 0}, 3000, {opacity: 0}); +//I('notice').style.animation = ''; +//I('notice').style.animation = 'fadeOut 3s ease-in-out'; +//I('notice').style.opacity = 1; // Cancel out previous animation. +//I('notice').style.animation = ''; // Cancel out previous animation. +//I('notice').style.animation = 'fadeOut 3s ease-in-out 0s 1 normal forwards'; +//I('main').insertBefore(h1, h2); +} else { +var rcodeb = 0; } // else { //var h1TN = statusm[1]; @@ -249,7 +298,8 @@ d.appendChild(li); } else { var h1TN = statusm[0]; h1.innerHTML = h1TN; -I('main').insertBefore(h1, h2); +//I('main').insertBefore(h1, h2); +I('notice').appendChild(h1); var h2TN = statusm[3]; if (count > 1) { if (count > 3) { @@ -261,7 +311,17 @@ h2.innerHTML = h2TN + ' for the ' + count + '' + suffix + '' + ' time } else { h2.innerHTML = h2TN; } -I('main').insertBefore(h2, I('board')); +//I('main').insertBefore(h2, I('board')); +I('notice').appendChild(h2); +//I('notice').style.opacity = 1; // Cancel out previous animation. +//I('notice').style.animation = ''; +I('notice').setAttribute('style', 'animation: fadeOut 3s ease-in-out 0s normal both;'); +//I('notice').animate({opacity: 0}, 3000, {opacity: 0}); +//I('notice').style.animation = ''; +//I('notice').style.animation = 'fadeOut 3s ease-in-out'; +//I('notice').style.opacity = 1; // Cancel out previous animation. +//I('notice').style.animation = ''; // Cancel out previous animation. +//I('notice').style.animation = 'fadeOut 3s ease-in-out 0s 1 normal forwards'; count++; } // TODO: Display status and/or sleep. @@ -272,11 +332,25 @@ count++; //I('description').innerHTML = responseObject.Black.status[1]; } else { var h1TN = statusm[8]; +h1.innerHTML = h1TN; +I('notice').appendChild(h1); var h2TN = statusm[9]; h2.innerHTML = h2TN; -I('main').insertBefore(h2, I('board')); -h1.innerHTML = h1TN; -I('main').insertBefore(h1, h2); +//I('main').insertBefore(h2, I('board')); +I('notice').appendChild(h2); +//I('notice').style.opacity = 1; // Cancel out previous animation. +//I('notice').style.animation = ''; +I('notice').setAttribute('style', 'animation: fadeOut 3s ease-in-out 0s normal both;'); +//I('notice').animate({opacity: 0}, 3000, {opacity: 0}); +//I('notice').style.animation = ''; +//I('notice').style.animation = 'fadeOut 3s ease-in-out'; +//I('notice').style.opacity = 1; // Cancel out previous animation. +//I('notice').style.animation = ''; // Cancel out previous animation. +//I('notice').style.animation = 'fadeOut 3s ease-in-out 0s 1 normal forwards'; +//I('main').insertBefore(h1, h2); +} +if (auto === true && rcodeb === 0 && rcodew === 0) { +dragAndDrop(null, null, auto); } } } @@ -292,3 +366,46 @@ I('main').insertBefore(h1, h2); //drag = this.id; //}} //} + +for (var i=0; C('values').length > i; i++) { // Add event listeners for all options of the chess control panel (1/2). +for (var j=0; C('values')[i].children.length > j; j++) { +C('values')[i].children[j].onclick = function () { +xhr.open('GET', 'board/set/' + this.innerText + '/' + localStorage.state, true); +xhr.send(null); +var selection = this.innerText; +xhr.onload = function () { +if (xhr.status === 200) { +if (selection === 'Spectator') { +auto = true; +dragAndDrop(null, null, auto); +} else { +auto = false; +} +} +} +} +} +} +for (var k=0; C('features')[0].children.length > k; k++) { // Add event listeners for the main navigation of the chess control panel (2/2). +C('features')[0].children[k].onclick = function () { +if (this.textContent === 'New game') { // Reset storage to default, regenerate chessboard, remove log, and generate a new chess game ID. +localStorage.state = S(); +I('y-co').innerHTML = '
'; +I('log').parentNode.removeChild(I('log')); +var ol; +var javascript = localStorage.init.split(','); // TODO: There should be a cleaner way to store/retrieve multidimensional data structures in localStorage. +for (var i=j=0; javascript.length > j; j += 2) { +//if (!localStorage.getItem(javascript[j+1])) { +if (localStorage.getItem(javascript[j]) === null && !localStorage.getItem(javascript[j+1]) && (javascript[j+1] === '' || I(javascript[j+1]) === null)) { +G(i, javascript[j], javascript[j+1]); +} else { +//console.log(javascript[j], localStorage.getItem(javascript[j])); +localStorage.removeItem(javascript[j]); +G(i, javascript[j], javascript[j+1]); +} +//} +i++; +} +} +} +} diff --git a/chess_gui/public/js/head.js b/chess_gui/public/js/head.js index 344da9c..d1048bd 100644 --- a/chess_gui/public/js/head.js +++ b/chess_gui/public/js/head.js @@ -12,7 +12,7 @@ function T(a) { return document.getElementsByTagName(a); } -function S() { +function S() { // Generate a chess game ID. var r = (Math.random()*36).toString(36).substring(2); var f = Math.random().toString().replace(/^0\./, ''); //f = f*10**(f.toString().length-2); @@ -78,7 +78,7 @@ li.innerHTML = srci; // Add. postG(); } -function postG () { +function postG () { // Add event listeners for the generated chessboard. var drag; var drop; for (var b=0; C('coord').length > b; b++) { diff --git a/chess_gui/public/lllll b/chess_gui/public/lllll deleted file mode 100644 index 220c60c..0000000 --- a/chess_gui/public/lllll +++ /dev/null @@ -1,10 +0,0 @@ -use warnings; -use strict; -my @pages; -@pages = { url => 'http://foo.org', - title => 'The Foo Organisation' - }, - { url => 'http://bar.org', - title => 'The Bar Organisation' - }; -print $pages[0]{'url'}; diff --git a/chess_gui/views/index.html b/chess_gui/views/index.html index f7d7b2d..28e5514 100644 --- a/chess_gui/views/index.html +++ b/chess_gui/views/index.html @@ -11,6 +11,8 @@
+
+
    @@ -54,5 +56,6 @@
+