chiark / gitweb /
angles: Make not be insane
authorIan Jackson <ijackson@chiark.greenend.org.uk>
Sun, 22 May 2022 11:02:57 +0000 (12:02 +0100)
committerIan Jackson <ijackson@chiark.greenend.org.uk>
Sun, 22 May 2022 11:02:57 +0000 (12:02 +0100)
Signed-off-by: Ian Jackson <ijackson@chiark.greenend.org.uk>
daemon/cmdlistener.rs
docs/bundles.rst
docs/gamespec.rst
specs/demo.game.toml
src/imports.rs
src/spec.rs

index fd853d1a66856cd7b03b404e08ea86b63c58894a..c30840ac142060ae94a810566667f790df2bd062 100644 (file)
@@ -1049,6 +1049,7 @@ fn execute_game_insn<'cs, 'igr, 'ig: 'igr>(
         .try_into().map_err(
           |_| SpE::InternalError(format!("implicit item count out of range"))
         )?;
+      let angle = angle.resolve()?;
       let count: Box<dyn ExactSizeIterator<Item=u32>> = match count {
         Some(explicit) if implicit == 1 => {
           Box::new((0..explicit).map(|_| 0))
index dafe41aa38216351ae2dfc004ed0c62ffe7a7760..396ceb27563253d97b250b5faf4c2e2c18fdb30c 100644 (file)
@@ -179,6 +179,8 @@ follow the link to the latest published documentation for that format.
       of library pieces overhauled.  ``size`` is now the in-game
       size, and the SVG size is obtained from the SVG.
       Library catalogues must be overhauled.
+    - Handling of the ``angle`` parameter in game specs is now
+      much more sensible, and also accurately documented.
 
   * - ``1``
     - 0.x - `1.0.0 <https://www.chiark.greenend.org.uk/~ianmdlvl/otter/1.0.0/docs/README.html>`_
index 34f047dad390923aa3af573bc47e275907b913f9..d1f13bdc0f11f0bb75922d0f2807d5191b9f7ea5 100644 (file)
@@ -109,10 +109,9 @@ These apply regardless of the value of ``type``.
    pin and unpin pieces during the game; this is the initial state.
    [boolean]
 
- * ``angle``: Initial orientation of the piece.  The
-   specified value is multiplied by 45 degrees, increasing values
-   rotating anticlockwise.  So for example ``6`` would mean to rotate
-   90 degrees clockwise.  [integer 0..7]
+ * ``angle``: Initial orientation of the piece.  Only 45-degree
+   angles are supported.
+   [number, degrees, clockwise; or string, "N", "NE" etc.]
 
 
 Common parameters
index 739497e1410d4717be181c6d9bfd236f6b9e7e69..8956302d4272a11b7f0f5a4d86c3e8af44c358df 100644 (file)
@@ -16,7 +16,7 @@ edges = ["black","white"]
 pos = [90, 20]
 type = "Rect"
 size = [10]
-angle.Compass = 1
+angle = "SW"
 faces = ["blue", "grey"]
 
 [[pieces]]
@@ -28,7 +28,7 @@ item = "chess-w-B"
 [[pieces]]
 pos = [160,40]
 type = "Lib"
-angle.Compass = 1
+angle = "NE"
 lib = "wikimedia"
 item = "chess-b-N"
 
@@ -36,7 +36,7 @@ item = "chess-b-N"
 pos = [120, 30]
 type = "Rect"
 size = [10]
-angle.Compass = 1
+angle = 45
 faces = [ ]
 edges = ["yellow", "orange"]
 edge_width = 0.5
index 0a3dfc0bd40665e6a39c338fddd8570be9a80317..10baa4409474e812d7228b4df71efac13c648d2f 100644 (file)
@@ -103,7 +103,7 @@ pub use crate::shapelib;
 pub use crate::shapelib::{ItemEnquiryData, LibraryEnquiryData};
 pub use crate::shapelib::{LibraryLoadError};
 pub use crate::spec::*;
-pub use crate::spec::imp::ColourSpecExt as _;
+pub use crate::spec::imp::{ColourSpecExt as _, OptionPieceAngleSpecExt as _};
 pub use crate::spec::piece_specs::{FaceColourSpecs, SimpleCommon};
 pub use crate::updates::*;
 pub use crate::utils::*;
index 7634c5cdeec06de43af4bd0c17f04c3135002c3b..7ba438cc957ca96a323ea98bbc00fbafe2aade1d 100644 (file)
@@ -225,11 +225,18 @@ pub struct PiecesSpec {
   pub count: Option<u32>,
   pub face: Option<FaceId>,
   pub pinned: Option<bool>,
-  #[serde(default)] pub angle: PieceAngle,
+  #[serde(default)] pub angle: Option<PieceAngleSpec>,
   #[serde(flatten)]
   pub info: Box<dyn PieceSpec>,
 }
 
+#[derive(Debug,Clone,Serialize,Deserialize)]
+#[serde(untagged)]
+pub enum PieceAngleSpec {
+  Compass(String),
+  Degrees(i32),
+}
+
 #[derive(Debug,Copy,Clone,Serialize,Deserialize)]
 pub enum PieceAngle {
   Compass(CompassAngle),
@@ -653,6 +660,30 @@ pub mod imp {
     }
   }
 
+  #[ext(pub)]
+  impl Option<PieceAngleSpec> {
+    #[throws(SpecError)]
+    fn resolve(&self) -> PieceAngle {
+      use PieceAngleSpec as PAS;
+      let i = match self {
+        None => return default(),
+        Some(PAS::Compass(s)) => {
+          let (i,_) = [
+            "N" , "NE", "E" , "SE", "S" , "SW", "W" , "NW",
+          ].iter().enumerate().find(|(_i,&exp)| s == exp)
+            .ok_or_else(|| SpE::CompassAngleInvalid)?;
+          i as u8
+        },
+        Some(PAS::Degrees(deg)) => {
+          let deg = deg.rem_euclid(360);
+          if deg % 45 != 0 { throw!(SpE::CompassAngleInvalid) }
+          (deg / 45) as u8
+        },
+      };
+      PieceAngle::Compass(i.try_into()?)
+    }
+  }
+
   impl UrlSpec {
     const MAX_LEN: usize = 200;
   }