diff options
-rw-r--r-- | TODO.txt | 2 | ||||
-rw-r--r-- | game.html | 2 | ||||
-rw-r--r-- | game.js | 12 | ||||
-rw-r--r-- | index.html | 2 | ||||
-rw-r--r-- | index.js | 8 | ||||
-rw-r--r-- | server/src/main.rs | 22 |
6 files changed, 31 insertions, 17 deletions
@@ -2,3 +2,5 @@ - congratualations - handle server errors on the client side - let user select piece size +- change piece.x,y to relative (% of play-area) +- webgl? maybe? @@ -7,7 +7,7 @@ <meta content="width=device-width,initial-scale=1" name="viewport"> <link rel="icon" href="favicon.png"> <link rel="stylesheet" href="style.css"> - <script src="game.js?v=3" async></script> + <script src="game.js?v=4" async></script> </head> <body> <div id="header"> @@ -212,7 +212,7 @@ window.addEventListener('load', function () { element; nibTypes; connectedComponent; - upToDateWithServer; + needsServerUpdate; getClipPath() { const nibTypes = this.nibTypes; let shoulderWidth = (pieceWidth - nibSize) / 2; @@ -247,7 +247,7 @@ window.addEventListener('load', function () { this.y = y; this.u = u; this.v = v; - this.upToDateWithServer = true; + this.needsServerUpdate = false; this.connectedComponent = [this]; const element = this.element = document.createElement('div'); element.classList.add('piece'); @@ -300,6 +300,7 @@ window.addEventListener('load', function () { piece.element.classList.remove('no-animation'); piece.element.style.zIndex = pieceZIndexCounter; if (solved) break; + piece.needsServerUpdate = true; const col = piece.col(); const row = piece.row(); const bbox = piece.boundingBox(); @@ -341,7 +342,6 @@ window.addEventListener('load', function () { piece.x += dx; piece.y += dy; piece.updatePosition(); - piece.upToDateWithServer = false; } draggingPieceLastPos.x = e.clientX; draggingPieceLastPos.y = e.clientY; @@ -445,7 +445,7 @@ window.addEventListener('load', function () { // only receive the position of one piece per equivalence class mod is-connected-to if (connectivity[i] !== i) continue; const piece = pieces[i]; - if (!piece.upToDateWithServer) continue; + if (piece.needsServerUpdate) continue; if (draggingPiece && draggingPiece.connectedComponent === piece.connectedComponent) continue; const newPos = canonicalToScreenPos({x: piecePositions[2*i], y: piecePositions[2*i+1]}); const diff = [newPos.x - piece.x, newPos.y - piece.y]; @@ -468,7 +468,7 @@ window.addEventListener('load', function () { if (!receivedAck) return; // last update hasn't been acknowledged yet const motions = []; for (const piece of pieces) { - if (piece.upToDateWithServer) continue; + if (!piece.needsServerUpdate) continue; const canonicalPos = screenPosToCanonical({ x: piece.x, y: piece.y, @@ -530,7 +530,7 @@ window.addEventListener('load', function () { setJoinLink(puzzleID); } else if (e.data === 'ack') { for (const piece of pieces) { - piece.upToDateWithServer = true; + piece.needsServerUpdate = false; } receivedAck = true; } else if (waitingForServerToGiveUsImageUrl && e.data.startsWith('useImage ')) { @@ -19,7 +19,7 @@ <body class="margined"> <h3>jigsaw</h3> <form id="host-form" method="dialog" action="#"> - <div class="form-line"><label><input type="number" min="10" max="1000" name="pieces" value="100"> 🧩 Number of pieces</label></div> + <div class="form-line"><label><input type="number" min="10" max="1000" name="pieces" value="100" id="piece-count"> 🧩 Number of pieces</label></div> <div class="form-line"> <fieldset> <legend>Choose your image…</legend> @@ -1,7 +1,12 @@ -window.addEventListener('load', function () { +window.addEventListener('load', function () { const getById = (id) => document.getElementById(id); const customImageRadio = getById("custom-image"); const customImageURL = getById("image-url"); + const pieceCountInput = getById("piece-count"); + const lastPieceCount = parseInt(localStorage.getItem('jigsaw.index.pieceCount')); + if (isFinite(lastPieceCount) && lastPieceCount >= parseInt(pieceCountInput.min) && lastPieceCount <= parseInt(pieceCountInput.max)) { + getById("piece-count").value = lastPieceCount; + } function onImageTypeChange() { customImageURL.disabled = customImageRadio.checked ? '' : 'disabled'; } @@ -13,6 +18,7 @@ window.addEventListener('load', function () { hostForm.addEventListener("submit", function () { const formData = new FormData(hostForm); const pieceCount = formData.get('pieces'); + localStorage.setItem('jigsaw.index.pieceCount', pieceCount); const image = formData.get('image') === 'custom' ? formData.get('image-url') : formData.get('image'); const search = new URLSearchParams(); search.set('image', image); diff --git a/server/src/main.rs b/server/src/main.rs index afc87eb..d5c33be 100644 --- a/server/src/main.rs +++ b/server/src/main.rs @@ -1,4 +1,5 @@ #![allow(clippy::too_many_arguments)] +#![allow(clippy::manual_range_contains)] use futures_util::{SinkExt, StreamExt}; use rand::seq::SliceRandom; @@ -318,8 +319,8 @@ async fn handle_websocket( if usize::from(width) * usize::from(height) > MAX_PIECES { return Err(Error::TooManyPieces); } - let nib_count = - 2 * (width as usize) * (height as usize) - (width as usize) - (height as usize); + let nib_count = 2 * usize::from(width) * usize::from(height) + - usize::from(width) - usize::from(height); let mut nib_types: Vec<u16> = Vec::with_capacity(nib_count); let mut piece_positions: Vec<[f32; 2]> = Vec::with_capacity((width as usize) * (height as usize)); @@ -330,21 +331,21 @@ async fn handle_websocket( nib_types.push(rng.gen()); } // pick piece positions - for y in 0..(height as u16) { - for x in 0..(width as u16) { + for y in 0..u16::from(height) { + for x in 0..u16::from(width) { let dx: f32 = rng.gen_range(0.0..0.3); let dy: f32 = rng.gen_range(0.0..0.3); piece_positions.push([ - (x as f32 + dx) / ((width + 1) as f32), - (y as f32 + dy) / ((height + 1) as f32), + (f32::from(x) + dx) / (f32::from(width) + 1.0), + (f32::from(y) + dy) / (f32::from(height) + 1.0), ]); } } piece_positions.shuffle(&mut rng); } let mut connectivity_data: Vec<u16> = - Vec::with_capacity((width as usize) * (height as usize)); - for i in 0..(width as u16) * (height as u16) { + Vec::with_capacity(usize::from(width) * usize::from(height)); + for i in 0..u16::from(width) * u16::from(height) { connectivity_data.push(i); } let mut id; @@ -403,6 +404,11 @@ async fn handle_websocket( .ok_or(Error::BadSyntax)? .parse() .map_err(|_| Error::BadSyntax)?; + for coord in [x, y] { + if !coord.is_finite() || coord < -1.0 || coord > 2.0 { + return Err(Error::BadSyntax); + } + } server.move_piece(puzzle_id, piece, x, y).await?; } ws.send(Message::Text("ack".to_string())).await?; |