From cb9ba3cc38f95dbadce283537fbeabe845a4636b Mon Sep 17 00:00:00 2001 From: Lahari Gandrapu Date: Sat, 20 Sep 2025 02:41:02 -0400 Subject: [PATCH 01/12] Add mobile responsive design to static chess webpages --- chessClient/README_MOBILE_RESPONSIVE.md | 114 ++++++++++++++++++++++++ chessClient/both.html | 85 +++++++++++++++++- chessClient/css/chessboard-1.0.0.css | 52 +++++++++++ chessClient/html/index.html | 52 ++++++++++- chessClient/index.html | 74 +++++++++++++-- chessClient/parent.html | 102 ++++++++++++++++++++- 6 files changed, 465 insertions(+), 14 deletions(-) create mode 100644 chessClient/README_MOBILE_RESPONSIVE.md diff --git a/chessClient/README_MOBILE_RESPONSIVE.md b/chessClient/README_MOBILE_RESPONSIVE.md new file mode 100644 index 00000000..a1449512 --- /dev/null +++ b/chessClient/README_MOBILE_RESPONSIVE.md @@ -0,0 +1,114 @@ +# Mobile Responsive Chess Client + +## Overview +The static chess client webpages have been enhanced with comprehensive mobile responsive design to provide an optimal user experience across all device sizes. + +## Files Modified + +### 1. `index.html` - Main Chess Board +- Added proper HTML5 doctype and meta viewport tag +- Implemented responsive CSS with mobile-first approach +- Chessboard now scales appropriately on mobile devices (95vw on tablets, 98vw on phones) +- Enhanced cursor element for better mobile interaction +- Added centering and proper spacing for mobile layouts + +### 2. `parent.html` - Parent Window with Controls +- Complete mobile responsive redesign +- Bootstrap grid system optimized for mobile stacking +- Form controls enhanced with better touch targets +- Responsive chessboard iframe sizing +- Improved button layout for mobile interaction +- Added iOS-specific fixes (font-size 16px to prevent zoom) +- Landscape orientation support + +### 3. `both.html` - Dual View Layout +- Responsive dual-pane layout +- Mobile: Stacks vertically (50vh each pane) +- Tablet: Maintains side-by-side layout +- Landscape mobile: Reverts to horizontal layout +- Enhanced visual styling with gradients and shadows +- Proper iframe scaling and minimum heights + +### 4. `css/chessboard-1.0.0.css` - Chessboard Styling +- Added mobile-specific breakpoints +- Responsive board sizing using viewport units +- Optimized touch targets for mobile interaction +- Landscape orientation handling +- Improved notation font sizes for smaller screens + +### 5. `html/index.html` - HTML Subdirectory Version +- Added HTML5 doctype and responsive meta tags +- Mobile-first CSS approach +- Proper viewport scaling for chessboard + +## Responsive Breakpoints + +### Desktop (Default) +- Full-size chessboard and controls +- Standard Bootstrap grid layout + +### Tablet (≤768px) +- Chessboard scales to 95vw +- Form elements stack appropriately +- Buttons maintain full width for better touch interaction + +### Mobile (≤480px) +- Chessboard scales to 98vw with maximum 350px +- Optimized padding and margins +- Smaller font sizes for better fit +- Enhanced touch targets + +### Landscape Mobile +- Special handling for landscape orientation +- Maintains usability in both orientations + +## Features Added + +1. **Touch-Friendly Design** + - Larger touch targets for mobile interaction + - Proper touch-action CSS properties + - iOS-specific optimizations + +2. **Flexible Layouts** + - Viewport-based sizing (vw/vh units) + - Flexbox layouts for better responsive behavior + - Bootstrap grid enhancements + +3. **Cross-Device Compatibility** + - Works on phones, tablets, and desktops + - Handles both portrait and landscape orientations + - Maintains functionality across all screen sizes + +4. **Visual Enhancements** + - Modern gradient backgrounds + - Subtle shadows and rounded corners + - Improved typography scaling + +## Testing + +To test the responsive design: + +1. Start the HTTP server: `python3 -m http.server 8080` +2. Visit the following URLs: + - `http://localhost:8080/index.html` - Main chessboard + - `http://localhost:8080/parent.html` - Parent window with controls + - `http://localhost:8080/both.html` - Dual view layout + - `http://localhost:8080/html/index.html` - HTML subdirectory version + +3. Test on various screen sizes using browser developer tools +4. Test on actual mobile devices for touch interaction + +## Browser Support + +- Chrome/Safari/Firefox on desktop +- Mobile Safari (iOS) +- Chrome Mobile (Android) +- Responsive design works across all modern browsers + +## Next Steps + +The static webpages are now fully mobile responsive. Consider: +1. Testing on actual mobile devices +2. Performance optimization for slower mobile connections +3. Adding PWA features for mobile app-like experience +4. Implementing touch gestures for enhanced mobile interaction diff --git a/chessClient/both.html b/chessClient/both.html index d709de27..141aa8fa 100644 --- a/chessClient/both.html +++ b/chessClient/both.html @@ -12,24 +12,105 @@ height: 100%; margin: 0; padding: 0; + font-family: 'Arial', sans-serif; } .container-fluid { height: 100%; + padding: 0; } .row { height: 100%; + margin: 0; } .col-md-6 { height: 100%; + padding: 5px; + display: flex; + flex-direction: column; + } + + h3 { + margin: 10px 0; + padding: 10px; + background: linear-gradient(135deg, #667eea 0%, #764ba2 100%); + color: white; + text-align: center; + border-radius: 5px; + font-size: 1.2rem; + flex-shrink: 0; } iframe { width: 100%; - height: 100%; - border: 1px solid #ccc; + flex-grow: 1; + border: 2px solid #ddd; + border-radius: 5px; + box-shadow: 0 2px 10px rgba(0,0,0,0.1); + min-height: 400px; + } + + /* Mobile responsive styles */ + @media screen and (max-width: 768px) { + .row { + flex-direction: column; + height: auto; + min-height: 100vh; + } + + .col-md-6 { + height: 50vh; + min-height: 300px; + padding: 3px; + } + + h3 { + font-size: 1rem; + margin: 5px 0; + padding: 8px; + } + + iframe { + min-height: 250px; + border-width: 1px; + } + } + + @media screen and (max-width: 480px) { + .col-md-6 { + height: 45vh; + min-height: 280px; + padding: 2px; + } + + h3 { + font-size: 0.9rem; + margin: 3px 0; + padding: 6px; + } + + iframe { + min-height: 220px; + } + } + + /* Landscape orientation on mobile */ + @media screen and (max-width: 768px) and (orientation: landscape) { + .row { + flex-direction: row; + height: 100vh; + } + + .col-md-6 { + height: 100vh; + width: 50%; + } + + iframe { + min-height: 200px; + } } diff --git a/chessClient/css/chessboard-1.0.0.css b/chessClient/css/chessboard-1.0.0.css index 8dc42fc5..5d0d914c 100644 --- a/chessClient/css/chessboard-1.0.0.css +++ b/chessClient/css/chessboard-1.0.0.css @@ -7,6 +7,9 @@ .board-b72b1 { border: 2px solid #404040; box-sizing: content-box; + max-width: 100%; + height: auto; + margin: 0 auto; } .square-55d63 { @@ -20,6 +23,9 @@ -moz-user-select: none; -ms-user-select: none; user-select: none; + + /* Improve touch targets for mobile */ + touch-action: manipulation; } .white-1e1d7 { @@ -58,3 +64,49 @@ .hightlight-red { color: red; } + +/* Mobile responsive enhancements */ +@media screen and (max-width: 768px) { + .board-b72b1 { + border-width: 1px; + max-width: 95vw; + width: 95vw; + height: 95vw; + } + + .notation-322f9 { + font-size: 14px; + } + + .square-55d63 { + /* Larger touch targets for mobile */ + min-width: 11.875vw; + min-height: 11.875vw; + } +} + +@media screen and (max-width: 480px) { + .board-b72b1 { + max-width: 98vw; + width: 98vw; + height: 98vw; + } + + .notation-322f9 { + font-size: 12px; + } + + .square-55d63 { + min-width: 12.25vw; + min-height: 12.25vw; + } +} + +/* Landscape orientation adjustments */ +@media screen and (max-height: 500px) and (orientation: landscape) { + .board-b72b1 { + max-height: 85vh; + width: 85vh; + height: 85vh; + } +} diff --git a/chessClient/html/index.html b/chessClient/html/index.html index 1960e078..42a4fd00 100644 --- a/chessClient/html/index.html +++ b/chessClient/html/index.html @@ -1,11 +1,61 @@ - + + + + + Chess Game - HTML Version +
@@ -13,6 +17,25 @@ diff --git a/chessClient/parent.html b/chessClient/parent.html index d0e29081..380a7f1b 100644 --- a/chessClient/parent.html +++ b/chessClient/parent.html @@ -13,18 +13,24 @@ body { background: radial-gradient(circle, #202020, #292929); padding: 20px; + min-height: 100vh; + box-sizing: border-box; } h1 { text-align: center; margin-bottom: 30px; + color: white; + font-size: 2rem; } #chessboard { display: block; - margin: 0 auto; + margin: 0 auto 30px auto; border: 2px solid #ffffff; border-radius: 10px; + max-width: 100%; + height: auto; } .form-control { @@ -34,22 +40,32 @@ color: #ffffff; margin-bottom: 15px; padding: 10px; + width: 100%; + box-sizing: border-box; + } + + .form-control::placeholder { + color: #ccc; } .form-label { font-weight: bold; color: white; + margin-bottom: 8px; + display: block; } .btn-custom { border: 2px solid #ffffff; background-color: transparent; - - color: #333; + color: white; border-radius: 10px; padding: 10px 20px; - margin: 10px; + margin: 5px; transition: background-color 0.3s, color 0.3s; + cursor: pointer; + width: 100%; + box-sizing: border-box; } .btn-custom:hover { @@ -61,6 +77,84 @@ text-align: center; color: white; } + + .container { + max-width: 1200px; + margin: 0 auto; + } + + /* Mobile responsive styles */ + @media screen and (max-width: 768px) { + body { + padding: 10px; + } + + h1 { + font-size: 1.5rem; + margin-bottom: 20px; + } + + #chessboard { + width: 90vw; + height: 90vw; + max-width: 350px; + max-height: 350px; + margin-bottom: 20px; + } + + .container { + padding: 0; + } + + .col-md-6 { + margin-bottom: 20px; + } + + .btn-custom { + margin: 5px 0; + padding: 12px 15px; + font-size: 14px; + } + + .form-control { + font-size: 16px; /* Prevents zoom on iOS */ + padding: 12px; + } + } + + @media screen and (max-width: 480px) { + body { + padding: 5px; + } + + h1 { + font-size: 1.3rem; + } + + #chessboard { + width: 95vw; + height: 95vw; + max-width: 300px; + max-height: 300px; + } + + .btn-custom { + padding: 10px 12px; + font-size: 13px; + } + + .form-control { + padding: 10px; + } + + .row { + margin: 0; + } + + .col-md-3, .col-md-6 { + padding: 5px; + } + } From f7af017f07a8859ac02c0aa0c6c8a048eba02560 Mon Sep 17 00:00:00 2001 From: Lahari Gandrapu Date: Thu, 2 Oct 2025 20:22:04 -0400 Subject: [PATCH 02/12] fix: chessClient responsive ui --- chessClient/css/chessboard-1.0.0.css | 35 -------------------- chessClient/index.html | 48 +++++++++++++++++----------- chessClient/index.js | 29 ++++++++++++++++- 3 files changed, 57 insertions(+), 55 deletions(-) diff --git a/chessClient/css/chessboard-1.0.0.css b/chessClient/css/chessboard-1.0.0.css index 5d0d914c..702feb01 100644 --- a/chessClient/css/chessboard-1.0.0.css +++ b/chessClient/css/chessboard-1.0.0.css @@ -7,9 +7,6 @@ .board-b72b1 { border: 2px solid #404040; box-sizing: content-box; - max-width: 100%; - height: auto; - margin: 0 auto; } .square-55d63 { @@ -23,9 +20,6 @@ -moz-user-select: none; -ms-user-select: none; user-select: none; - - /* Improve touch targets for mobile */ - touch-action: manipulation; } .white-1e1d7 { @@ -69,44 +63,15 @@ @media screen and (max-width: 768px) { .board-b72b1 { border-width: 1px; - max-width: 95vw; - width: 95vw; - height: 95vw; } .notation-322f9 { font-size: 14px; } - - .square-55d63 { - /* Larger touch targets for mobile */ - min-width: 11.875vw; - min-height: 11.875vw; - } } @media screen and (max-width: 480px) { - .board-b72b1 { - max-width: 98vw; - width: 98vw; - height: 98vw; - } - .notation-322f9 { font-size: 12px; } - - .square-55d63 { - min-width: 12.25vw; - min-height: 12.25vw; - } -} - -/* Landscape orientation adjustments */ -@media screen and (max-height: 500px) and (orientation: landscape) { - .board-b72b1 { - max-height: 85vh; - width: 85vh; - height: 85vh; - } } diff --git a/chessClient/index.html b/chessClient/index.html index d1bd51f1..b137d3bf 100644 --- a/chessClient/index.html +++ b/chessClient/index.html @@ -30,10 +30,8 @@ } #myBoard { - max-width: 100%; - max-height: 100vh; - width: auto; - height: auto; + width: min(500px, 90vw); + max-width: 90vw; } .lastmove { @@ -60,10 +58,8 @@ } #myBoard { - width: 95vw; - height: 95vw; - max-width: 400px; - max-height: 400px; + width: min(400px, 85vw); + max-width: 85vw; } #cursor { @@ -78,10 +74,8 @@ } #myBoard { - width: 98vw; - height: 98vw; - max-width: 350px; - max-height: 350px; + width: min(320px, 95vw); + max-width: 95vw; } #cursor { @@ -90,14 +84,30 @@ } } - - - -
+ @media screen and (max-width: 350px) { + body { + padding: 1px; + } + + #myBoard { + width: 98vw; + max-width: 98vw; + } + + #cursor { + width: 20vw; + height: 20vw; + } + } - - + + + +
- + + + + \ No newline at end of file diff --git a/chessClient/index.js b/chessClient/index.js index b55942d4..e4409d3e 100644 --- a/chessClient/index.js +++ b/chessClient/index.js @@ -1001,10 +1001,37 @@ var config = { }; if (isLesson == false) { + // Initialize board with proper sizing board = Chessboard("myBoard", config); + + // Force a resize to ensure proper dimensions + setTimeout(function() { + if (board) { + board.resize(); + } + }, 100); + // var overlay = new ChessboardArrows('board_wrapper'); } -$(window).resize(board.resize); +// Handle window resize with proper board resizing +let resizeTimer; +$(window).resize(function() { + clearTimeout(resizeTimer); + resizeTimer = setTimeout(function() { + if (board) { + board.resize(); + } + }, 250); +}); + +// Also handle orientation changes on mobile +$(window).on('orientationchange', function() { + setTimeout(function() { + if (board) { + board.resize(); + } + }, 500); +}); updateStatus(); \ No newline at end of file From ea7fe9560fdad022445a8223209f893cf58ba837 Mon Sep 17 00:00:00 2001 From: Lahari Gandrapu Date: Thu, 2 Oct 2025 21:15:52 -0400 Subject: [PATCH 03/12] fix: chessClient responsive UI --- chessClient/both.html | 29 +++++++++++++------- chessClient/parent.html | 60 ++++++++++++++++++++++++++++++++++------- 2 files changed, 71 insertions(+), 18 deletions(-) diff --git a/chessClient/both.html b/chessClient/both.html index 141aa8fa..82b3e603 100644 --- a/chessClient/both.html +++ b/chessClient/both.html @@ -54,45 +54,56 @@ /* Mobile responsive styles */ @media screen and (max-width: 768px) { + .container-fluid { + height: 100vh; + overflow-y: auto; + } + .row { flex-direction: column; height: auto; min-height: 100vh; + margin: 0; } .col-md-6 { height: 50vh; - min-height: 300px; - padding: 3px; + min-height: 400px; + padding: 2px; + overflow: visible; + display: flex; + flex-direction: column; } h3 { font-size: 1rem; - margin: 5px 0; + margin: 0; padding: 8px; + flex-shrink: 0; } iframe { - min-height: 250px; + height: calc(50vh - 40px); + min-height: 350px; border-width: 1px; + flex-grow: 1; } } @media screen and (max-width: 480px) { .col-md-6 { - height: 45vh; - min-height: 280px; - padding: 2px; + height: 50vh; + padding: 0; } h3 { font-size: 0.9rem; - margin: 3px 0; + margin: 0; padding: 6px; } iframe { - min-height: 220px; + height: calc(50vh - 30px); } } diff --git a/chessClient/parent.html b/chessClient/parent.html index 380a7f1b..6a1636b0 100644 --- a/chessClient/parent.html +++ b/chessClient/parent.html @@ -29,8 +29,9 @@ margin: 0 auto 30px auto; border: 2px solid #ffffff; border-radius: 10px; + width: 300px; + height: 300px; max-width: 100%; - height: auto; } .form-control { @@ -83,6 +84,45 @@ margin: 0 auto; } + /* Iframe-specific styles */ + .iframe-mode #chessboard { + width: 220px; + height: 220px; + margin-bottom: 15px; + } + + .iframe-mode h1 { + font-size: 0.9rem; + margin-bottom: 8px; + } + + .iframe-mode body { + padding: 3px; + min-height: auto; + overflow: hidden; + } + + .iframe-mode .btn-custom { + padding: 6px 10px; + margin: 2px; + font-size: 11px; + } + + .iframe-mode .form-control { + padding: 6px; + margin-bottom: 8px; + font-size: 12px; + } + + .iframe-mode .container { + padding: 0; + margin: 0; + } + + .iframe-mode .col-md-6 { + margin-bottom: 10px; + } + /* Mobile responsive styles */ @media screen and (max-width: 768px) { body { @@ -95,10 +135,8 @@ } #chessboard { - width: 90vw; - height: 90vw; - max-width: 350px; - max-height: 350px; + width: 250px; + height: 250px; margin-bottom: 20px; } @@ -132,10 +170,8 @@ } #chessboard { - width: 95vw; - height: 95vw; - max-width: 300px; - max-height: 300px; + width: 200px; + height: 200px; } .btn-custom { @@ -253,5 +289,11 @@

Parent Window

+ From f78b9098249c87bfc999dcc604274a570818960c Mon Sep 17 00:00:00 2001 From: Lahari Gandrapu Date: Fri, 3 Oct 2025 01:45:41 -0400 Subject: [PATCH 04/12] fix: chessClient index.html --- chessClient/index.html | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/chessClient/index.html b/chessClient/index.html index b137d3bf..b084069b 100644 --- a/chessClient/index.html +++ b/chessClient/index.html @@ -20,18 +20,20 @@ /* Base styles */ body { margin: 0; - padding: 10px; - background-color: #f0f0f0; + padding: 0; + background-color: transparent; display: flex; justify-content: center; align-items: center; min-height: 100vh; box-sizing: border-box; + overflow: hidden; } #myBoard { - width: min(500px, 90vw); - max-width: 90vw; + width: 100%; + max-width: 100%; + height: auto; } .lastmove { @@ -54,12 +56,12 @@ /* Mobile responsive styles */ @media screen and (max-width: 768px) { body { - padding: 5px; + padding: 0; } #myBoard { - width: min(400px, 85vw); - max-width: 85vw; + width: 100%; + max-width: 100%; } #cursor { From 04cfa30f8fa21a21b7e9d4bc99a3d5b886d56145 Mon Sep 17 00:00:00 2001 From: Lahari Gandrapu Date: Fri, 3 Oct 2025 01:59:15 -0400 Subject: [PATCH 05/12] fix: chessClient index.html --- chessClient/index.html | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/chessClient/index.html b/chessClient/index.html index b084069b..bfe547bf 100644 --- a/chessClient/index.html +++ b/chessClient/index.html @@ -20,7 +20,7 @@ /* Base styles */ body { margin: 0; - padding: 0; + padding: 5px; background-color: transparent; display: flex; justify-content: center; @@ -31,9 +31,10 @@ } #myBoard { - width: 100%; - max-width: 100%; - height: auto; + width: min(95vw, 95vh); + height: min(95vw, 95vh); + max-width: 800px; + max-height: 800px; } .lastmove { @@ -60,8 +61,10 @@ } #myBoard { - width: 100%; - max-width: 100%; + width: min(98vw, 98vh); + height: min(98vw, 98vh); + max-width: 500px; + max-height: 500px; } #cursor { From a01d0b8979e156c339967608aaa52effd93f61d6 Mon Sep 17 00:00:00 2001 From: Lahari Gandrapu Date: Fri, 3 Oct 2025 02:17:29 -0400 Subject: [PATCH 06/12] fix: chessClient parent and both html --- chessClient/both.html | 9 +-------- chessClient/parent.html | 33 ++++++++++++++++++++++++--------- 2 files changed, 25 insertions(+), 17 deletions(-) diff --git a/chessClient/both.html b/chessClient/both.html index 82b3e603..0a55f2b9 100644 --- a/chessClient/both.html +++ b/chessClient/both.html @@ -33,14 +33,7 @@ } h3 { - margin: 10px 0; - padding: 10px; - background: linear-gradient(135deg, #667eea 0%, #764ba2 100%); - color: white; - text-align: center; - border-radius: 5px; - font-size: 1.2rem; - flex-shrink: 0; + /* No background property defined */ } iframe { diff --git a/chessClient/parent.html b/chessClient/parent.html index 6a1636b0..c4614fa3 100644 --- a/chessClient/parent.html +++ b/chessClient/parent.html @@ -29,9 +29,10 @@ margin: 0 auto 30px auto; border: 2px solid #ffffff; border-radius: 10px; - width: 300px; - height: 300px; - max-width: 100%; + width: 400px; + height: 400px; + max-width: 90vw; + max-height: 50vh; } .form-control { @@ -86,9 +87,11 @@ /* Iframe-specific styles */ .iframe-mode #chessboard { - width: 220px; - height: 220px; + width: 280px; + height: 280px; margin-bottom: 15px; + max-width: 85%; + max-height: 45vh; } .iframe-mode h1 { @@ -123,6 +126,14 @@ margin-bottom: 10px; } + /* Large desktop screens - bigger chessboard */ + @media screen and (min-width: 1200px) { + #chessboard { + width: 450px; + height: 450px; + } + } + /* Mobile responsive styles */ @media screen and (max-width: 768px) { body { @@ -135,9 +146,11 @@ } #chessboard { - width: 250px; - height: 250px; + width: 350px; + height: 350px; margin-bottom: 20px; + max-width: 85vw; + max-height: 40vh; } .container { @@ -170,8 +183,10 @@ } #chessboard { - width: 200px; - height: 200px; + width: 280px; + height: 280px; + max-width: 80vw; + max-height: 35vh; } .btn-custom { From 47ac2d45bb4448aa193cd0f8ce41ee1a7d48140c Mon Sep 17 00:00:00 2001 From: Lahari Gandrapu Date: Fri, 3 Oct 2025 17:58:49 -0400 Subject: [PATCH 07/12] Save current changes before pulling from main --- chessClient/index.js | 1101 ++++++++++++++++++++---------------------- 1 file changed, 513 insertions(+), 588 deletions(-) diff --git a/chessClient/index.js b/chessClient/index.js index e4409d3e..751501a6 100644 --- a/chessClient/index.js +++ b/chessClient/index.js @@ -1,67 +1,66 @@ -let flag = false; -let lessonFlag = false; -let isLesson = false; -let lessonStarted = false; -let lessonBoard = ""; -let lessonEnd = ""; -let endSquare = ""; -let previousEndSquare = ""; -var squareClass = "square-55d63"; -var $board = $("#myBoard"); -var board = null; -var currentState = new Chess(); -var whiteSquareGrey = "#eebe7bf7"; -var blackSquareGrey = "#ae5716d6"; +let flag = false +let lessonFlag = false +let isLesson = false +let lessonStarted = false +let lessonBoard = '' +let lessonEnd = '' +let endSquare = '' +let previousEndSquare = '' +var squareClass = 'square-55d63' +var $board = $('#myBoard') +var board = null +var currentState = new Chess() +var whiteSquareGrey = '#eebe7bf7' +var blackSquareGrey = '#ae5716d6' -var serverStartNotified = false; +var serverStartNotified = false -var eventMethod = window.addEventListener ? "addEventListener" : "attachEvent"; -var eventer = window[eventMethod]; -var messageEvent = eventMethod == "attachEvent" ? "onmessage" : "message"; +var eventMethod = window.addEventListener ? 'addEventListener' : 'attachEvent' +var eventer = window[eventMethod] +var messageEvent = eventMethod == 'attachEvent' ? 'onmessage' : 'message' -var mentor = ""; -var student = ""; -var role = "student"; +var mentor = '' +var student = '' +var role = 'student' -var playerColor; +var playerColor -var freemoveFlag = false; +var freemoveFlag = false -var myMouseX; -var myMouseY; -const mouseImage = 'img/cursor.png'; +var myMouseX +var myMouseY +const mouseImage = 'img/cursor.png' -var opponentMouseX = 0; -var opponentMouseY = 0; +var opponentMouseX = 0 +var opponentMouseY = 0 -var nextPuzzleMove = []; -var isPuzzle = false; +var nextPuzzleMove = [] +var isPuzzle = false -var highlightFrom = ""; -var highlightTo = ""; +var highlightFrom = '' +var highlightTo = '' -// Listen for mouse position change +// Listen for mouse position change document.addEventListener('mousemove', (event) => { - myMouseX = event.clientX; - myMouseY = event.clientY; + myMouseX = event.clientX + myMouseY = event.clientY - if (mentor && student) - { - sendMouseXY(); + if (mentor && student) { + sendMouseXY() } -}); +}) // Update the position of the other players mouse -function updateOpponentMouseXY() { - const img = document.getElementById("cursor"); - +function updateOpponentMouseXY () { + const img = document.getElementById('cursor') + // Set absolute position values (top and left in pixels) - img.style.top = `${opponentMouseY}px`; - img.style.left = `${opponentMouseX}px`; + img.style.top = `${opponentMouseY}px` + img.style.left = `${opponentMouseX}px` } // References to chess piece images -const chessPieceFolder = 'img/chesspieces/wikipedia/'; +const chessPieceFolder = 'img/chesspieces/wikipedia/' const chessImages = { bB: 'bB.png', // Black Bishop @@ -75,441 +74,409 @@ const chessImages = { wN: 'wN.png', // White Knight wP: 'wP.png', // White Pawn wQ: 'wQ.png', // White Queen - wR: 'wR.png', // White Rook -}; - -function getChessPieceImage(peice) -{ - chessString = chessPieceFolder + chessImages[peice]; - return chessString; + wR: 'wR.png' // White Rook } +function getChessPieceImage (peice) { + chessString = chessPieceFolder + chessImages[peice] + return chessString +} -const socket = io('http://localhost:3001'); - +const socket = io('http://localhost:3001') -let defaultFEN = "rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR"; +let defaultFEN = 'rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR' -letParentKnow(); +letParentKnow() -function removeGreySquares() { - $("#myBoard .square-55d63").css("background", ""); - $("#myBoard .square-55d63").css("background-image", ""); - $("#myBoard .square-55d63").css("background-position", ""); +function removeGreySquares () { + $('#myBoard .square-55d63').css('background', '') + $('#myBoard .square-55d63').css('background-image', '') + $('#myBoard .square-55d63').css('background-position', '') } -function greySquare(square) { - var $square = $("#myBoard .square-" + square); +function greySquare (square) { + var $square = $('#myBoard .square-' + square) - var background = whiteSquareGrey; - if ($square.hasClass("black-3c85d")) { - background = blackSquareGrey; + var background = whiteSquareGrey + if ($square.hasClass('black-3c85d')) { + background = blackSquareGrey } - $square.css("background", background); - $square.css("background-position", "center"); - $square.css("background-image", "url('img/chesspieces/wikipedia/dot.png')"); + $square.css('background', background) + $square.css('background-position', 'center') + $square.css('background-image', "url('img/chesspieces/wikipedia/dot.png')") } -function sendNewGame() -{ - console.log("starting new game with server") - var data = {"mentor": mentor, "student": student, "role": role}; - console.log(data); - socket.emit("newgame", JSON.stringify(data)); +function sendNewGame () { + console.log('starting new game with server') + var data = {'mentor': mentor, 'student': student, 'role': role} + console.log(data) + socket.emit('newgame', JSON.stringify(data)) } // similar to sendNewGame, but for puzzles specifically -function sendNewPuzzle() -{ - console.log("starting new puzzle with server") - var data = {"mentor": mentor, "student": student, "role": role}; - console.log(data); - socket.emit("newPuzzle", JSON.stringify(data)); +function sendNewPuzzle () { + console.log('starting new puzzle with server') + var data = {'mentor': mentor, 'student': student, 'role': role} + console.log(data) + socket.emit('newPuzzle', JSON.stringify(data)) } // for chess server to modify the game's board state & player color, (designed just for puzzles for now) -function sendSetState(fen) -{ - console.log("setting a new board state"); - var data = {"state": fen}; - console.log(data); - socket.emit("setstate", JSON.stringify(data)); +function sendSetState (fen) { + console.log('setting a new board state') + var data = {'state': fen} + console.log(data) + socket.emit('setstate', JSON.stringify(data)) } // for chess server to modify the game's board state & player color, (designed just for puzzles for now) -function sendSetStateColor(fen, color, hints) -{ - console.log("setting a new board state"); - var data = {"state": fen, "color": color, "hints": hints}; - console.log(data); - socket.emit("setstateColor", JSON.stringify(data)); +function sendSetStateColor (fen, color, hints) { + console.log('setting a new board state') + var data = {'state': fen, 'color': color, 'hints': hints} + console.log(data) + socket.emit('setstateColor', JSON.stringify(data)) } -function sendMove(from, to) -{ - console.log("sending move to server"); - var data = {"mentor": mentor, "student": student, "role": role, "from": from, "to": to}; - console.log(data); - socket.emit("move", JSON.stringify(data)); +function sendMove (from, to) { + console.log('sending move to server') + var data = {'mentor': mentor, 'student': student, 'role': role, 'from': from, 'to': to} + console.log(data) + socket.emit('move', JSON.stringify(data)) } - -function sendEndGame() -{ - console.log("sending end game to server"); - var data = {"mentor": mentor, "student": student, "role": role}; - console.log(data); - socket.emit("endgame", JSON.stringify(data)); +function sendEndGame () { + console.log('sending end game to server') + var data = {'mentor': mentor, 'student': student, 'role': role} + console.log(data) + socket.emit('endgame', JSON.stringify(data)) } -function sendMouseXY() -{ - let data = {"x":myMouseX, "y":myMouseY, "mentor":mentor, "student":student}; - socket.emit('mousexy', JSON.stringify(data)); +function sendMouseXY () { + let data = {'x': myMouseX, 'y': myMouseY, 'mentor': mentor, 'student': student} + socket.emit('mousexy', JSON.stringify(data)) } - -function sendLastMove(from, to) { - let data = {"from":from, "to":to, "mentor":mentor, "student":student}; - socket.emit('lastmove', JSON.stringify(data)); +function sendLastMove (from, to) { + let data = {'from': from, 'to': to, 'mentor': mentor, 'student': student} + socket.emit('lastmove', JSON.stringify(data)) } -function sendHighLight(from, to) { - console.log("sending highlihgt"); - let data = {"from":from, "to":to, "mentor":mentor, "student":student}; - socket.emit('highlight', JSON.stringify(data)); +function sendHighLight (from, to) { + console.log('sending highlihgt') + let data = {'from': from, 'to': to, 'mentor': mentor, 'student': student} + socket.emit('highlight', JSON.stringify(data)) } -function sendUndo() -{ - console.log("sending undo to server"); - var data = {"mentor": mentor, "student": student, "role": role}; - console.log(data); - socket.emit("undo", JSON.stringify(data)); +function sendUndo () { + console.log('sending undo to server') + var data = {'mentor': mentor, 'student': student, 'role': role} + console.log(data) + socket.emit('undo', JSON.stringify(data)) } -function sendRemoveGrey() { - var data = {"mentor": mentor, "student": student}; - socket.emit("removegrey", JSON.stringify(data)); +function sendRemoveGrey () { + var data = {'mentor': mentor, 'student': student} + socket.emit('removegrey', JSON.stringify(data)) } -function sendGreySquare(to) -{ - var data = {"mentor": mentor, "student": student, "to": to}; - socket.emit("addgrey", JSON.stringify(data)); +function sendGreySquare (to) { + var data = {'mentor': mentor, 'student': student, 'to': to} + socket.emit('addgrey', JSON.stringify(data)) } -function sendPieceDrag(piece) -{ - console.log("sending drag"); - var data = {"mentor": mentor, "student": student, "piece": piece}; - socket.emit("piecedrag", JSON.stringify(data)); +function sendPieceDrag (piece) { + console.log('sending drag') + var data = {'mentor': mentor, 'student': student, 'piece': piece} + socket.emit('piecedrag', JSON.stringify(data)) } -function sendPieceDrop() -{ - console.log("sending drop"); - var data = {"mentor": mentor, "student": student}; - socket.emit("piecedrop", JSON.stringify(data)); +function sendPieceDrop () { + console.log('sending drop') + var data = {'mentor': mentor, 'student': student} + socket.emit('piecedrop', JSON.stringify(data)) } // sending simple string messages -function sendMessage(message) -{ - console.log("sending message:", message); - var data = {"message": message}; - socket.emit("message", JSON.stringify(data)); +function sendMessage (message) { + console.log('sending message:', message) + var data = {'message': message} + socket.emit('message', JSON.stringify(data)) } // notify front end that their user has created a new game/puzzle as host socket.on('host', () => { - parent.postMessage("host", "*"); - isPuzzle = true; + parent.postMessage('host', '*') + isPuzzle = true }) // notify front end that their user has joined an existing new game/puzzle as guest socket.on('guest', () => { - parent.postMessage("guest", "*"); - isPuzzle = true; + parent.postMessage('guest', '*') + isPuzzle = true }) socket.on('message', (msg) => { - parsedMsg = JSON.parse(msg); - parent.postMessage(parsedMsg.message, "*"); + parsedMsg = JSON.parse(msg) + parent.postMessage(parsedMsg.message, '*') }) // Handle boardstate message from the client socket.on('boardstate', (msg) => { - parsedMsg = JSON.parse(msg); + parsedMsg = JSON.parse(msg) // if served as a client for a puzzle host (a guest does not store nextPuzzleMove for simplicity) - if (nextPuzzleMove.length == 2) { + if (nextPuzzleMove.length == 2) { // for a puzzle host, 'boardstate' message is either initiated by host itself or its guest - + // if initiated by host itself, ignore the message - if (parsedMsg.boardState == currentState.fen()) return; + if (parsedMsg.boardState == currentState.fen()) return // else 'boardstate' message is initiated by puzzle guest // the expected puzzle moves - var source = nextPuzzleMove[0]; - var target = nextPuzzleMove[1]; - + var source = nextPuzzleMove[0] + var target = nextPuzzleMove[1] + // the expected chess board based on expected moves - const testState = new Chess(currentState.fen()); - testState.move({ from: source, to: target }); + const testState = new Chess(currentState.fen()) + testState.move({ from: source, to: target }) // new board state is different from expected board, so client has made an incorrect move - if (testState.fen() != parsedMsg.boardState) { + if (testState.fen() != parsedMsg.boardState) { // snap back, reset puzzle to current state - sendSetState(currentState.fen()); - highlightMove(highlightFrom, highlightTo, "lastmove"); - } else { + sendSetState(currentState.fen()) + highlightMove(highlightFrom, highlightTo, 'lastmove') + } else { // else client has made the expected move - nextPuzzleMove = []; // clear next moves - currentState = new Chess(parsedMsg.boardState); // rearrange board according to guest move - board.position(currentState.fen()); - sendToParent( // notify front end that a move has been made + nextPuzzleMove = [] // clear next moves + currentState = new Chess(parsedMsg.boardState) // rearrange board according to guest move + board.position(currentState.fen()) + sendToParent( // notify front end that a move has been made JSON.stringify({ from: source, - to: target, - }), - ); - } - return; + to: target + }) + ) } - + return + } + // update state of chess board - console.log(currentState); - console.log(currentState.fen()); - currentState = new Chess(parsedMsg.boardState); - console.log("received board state", parsedMsg); - - // setting player color - if (parsedMsg.color) - { - // setting player color for turn keeping - playerColor = parsedMsg.color; - console.log(playerColor); + console.log(currentState) + console.log(currentState.fen()) + currentState = new Chess(parsedMsg.boardState) + console.log('received board state', parsedMsg) + + // setting player color + if (parsedMsg.color) { + // setting player color for turn keeping + playerColor = parsedMsg.color + console.log(playerColor) // setting chess board orientation - config.orientation = parsedMsg.color; - board = Chessboard("myBoard", config); - parent.postMessage("new game received", "*"); - } + config.orientation = parsedMsg.color + board = Chessboard('myBoard', config) + parent.postMessage('new game received', '*') + } // update visuals of chessboard - board.position(currentState.fen()); -}); + board.position(currentState.fen()) +}) socket.on('piecedrag', (msg) => { - - console.log('recieved piece drag'); - parsedMsg = JSON.parse(msg); + console.log('recieved piece drag') + parsedMsg = JSON.parse(msg) // Change the image of the cursor back to default - cursor = document.getElementById('cursor'); - pieceImage = getChessPieceImage(parsedMsg.piece); - - console.log(pieceImage); - console.log(parsedMsg.piece); + cursor = document.getElementById('cursor') + pieceImage = getChessPieceImage(parsedMsg.piece) - cursor.src = pieceImage; + console.log(pieceImage) + console.log(parsedMsg.piece) -}); + cursor.src = pieceImage +}) socket.on('color', (msg) => { - console.log("received color", msg); - parsedMsg = JSON.parse(msg); - playerColor = parsedMsg.color; -}); + console.log('received color', msg) + parsedMsg = JSON.parse(msg) + playerColor = parsedMsg.color +}) socket.on('piecedrop', () => { - - console.log('recieved piece drop'); + console.log('recieved piece drop') // Change the image of the cursor back to default - cursor = document.getElementById('cursor'); - cursor.src = mouseImage; - -}); + cursor = document.getElementById('cursor') + cursor.src = mouseImage +}) socket.on('highlight', (msg) => { // Highlight the anticipated space - console.log("highlight recieved") - parsedMsg = JSON.parse(msg); - highlightMove(parsedMsg.from, parsedMsg.to, 'lastMove'); - -}); + console.log('highlight recieved') + parsedMsg = JSON.parse(msg) + highlightMove(parsedMsg.from, parsedMsg.to, 'lastMove') +}) socket.on('addgrey', (msg) => { - // Highlight the last moved spaces - parsedMsg = JSON.parse(msg); - greySquare(parsedMsg.to); - -}); + parsedMsg = JSON.parse(msg) + greySquare(parsedMsg.to) +}) socket.on('removegrey', () => { - removeGreySquares(); -}); + removeGreySquares() +}) // handle change of opponents mousexy -socket.on('mousexy', (msg)=>{ - let parsedMsg = JSON.parse(msg); - - let viewportWidth = window.innerWidth; - let viewportHeight = window.innerHeight; - - if (parsedMsg.x && parsedMsg.y) - { +socket.on('mousexy', (msg) => { + let parsedMsg = JSON.parse(msg) + + let viewportWidth = window.innerWidth + let viewportHeight = window.innerHeight + + if (parsedMsg.x && parsedMsg.y) { if (isPuzzle) { - opponentMouseX = parsedMsg.x - 28; - opponentMouseY = parsedMsg.y - 28; + opponentMouseX = parsedMsg.x - 28 + opponentMouseY = parsedMsg.y - 28 } else { - opponentMouseX = (-1 * parsedMsg.x) + viewportWidth - 28; - opponentMouseY = (-1 * parsedMsg.y) + viewportHeight - 28; + opponentMouseX = (-1 * parsedMsg.x) + viewportWidth - 28 + opponentMouseY = (-1 * parsedMsg.y) + viewportHeight - 28 } - - updateOpponentMouseXY(); - } -}); + updateOpponentMouseXY() + } +}) // Handle reset message from the client socket.on('reset', () => { // reload page - location.reload(); + location.reload() // deleteAllCookies(); - console.log("resetting board"); -}); + console.log('resetting board') +}) // Handle lastmove message from the client socket.on('lastmove', (msg) => { // Highlight the last moved spaces - parsedMsg = JSON.parse(msg); - if(!parsedMsg.from && !parsedMsg.to && nextPuzzleMove.length > 0) return; - highlightMove(parsedMsg.from, parsedMsg.to, "lastmove"); - -}); + parsedMsg = JSON.parse(msg) + if (!parsedMsg.from && !parsedMsg.to && nextPuzzleMove.length > 0) return + highlightMove(parsedMsg.from, parsedMsg.to, 'lastmove') +}) // Deletes all cookies on iframe -function deleteAllCookies() { - const cookies = document.cookie.split(";"); +function deleteAllCookies () { + const cookies = document.cookie.split(';') for (let cookie of cookies) { - const cookieName = cookie.split("=")[0].trim(); - deleteCookie(cookieName); + const cookieName = cookie.split('=')[0].trim() + deleteCookie(cookieName) } } - // Listen to message from parent window eventer( messageEvent, (e) => { + console.log('client event: ', e) // uncomment for debugging + let data + try { + data = typeof e.data === 'string' ? JSON.parse(e.data) : e.data + } catch (err) { + console.error('Invalid JSON message from parent:', e.data) + return + } - console.log("client event: ", e); // uncomment for debugging - let data; -try { - data = typeof e.data === 'string' ? JSON.parse(e.data) : e.data; -} catch (err) { - console.error("Invalid JSON message from parent:", e.data); - return; -} + updateStatus() + board.position(currentState.fen()) + sendToParent(currentState.fen()) - updateStatus(); - board.position(currentState.fen()); - sendToParent(currentState.fen()); - // get command from parent and send to server - var command = data.command; - if (command == "newgame") { // front end wants to create / join game - sendNewGame(); - } else if (command == "newPuzzle"){ // front end wants to create / join puzzle - sendNewPuzzle(); - } else if (command == "message"){ // front end wants to broadcast a message - sendMessage(data.message); - } else if (command == "endgame") { // front end wants to end existing game / puzzle + var command = data.command + if (command == 'newgame') { // front end wants to create / join game + sendNewGame() + } else if (command == 'newPuzzle') { // front end wants to create / join puzzle + sendNewPuzzle() + } else if (command == 'message') { // front end wants to broadcast a message + sendMessage(data.message) + } else if (command == 'endgame') { // front end wants to end existing game / puzzle // delete game on server - sendEndGame(); - } - else if (command == "userinfo") { - mentor = data.mentor; - student = data.student; - role = data.role; - } else if (command == "undo") { sendUndo(); } + sendEndGame() + } else if (command == 'userinfo') { + mentor = data.mentor + student = data.student + role = data.role + } else if (command == 'undo') { sendUndo() } // check if puzzle if (data.PuzzleId) { - console.log("loading puzzle: ", data.PuzzleId); - currentState.load(data.FEN); - board.position(data.FEN); + console.log('loading puzzle: ', data.PuzzleId) + currentState.load(data.FEN) + board.position(data.FEN) // find the starting color - var activeColor = data.FEN.split(" ")[1]; + var activeColor = data.FEN.split(' ')[1] // the computer makes the first move // change board orientation accordingly // i.e. if active color is w, then player is black, and vice versa - if (activeColor === 'w'){ - playerColor = "black"; - board.orientation('black'); - } - else{ - playerColor = "white"; - board.orientation('white'); + if (activeColor === 'w') { + playerColor = 'black' + board.orientation('black') + } else { + playerColor = 'white' + board.orientation('white') } - sendSetStateColor(currentState.fen(), playerColor, data.Hints); - sendToParent(currentState.fen()); + sendSetStateColor(currentState.fen(), playerColor, data.Hints) + sendToParent(currentState.fen()) } // get and set lessonflag - lessonFlag = data.lessonFlag; + lessonFlag = data.lessonFlag if (lessonFlag == true) { - isLesson = true; + isLesson = true } // move a piece if it's a move message - if ("from" in data && "to" in data) { - currentState.move({ from: data.from, to: data.to }); + if ('from' in data && 'to' in data) { + currentState.move({ from: data.from, to: data.to }) // move highlight - highlightMove(data.from, data.to); + highlightMove(data.from, data.to) - updateStatus(); - sendToParent(currentState.fen()); + updateStatus() + sendToParent(currentState.fen()) } // highlight message - if ("highlightFrom" in data && "highlightTo" in data) { - highlightMove(data.highlightFrom, data.highlightTo, "lastmove"); + if ('highlightFrom' in data && 'highlightTo' in data) { + highlightMove(data.highlightFrom, data.highlightTo, 'lastmove') } - if ("clearhighlight" in data) { - $board.find("." + squareClass).removeClass("lastmove");; + if ('clearhighlight' in data) { + $board.find('.' + squareClass).removeClass('lastmove') } // if this is a lesson, setup lesson if (isLesson == true) { - endSquare = data.endSquare; - lessonBoard = data.boardState; - lessonEnd = data.endState; + endSquare = data.endSquare + lessonBoard = data.boardState + lessonEnd = data.endState if ( - (data.color === "black" || data.color === "white") && + (data.color === 'black' || data.color === 'white') && data.color !== playerColor ) { - playerColor = data.color; - console.log("data.color: " + data.color); - console.log("setting orientation to: " + playerColor); - board.orientation(playerColor); + playerColor = data.color + console.log('data.color: ' + data.color) + console.log('setting orientation to: ' + playerColor) + board.orientation(playerColor) } - previousEndSquare = data.previousEndSquare; + previousEndSquare = data.previousEndSquare - if (previousEndSquare !== "") { - $board.find(".square-" + previousEndSquare).removeClass("highlight"); + if (previousEndSquare !== '') { + $board.find('.square-' + previousEndSquare).removeClass('highlight') } if (lessonStarted == false) { @@ -521,264 +488,250 @@ try { onDrop: onDrop, onMouseoutSquare: onMouseoutSquare, onMouseoverSquare: onMouseoverSquare, - onSnapEnd: onSnapEnd, - }; - board = Chessboard("myBoard", lessonConfig); + onSnapEnd: onSnapEnd + } + board = Chessboard('myBoard', lessonConfig) // var overlay = new ChessboardArrows('board_wrapper'); - lessonStarted = true; - currentState.load(lessonBoard); + lessonStarted = true + currentState.load(lessonBoard) } else { - board.position(data.boardState); - currentState.load(data.boardState); - updateStatus(); + board.position(data.boardState) + currentState.load(data.boardState) + updateStatus() } - $board.find(".square-" + endSquare).addClass("highlight"); + $board.find('.square-' + endSquare).addClass('highlight') } else if (data.boardState == defaultFEN) { - currentState = new Chess(); + currentState = new Chess() } - + if (isLesson == false && data.color && data.boardState) { - playerColor = data.color; - board.orientation(playerColor); - currentState.load(data.boardState); - board.position(data.boardState); - updateStatus(); + playerColor = data.color + board.orientation(playerColor) + currentState.load(data.boardState) + board.position(data.boardState) + updateStatus() } // highlight message // if ("highlightFrom" in data && "highlightTo" in data) { // highlightMove(data.highlightFrom, data.highlightTo); // } - - }, - false, -); + false +) -function highlightMove(from, to, style) { - console.log("hightlight!!!", from, to); - $board.find("." + squareClass).removeClass(style); - if (from !== "remove" || to !== "remove") { +function highlightMove (from, to, style) { + console.log('hightlight!!!', from, to) + $board.find('.' + squareClass).removeClass(style) + if (from !== 'remove' || to !== 'remove') { if (from && to) { - highlightFrom = from; - highlightTo = to; + highlightFrom = from + highlightTo = to } - $board.find(".square-" + from).addClass(style); - $board.find(".square-" + to).addClass(style); + $board.find('.square-' + from).addClass(style) + $board.find('.square-' + to).addClass(style) } } -function flip() { - board.flip(); +function flip () { + board.flip() } - -function letParentKnow() { +function letParentKnow () { if (flag === false) { - parent.postMessage("ReadyToRecieve", "*"); + parent.postMessage('ReadyToRecieve', '*') } - flag = true; + flag = true } -function onDragStart(source, piece, position, orientation) { - +function onDragStart (source, piece, position, orientation) { // if freeplay mode is off - if (!freemoveFlag) - { - - if(!playerColor) { - console.log("Player color not set"); + if (!freemoveFlag) { + if (!playerColor) { + console.log('Player color not set') } - + // if it's your turn - if (playerColor && playerColor[0] == currentState.turn()) - { + if (playerColor && playerColor[0] == currentState.turn()) { // do not pick up pieces if the game is over - if (isLesson == false) { - if (currentState.game_over()) { - sendGameOver(); - return false; - } - } - - if (playerColor === "black") { - if (piece.search(/^w/) !== -1) return false; - } else if (playerColor === "white") { - if (piece.search(/^b/) !== -1) return false; + if (isLesson == false) { + if (currentState.game_over()) { + sendGameOver() + return false } - + } + + if (playerColor === 'black') { + if (piece.search(/^w/) !== -1) return false + } else if (playerColor === 'white') { + if (piece.search(/^b/) !== -1) return false + } + // only pick up pieces for the side to move - if ( - (currentState.turn() === "w" && piece.search(/^b/) !== -1) || - (currentState.turn() === "b" && piece.search(/^w/) !== -1) + if ( + (currentState.turn() === 'w' && piece.search(/^b/) !== -1) || + (currentState.turn() === 'b' && piece.search(/^w/) !== -1) ) { - return false; - } - - sendPieceDrag(piece); + return false } + + sendPieceDrag(piece) + } + } else { + return true } - else - { - return true; - } - } -function onDrop(source, target, draggedPieceSource) { - removeGreySquares(); - sendPieceDrop(); - +function onDrop (source, target, draggedPieceSource) { + removeGreySquares() + sendPieceDrop() + // if we're not in freeplay - if (!freemoveFlag) - { - + if (!freemoveFlag) { // if we're doing a puzzle, check if the move is correct if (nextPuzzleMove.length == 2) { // incorrect move, snapback if (source !== nextPuzzleMove[0] || target !== nextPuzzleMove[1]) { - return "snapback"; + return 'snapback' } // correct move, clear the next expected move - else - nextPuzzleMove = []; + else { nextPuzzleMove = [] } } // see if the move is legal var move = currentState.move({ from: source, to: target, - promotion: "q", // NOTE: always promote to a queen for example simplicity - }); + promotion: 'q' // NOTE: always promote to a queen for example simplicity + }) // illegal move - if (move === null) {return "snapback"} + if (move === null) { return 'snapback' } // legal move - else {sendMove(source, target)}; + else { sendMove(source, target) }; if (isLesson == false) { if (currentState.game_over()) { - sendGameOver(); + sendGameOver() } } // move highlight - highlightMove(source, target, 'lastmove'); + highlightMove(source, target, 'lastmove') // move highlight of mentor/student - sendLastMove(source, target); + sendLastMove(source, target) - updateStatus(); - sendToParent(`piece-${draggedPieceSource}`); + updateStatus() + sendToParent(`piece-${draggedPieceSource}`) sendToParent( JSON.stringify({ from: source, - to: target, - }), - ); - sendToParent(`target:${move.to}`); - sendToParent(currentState.fen()); + to: target + }) + ) + sendToParent(`target:${move.to}`) + sendToParent(currentState.fen()) } } // To add possible move suggestion on chessboard -function onMouseoverSquare(square, piece) { - if (playerColor && playerColor[0] == currentState.turn()) - { +function onMouseoverSquare (square, piece) { + if (playerColor && playerColor[0] == currentState.turn()) { // get list of possible moves for this square var moves = currentState.moves({ square: square, - verbose: true, - }); + verbose: true + }) // exit if there are no moves available for this square - if (moves.length === 0) return; + if (moves.length === 0) return // highlight the possible squares for this piece for (var i = 0; i < moves.length; i++) { - greySquare(moves[i].to); - sendGreySquare(moves[i].to); + greySquare(moves[i].to) + sendGreySquare(moves[i].to) } } } // To remove possible move suggestion on chessboard -function onMouseoutSquare(square, piece) { - removeGreySquares(); - sendRemoveGrey(); +function onMouseoutSquare (square, piece) { + removeGreySquares() + sendRemoveGrey() } -function sendToParent(fen) { - parent.postMessage(fen, "*"); +function sendToParent (fen) { + parent.postMessage(fen, '*') } // update the board position after the piece snap // for castling, en passant, pawn promotion -function onSnapEnd() { - board.position(currentState.fen()); +function onSnapEnd () { + board.position(currentState.fen()) } -function updateStatus() { - var status = ""; +function updateStatus () { + var status = '' - var moveColor = "White"; + var moveColor = 'White' - if (currentState.turn() === "b") { - moveColor = "Black"; + if (currentState.turn() === 'b') { + moveColor = 'Black' } // checkmate? if (isLesson == false) { if (currentState.in_checkmate()) { - status = "Game over, " + moveColor + " is in checkmate."; - sendCheckmate(); + status = 'Game over, ' + moveColor + ' is in checkmate.' + sendCheckmate() } // draw? else if (currentState.in_draw()) { - status = "Game over, drawn position"; - sendDraw(); + status = 'Game over, drawn position' + sendDraw() } } // game still on else { - status = moveColor + " to move"; + status = moveColor + ' to move' // check? if (currentState.in_check()) { - status += ", " + moveColor + " is in check"; + status += ', ' + moveColor + ' is in check' } - if(currentState.game_over()){ - if (currentState.in_check() && moveColor == "Black") { - parent.postMessage("won:white", "*"); - } else if (currentState.in_check() && moveColor == "Black") { - parent.postMessage("won:black", "*"); + if (currentState.game_over()) { + if (currentState.in_check() && moveColor == 'Black') { + parent.postMessage('won:white', '*') + } else if (currentState.in_check() && moveColor == 'Black') { + parent.postMessage('won:black', '*') } else { - parent.postMessage("restart", "*"); + parent.postMessage('restart', '*') } } } } -function sendGameOver() { - parent.postMessage("gameOver", "*"); +function sendGameOver () { + parent.postMessage('gameOver', '*') } -function sendDraw() { - parent.postMessage("draw", "*"); +function sendDraw () { + parent.postMessage('draw', '*') } -function sendCheckmate() { - parent.postMessage("checkmate", "*"); +function sendCheckmate () { + parent.postMessage('checkmate', '*') } // chessboard arrows var ChessboardArrows = function ( id, RES_FACTOR = 2, - COLOUR = "rgb(0, 128,0,1)", + COLOUR = 'rgb(0, 128,0,1)' ) { - const NUM_SQUARES = 8; + const NUM_SQUARES = 8 var resFactor, colour, drawCanvas, @@ -786,169 +739,168 @@ var ChessboardArrows = function ( primaryCanvas, primaryContext, initialPoint, - mouseDown; + mouseDown - resFactor = RES_FACTOR; - colour = COLOUR; + resFactor = RES_FACTOR + colour = COLOUR // drawing canvas - drawCanvas = document.getElementById("drawing_canvas"); - drawContext = changeResolution(drawCanvas, resFactor); - setContextStyle(drawContext); + drawCanvas = document.getElementById('drawing_canvas') + drawContext = changeResolution(drawCanvas, resFactor) + setContextStyle(drawContext) // primary canvas - primaryCanvas = document.getElementById("primary_canvas"); - primaryContext = changeResolution(primaryCanvas, resFactor); - setContextStyle(primaryContext); + primaryCanvas = document.getElementById('primary_canvas') + primaryContext = changeResolution(primaryCanvas, resFactor) + setContextStyle(primaryContext) // setup mouse event callbacks - var board = document.getElementById(id); - board.addEventListener("mousedown", function (event) { - onMouseDown(event); - }); - board.addEventListener("mouseup", function (event) { - onMouseUp(event); - }); - board.addEventListener("mousemove", function (event) { - onMouseMove(event); - }); + var board = document.getElementById(id) + board.addEventListener('mousedown', function (event) { + onMouseDown(event) + }) + board.addEventListener('mouseup', function (event) { + onMouseUp(event) + }) + board.addEventListener('mousemove', function (event) { + onMouseMove(event) + }) board.addEventListener( - "contextmenu", + 'contextmenu', function (e) { - e.preventDefault(); + e.preventDefault() }, - false, - ); + false + ) // initialise vars - initialPoint = { x: null, y: null }; - finalPoint = { x: null, y: null }; - arrowWidth = 15; - mouseDown = false; + initialPoint = { x: null, y: null } + finalPoint = { x: null, y: null } + arrowWidth = 15 + mouseDown = false // source: https://stackoverflow.com/questions/808826/draw-arrow-on-canvas-tag - function drawArrow(context, fromx, fromy, tox, toy, r) { - var x_center = tox; - var y_center = toy; - var angle, x, y; + function drawArrow (context, fromx, fromy, tox, toy, r) { + var x_center = tox + var y_center = toy + var angle, x, y - context.beginPath(); + context.beginPath() - angle = Math.atan2(toy - fromy, tox - fromx); - x = r * Math.cos(angle) + x_center; - y = r * Math.sin(angle) + y_center; + angle = Math.atan2(toy - fromy, tox - fromx) + x = r * Math.cos(angle) + x_center + y = r * Math.sin(angle) + y_center - context.moveTo(x, y); + context.moveTo(x, y) - angle += (1 / 3) * (2 * Math.PI); - x = r * Math.cos(angle) + x_center; - y = r * Math.sin(angle) + y_center; + angle += (1 / 3) * (2 * Math.PI) + x = r * Math.cos(angle) + x_center + y = r * Math.sin(angle) + y_center - context.lineTo(x, y); + context.lineTo(x, y) - angle += (1 / 3) * (2 * Math.PI); - x = r * Math.cos(angle) + x_center; - y = r * Math.sin(angle) + y_center; + angle += (1 / 3) * (2 * Math.PI) + x = r * Math.cos(angle) + x_center + y = r * Math.sin(angle) + y_center - context.lineTo(x, y); - context.closePath(); - context.fill(); + context.lineTo(x, y) + context.closePath() + context.fill() } - function getMousePos(canvas, evt) { - var rect = canvas.getBoundingClientRect(); + function getMousePos (canvas, evt) { + var rect = canvas.getBoundingClientRect() return { x: Q(evt.clientX - rect.left), - y: Q(evt.clientY - rect.top), - }; + y: Q(evt.clientY - rect.top) + } } - function setContextStyle(context) { - context.strokeStyle = context.fillStyle = colour; - context.lineJoin = "butt"; + function setContextStyle (context) { + context.strokeStyle = context.fillStyle = colour + context.lineJoin = 'butt' } - function onMouseDown(event) { + function onMouseDown (event) { if (event.which == 3) { // right click - mouseDown = true; - initialPoint = finalPoint = getMousePos(drawCanvas, event); + mouseDown = true + initialPoint = finalPoint = getMousePos(drawCanvas, event) drawCircle( drawContext, initialPoint.x, initialPoint.y, - primaryCanvas.width / (resFactor * NUM_SQUARES * 2) - 1, - ); + primaryCanvas.width / (resFactor * NUM_SQUARES * 2) - 1 + ) } } - function onMouseUp(event) { + function onMouseUp (event) { if (event.which == 3) { // right click - mouseDown = false; + mouseDown = false // if starting position == ending position, draw a circle to primary canvas if (initialPoint.x == finalPoint.x && initialPoint.y == finalPoint.y) { drawCircle( primaryContext, initialPoint.x, initialPoint.y, - primaryCanvas.width / (resFactor * NUM_SQUARES * 2) - 1, - ); // reduce radius of square by 1px + primaryCanvas.width / (resFactor * NUM_SQUARES * 2) - 1 + ) // reduce radius of square by 1px } // otherwise draw an arrow else { - drawArrowToCanvas(primaryContext); + drawArrowToCanvas(primaryContext) } - drawContext.clearRect(0, 0, drawCanvas.width, drawCanvas.height); + drawContext.clearRect(0, 0, drawCanvas.width, drawCanvas.height) } else if (event.which == 1) { // left click // clear canvases - drawContext.clearRect(0, 0, drawCanvas.width, drawCanvas.height); - primaryContext.clearRect(0, 0, primaryCanvas.width, primaryCanvas.height); + drawContext.clearRect(0, 0, drawCanvas.width, drawCanvas.height) + primaryContext.clearRect(0, 0, primaryCanvas.width, primaryCanvas.height) } } - function onMouseMove(event) { - finalPoint = getMousePos(drawCanvas, event); + function onMouseMove (event) { + finalPoint = getMousePos(drawCanvas, event) - if (!mouseDown) return; - if (initialPoint.x == finalPoint.x && initialPoint.y == finalPoint.y) - return; + if (!mouseDown) return + if (initialPoint.x == finalPoint.x && initialPoint.y == finalPoint.y) { return } - drawContext.clearRect(0, 0, drawCanvas.width, drawCanvas.height); - drawArrowToCanvas(drawContext); + drawContext.clearRect(0, 0, drawCanvas.width, drawCanvas.height) + drawArrowToCanvas(drawContext) } - function drawArrowToCanvas(context) { + function drawArrowToCanvas (context) { // offset finalPoint so the arrow head hits the center of the square - var xFactor, yFactor, offsetSize; + var xFactor, yFactor, offsetSize if (finalPoint.x == initialPoint.x) { - yFactor = Math.sign(finalPoint.y - initialPoint.y) * arrowWidth; - xFactor = 0; + yFactor = Math.sign(finalPoint.y - initialPoint.y) * arrowWidth + xFactor = 0 } else if (finalPoint.y == initialPoint.y) { - xFactor = Math.sign(finalPoint.x - initialPoint.x) * arrowWidth; - yFactor = 0; + xFactor = Math.sign(finalPoint.x - initialPoint.x) * arrowWidth + yFactor = 0 } else { // find delta x and delta y to achieve hypotenuse of arrowWidth slope_mag = Math.abs( - (finalPoint.y - initialPoint.y) / (finalPoint.x - initialPoint.x), - ); + (finalPoint.y - initialPoint.y) / (finalPoint.x - initialPoint.x) + ) xFactor = (Math.sign(finalPoint.x - initialPoint.x) * arrowWidth) / - Math.sqrt(1 + Math.pow(slope_mag, 2)); + Math.sqrt(1 + Math.pow(slope_mag, 2)) yFactor = Math.sign(finalPoint.y - initialPoint.y) * Math.abs(xFactor) * - slope_mag; + slope_mag } // draw line - context.beginPath(); - context.lineCap = "round"; - context.lineWidth = 8; - context.moveTo(initialPoint.x, initialPoint.y); - context.lineTo(finalPoint.x - xFactor, finalPoint.y - yFactor); - context.stroke(); + context.beginPath() + context.lineCap = 'round' + context.lineWidth = 8 + context.moveTo(initialPoint.x, initialPoint.y) + context.lineTo(finalPoint.x - xFactor, finalPoint.y - yFactor) + context.stroke() // draw arrow head drawArrow( @@ -957,81 +909,54 @@ var ChessboardArrows = function ( initialPoint.y, finalPoint.x - xFactor, finalPoint.y - yFactor, - arrowWidth, - ); + arrowWidth + ) } - function Q(x, d) { + function Q (x, d) { // mid-tread quantiser - d = primaryCanvas.width / (resFactor * NUM_SQUARES); - return d * (Math.floor(x / d) + 0.5); + d = primaryCanvas.width / (resFactor * NUM_SQUARES) + return d * (Math.floor(x / d) + 0.5) } - function drawCircle(context, x, y, r) { - context.beginPath(); - context.lineWidth = 4; - context.arc(x, y, r, 0, 2 * Math.PI); - context.stroke(); + function drawCircle (context, x, y, r) { + context.beginPath() + context.lineWidth = 4 + context.arc(x, y, r, 0, 2 * Math.PI) + context.stroke() } // source: https://stackoverflow.com/questions/14488849/higher-dpi-graphics-with-html5-canvas - function changeResolution(canvas, scaleFactor) { + function changeResolution (canvas, scaleFactor) { // Set up CSS size. - canvas.style.width = canvas.style.width || canvas.width + "px"; - canvas.style.height = canvas.style.height || canvas.height + "px"; + canvas.style.width = canvas.style.width || canvas.width + 'px' + canvas.style.height = canvas.style.height || canvas.height + 'px' // Resize canvas and scale future draws. - canvas.width = Math.ceil(canvas.width * scaleFactor); - canvas.height = Math.ceil(canvas.height * scaleFactor); - var ctx = canvas.getContext("2d"); - ctx.scale(scaleFactor, scaleFactor); - return ctx; + canvas.width = Math.ceil(canvas.width * scaleFactor) + canvas.height = Math.ceil(canvas.height * scaleFactor) + var ctx = canvas.getContext('2d') + ctx.scale(scaleFactor, scaleFactor) + return ctx } -}; +} var config = { draggable: true, showNotation: true, - position: "start", - orientation: "white", + position: 'start', + orientation: 'white', onDragStart: onDragStart, onDrop: onDrop, onMouseoutSquare: onMouseoutSquare, onMouseoverSquare: onMouseoverSquare, - onSnapEnd: onSnapEnd, -}; + onSnapEnd: onSnapEnd +} if (isLesson == false) { - // Initialize board with proper sizing - board = Chessboard("myBoard", config); - - // Force a resize to ensure proper dimensions - setTimeout(function() { - if (board) { - board.resize(); - } - }, 100); - + board = Chessboard('myBoard', config) // var overlay = new ChessboardArrows('board_wrapper'); } -// Handle window resize with proper board resizing -let resizeTimer; -$(window).resize(function() { - clearTimeout(resizeTimer); - resizeTimer = setTimeout(function() { - if (board) { - board.resize(); - } - }, 250); -}); - -// Also handle orientation changes on mobile -$(window).on('orientationchange', function() { - setTimeout(function() { - if (board) { - board.resize(); - } - }, 500); -}); +$(window).resize(board.resize) -updateStatus(); \ No newline at end of file +updateStatus() \ No newline at end of file From e00de71e299735a22c3cbeb6c8e6dd5a9abab837 Mon Sep 17 00:00:00 2001 From: Lahari Gandrapu Date: Fri, 3 Oct 2025 18:39:06 -0400 Subject: [PATCH 08/12] fix: chessClient index.js --- chessClient/index.js | 29 ++++++++++++++++++++++++++++- 1 file changed, 28 insertions(+), 1 deletion(-) diff --git a/chessClient/index.js b/chessClient/index.js index 8d7e7fac..c76be407 100644 --- a/chessClient/index.js +++ b/chessClient/index.js @@ -953,10 +953,37 @@ var config = { } if (isLesson == false) { + // Initialize board with proper sizing board = Chessboard('myBoard', config) + + // Force a resize to ensure proper dimensions + setTimeout(function() { + if (board) { + board.resize() + } + }, 100) + // var overlay = new ChessboardArrows('board_wrapper'); } -$(window).resize(board.resize) +// Handle window resize with proper board resizing +let resizeTimer +$(window).resize(function() { + clearTimeout(resizeTimer) + resizeTimer = setTimeout(function() { + if (board) { + board.resize() + } + }, 250) +}) + +// Also handle orientation changes on mobile +$(window).on('orientationchange', function() { + setTimeout(function() { + if (board) { + board.resize() + } + }, 500) +}) updateStatus() From d8b1755bed4cf8f676678ac815e182821152be00 Mon Sep 17 00:00:00 2001 From: Lahari Gandrapu Date: Fri, 3 Oct 2025 19:14:36 -0400 Subject: [PATCH 09/12] fix: chessboard rendering in chessClient --- chessClient/index.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/chessClient/index.html b/chessClient/index.html index bfe547bf..580f2c82 100644 --- a/chessClient/index.html +++ b/chessClient/index.html @@ -9,7 +9,7 @@ - + From 5a64c71cebe64ddb73d48071417a53fcd5589c87 Mon Sep 17 00:00:00 2001 From: Lahari Gandrapu Date: Fri, 3 Oct 2025 19:43:01 -0400 Subject: [PATCH 10/12] fix: chessboard rendering in chessClient --- chessClient/index.html | 28 ++++++++++++++++++++-------- chessClient/parent.html | 22 +++++++++++----------- 2 files changed, 31 insertions(+), 19 deletions(-) diff --git a/chessClient/index.html b/chessClient/index.html index 580f2c82..2e6ae4d6 100644 --- a/chessClient/index.html +++ b/chessClient/index.html @@ -31,10 +31,12 @@ } #myBoard { - width: min(95vw, 95vh); - height: min(95vw, 95vh); - max-width: 800px; - max-height: 800px; + width: min(90vw, 90vh); + height: min(90vw, 90vh); + max-width: 600px; + max-height: 600px; + min-width: 300px; + min-height: 300px; } .lastmove { @@ -61,10 +63,12 @@ } #myBoard { - width: min(98vw, 98vh); - height: min(98vw, 98vh); + width: min(95vw, 95vh); + height: min(95vw, 95vh); max-width: 500px; max-height: 500px; + min-width: 280px; + min-height: 280px; } #cursor { @@ -79,8 +83,12 @@ } #myBoard { - width: min(320px, 95vw); + width: min(95vw, 95vh); + height: min(95vw, 95vh); max-width: 95vw; + max-height: 95vh; + min-width: 250px; + min-height: 250px; } #cursor { @@ -95,8 +103,12 @@ } #myBoard { - width: 98vw; + width: min(98vw, 98vh); + height: min(98vw, 98vh); max-width: 98vw; + max-height: 98vh; + min-width: 200px; + min-height: 200px; } #cursor { diff --git a/chessClient/parent.html b/chessClient/parent.html index c4614fa3..306857c5 100644 --- a/chessClient/parent.html +++ b/chessClient/parent.html @@ -29,10 +29,10 @@ margin: 0 auto 30px auto; border: 2px solid #ffffff; border-radius: 10px; - width: 400px; - height: 400px; + width: 500px; + height: 500px; max-width: 90vw; - max-height: 50vh; + max-height: 60vh; } .form-control { @@ -146,11 +146,11 @@ } #chessboard { - width: 350px; - height: 350px; + width: 400px; + height: 400px; margin-bottom: 20px; - max-width: 85vw; - max-height: 40vh; + max-width: 90vw; + max-height: 50vh; } .container { @@ -183,10 +183,10 @@ } #chessboard { - width: 280px; - height: 280px; - max-width: 80vw; - max-height: 35vh; + width: 320px; + height: 320px; + max-width: 85vw; + max-height: 45vh; } .btn-custom { From 940b4bcd853363363f188c59cfef52ae04d0c76d Mon Sep 17 00:00:00 2001 From: Lahari Gandrapu Date: Thu, 9 Oct 2025 03:20:39 -0400 Subject: [PATCH 11/12] Restore chessClient/html/index.html to pre-merge version --- chessClient/html/index.html | 226 ++++++++++++++++++++++++++++++++++++ 1 file changed, 226 insertions(+) create mode 100644 chessClient/html/index.html diff --git a/chessClient/html/index.html b/chessClient/html/index.html new file mode 100644 index 00000000..42a4fd00 --- /dev/null +++ b/chessClient/html/index.html @@ -0,0 +1,226 @@ + + + + + + + + Chess Game - HTML Version + + + + + + +
+ + From 4dd853b3c34e549c919ef826e49172ed2192c4d0 Mon Sep 17 00:00:00 2001 From: Lahari Gandrapu Date: Thu, 9 Oct 2025 03:58:24 -0400 Subject: [PATCH 12/12] ix: chess client local load and responsive board --- chessClient/index.html | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/chessClient/index.html b/chessClient/index.html index 2e6ae4d6..e95909b3 100644 --- a/chessClient/index.html +++ b/chessClient/index.html @@ -9,7 +9,7 @@ - + @@ -35,8 +35,8 @@ height: min(90vw, 90vh); max-width: 600px; max-height: 600px; - min-width: 300px; - min-height: 300px; + min-width: 0; /* allow board to shrink on very small screens */ + min-height: 0; } .lastmove { @@ -67,8 +67,8 @@ height: min(95vw, 95vh); max-width: 500px; max-height: 500px; - min-width: 280px; - min-height: 280px; + min-width: 0; + min-height: 0; } #cursor { @@ -87,8 +87,8 @@ height: min(95vw, 95vh); max-width: 95vw; max-height: 95vh; - min-width: 250px; - min-height: 250px; + min-width: 0; + min-height: 0; } #cursor { @@ -107,8 +107,8 @@ height: min(98vw, 98vh); max-width: 98vw; max-height: 98vh; - min-width: 200px; - min-height: 200px; + min-width: 0; + min-height: 0; } #cursor {