Difference between revisions of "W3911 Sudoku Server"

From Coder Merlin
m (Editorial review and minor corrections)
 
(3 intermediate revisions by 2 users not shown)
Line 1: Line 1:
== Getting Started ==
See [[Vapor]]


== Background ==
== Background ==
A Sudoku board is made up of nine boxes.
A Sudoku board is made up of nine boxes.
Boxes (container for nine cells) are listed from top-to-bottom, left-to-right indexed from zero.
The boxes (containers for nine cells) are listed from top to bottom, left to right, and indexed from zero.
Cells are listed from top-to-bottom, left-to-right, indexed from zero.
Cells are listed from top to bottom, left to right, and indexed from zero.
All valid payloads and responses must use well-formed JSON.   
All valid payloads and responses must use well-formed JSON.   
“cells” is returned as follows:
The value of “cells” is returned as follows:
“cells”: [[<nine values from top-left>], [<nine values from top-middle>], …]
“cells”: [[<nine values from top-left>], [<nine values from top-middle>], …]


Line 97: Line 100:
{{CodeExplorer
{{CodeExplorer
|exerciseID=1
|exerciseID=1
|mode=swift
|language=swift
|height=400
|height=400
|initialCode=import Foundation
|initialCode=import Foundation
Line 148: Line 151:
{{CodeExplorer
{{CodeExplorer
|exerciseID=2
|exerciseID=2
|mode=swift
|language=swift
|height=400
|height=400
|initialCode=import Foundation
|initialCode=import Foundation
Line 234: Line 237:
{{CodeExplorer
{{CodeExplorer
|exerciseID=3
|exerciseID=3
|mode=swift
|language=swift
|height=400
|height=400
|initialCode=import Foundation                                                                                                                                                                                                                           
|initialCode=import Foundation                                                                                                                                                                                                                           
Line 307: Line 310:
   return Response(status: .noContent)
   return Response(status: .noContent)
</syntaxhighlight>
</syntaxhighlight>
== Conversion to Dynamic Library ==
* In a directory ''parallel'' to the root of your project, execute:
<syntaxhighlight lang="bash">
  git clone https://github.com/TheCoderMerlin/VaporShell
</syntaxhighlight>
* Enter your project's ''root directory''
* Execute the following:
<syntaxhighlight lang="bash">
  cp ../VaporShell/make.sh .
  cp ../VaporShell/Package.swift .
  cp ../VaporShell/dylib.manifest .
  cp -r ../VaporShell/Sources/CBase32 Sources/
  cp -r ../VaporShell/Sources/CBcrypt Sources/
  mkdir Sources/VaporShell
  mv Sources/App Sources/VaporShell/
  mv Sources/Run Sources/VaporShell/
  swift package clean
  rm .build -rf
</syntaxhighlight>
* Remove the line "import App" from Sources/VaporShell/Run/main.swift
* Execute "dylibEmacs"

Latest revision as of 08:59, 11 February 2023

Within these castle walls be forged Mavens of Computer Science ...
— Merlin, The Coder

Getting Started[edit]

See Vapor

Background[edit]

A Sudoku board is made up of nine boxes. The boxes (containers for nine cells) are listed from top to bottom, left to right, and indexed from zero. Cells are listed from top to bottom, left to right, and indexed from zero. All valid payloads and responses must use well-formed JSON. The value of “cells” is returned as follows: “cells”: [[<nine values from top-left>], [<nine values from top-middle>], …]

End Points[edit]

POST /games?difficulty=<difficulty>
Creates a new game and associated board
   Parameters: 
   difficulty: easy | medium | hard | hell
   Body: none
   Status code: 201 Created
   Response: ID (integer) of newly created game
   {"id":<id>}
   
{"id": 728134}
   Errors:
   
400 Bad Request (difficulty specified doesn't match requirements)



GET /games/<id>/cells?filter=<filter>
Returns the current cells for the specified game
   Parameters: 
   filter: all | repeated | incorrect
   Body: none
   Status code: 200 OK
   Response: {"board":
   [{"cells":[{"position":{"boxIndex":<boxIndex>,"cellIndex":<cellIndex>},"value":<value>}...
   
{"board": [{"cells":[{"position":{"boxIndex":0,"cellIndex":0},"value":0},{"position":{"boxIndex":0,"cellIndex":1},"value":1}, {"position":{"boxIndex":0,"cellIndex":2},"value":2},{"position":{"boxIndex":0,"cellIndex":3},"value":3}, {"position":{"boxIndex":0,"cellIndex":4},"value":4},{"position":{"boxIndex":0,"cellIndex":5},"value":5}, {"position":{"boxIndex":0,"cellIndex":6},"value":6},{"position":{"boxIndex":0,"cellIndex":7},"value":7}, {"position":{"boxIndex":0,"cellIndex":8},"value":8}]}, {"cells":[{"position":{"boxIndex":1,"cellIndex":0},"value":0},{"position":{"boxIndex":1,"cellIndex":1},"value":1}, {"position":{"boxIndex":1,"cellIndex":2},"value":2},{"position":{"boxIndex":1,"cellIndex":3},"value":3}, {"position":{"boxIndex":1,"cellIndex":4},"value":4},{"position":{"boxIndex":1,"cellIndex":5},"value":5}, {"position":{"boxIndex":1,"cellIndex":6},"value":6},{"position":{"boxIndex":1,"cellIndex":7},"value":7}, {"position":{"boxIndex":1,"cellIndex":8},"value":8}]}, {"cells":[{"position":{"boxIndex":1,"cellIndex":0},"value":0},{"position":{"boxIndex":1,"cellIndex":1},"value":1}, {"position":{"boxIndex":1,"cellIndex":2},"value":2},{"position":{"boxIndex":1,"cellIndex":3},"value":3}, {"position":{"boxIndex":1,"cellIndex":4},"value":4},{"position":{"boxIndex":1,"cellIndex":5},"value":5}, {"position":{"boxIndex":1,"cellIndex":6},"value":6},{"position":{"boxIndex":1,"cellIndex":7},"value":7}, {"position":{"boxIndex":1,"cellIndex":8},"value":8}]}, {"cells":[{"position":{"boxIndex":1,"cellIndex":0},"value":0},{"position":{"boxIndex":1,"cellIndex":1},"value":1}, {"position":{"boxIndex":1,"cellIndex":2},"value":2},{"position":{"boxIndex":1,"cellIndex":3},"value":3}, {"position":{"boxIndex":1,"cellIndex":4},"value":4},{"position":{"boxIndex":1,"cellIndex":5},"value":5}, {"position":{"boxIndex":1,"cellIndex":6},"value":6},{"position":{"boxIndex":1,"cellIndex":7},"value":7}, {"position":{"boxIndex":1,"cellIndex":8},"value":8}]}, {"cells":[{"position":{"boxIndex":1,"cellIndex":0},"value":0},{"position":{"boxIndex":1,"cellIndex":1},"value":1}, {"position":{"boxIndex":1,"cellIndex":2},"value":2},{"position":{"boxIndex":1,"cellIndex":3},"value":3}, {"position":{"boxIndex":1,"cellIndex":4},"value":4},{"position":{"boxIndex":1,"cellIndex":5},"value":5}, {"position":{"boxIndex":1,"cellIndex":6},"value":6},{"position":{"boxIndex":1,"cellIndex":7},"value":7}, {"position":{"boxIndex":1,"cellIndex":8},"value":8}]}, {"cells":[{"position":{"boxIndex":1,"cellIndex":0},"value":0},{"position":{"boxIndex":1,"cellIndex":1},"value":1}, {"position":{"boxIndex":1,"cellIndex":2},"value":2},{"position":{"boxIndex":1,"cellIndex":3},"value":3}, {"position":{"boxIndex":1,"cellIndex":4},"value":4},{"position":{"boxIndex":1,"cellIndex":5},"value":5}, {"position":{"boxIndex":1,"cellIndex":6},"value":6},{"position":{"boxIndex":1,"cellIndex":7},"value":7}, {"position":{"boxIndex":1,"cellIndex":8},"value":8}]}, {"cells":[{"position":{"boxIndex":1,"cellIndex":0},"value":0},{"position":{"boxIndex":1,"cellIndex":1},"value":1}, {"position":{"boxIndex":1,"cellIndex":2},"value":2},{"position":{"boxIndex":1,"cellIndex":3},"value":3}, {"position":{"boxIndex":1,"cellIndex":4},"value":4},{"position":{"boxIndex":1,"cellIndex":5},"value":5}, {"position":{"boxIndex":1,"cellIndex":6},"value":6},{"position":{"boxIndex":1,"cellIndex":7},"value":7}, {"position":{"boxIndex":1,"cellIndex":8},"value":8}]}, {"cells":[{"position":{"boxIndex":1,"cellIndex":0},"value":0},{"position":{"boxIndex":1,"cellIndex":1},"value":1}, {"position":{"boxIndex":1,"cellIndex":2},"value":2},{"position":{"boxIndex":1,"cellIndex":3},"value":3}, {"position":{"boxIndex":1,"cellIndex":4},"value":4},{"position":{"boxIndex":1,"cellIndex":5},"value":5}, {"position":{"boxIndex":1,"cellIndex":6},"value":6},{"position":{"boxIndex":1,"cellIndex":7},"value":7}, {"position":{"boxIndex":1,"cellIndex":8},"value":8}]}, {"cells":[{"position":{"boxIndex":1,"cellIndex":0},"value":0},{"position":{"boxIndex":1,"cellIndex":1},"value":1}, {"position":{"boxIndex":1,"cellIndex":2},"value":2},{"position":{"boxIndex":1,"cellIndex":3},"value":3}, {"position":{"boxIndex":1,"cellIndex":4},"value":4},{"position":{"boxIndex":1,"cellIndex":5},"value":5}, {"position":{"boxIndex":1,"cellIndex":6},"value":6},{"position":{"boxIndex":1,"cellIndex":7},"value":7}, {"position":{"boxIndex":1,"cellIndex":8},"value":8}]} ]}
   Errors:
   
400 Bad Request (filter specified doesn't match requirements)



PUT /games/<id>/cells/<boxIndex>/<cellIndex>
Place specified value at in game at boxIndex, cellIndex
   Parameters: 
   none
   Body: {"value":<value>}
   Status code: 200 OK
   Response: none
   
none
   Errors:
   
400 Bad Request (boxIndex is out of range 0 ... 8) 400 Bad Request (cellIndex is out of range 0 ... 8) 400 Bad Request (value is out of range 1 ... 9 or null)


JSON Encoding[edit]

CoderMerlin™ Code Explorer: W0000 (1) 🟢


JSON Decoding[edit]

CoderMerlin™ Code Explorer: W0000 (2) 🟢


Issue Request from Client to Server[edit]

CoderMerlin™ Code Explorer: W0000 (3) 🟢


Server-side Query String Access[edit]

  let difficulty: String? = request.query["difficulty"]

Server-side Content Access for JSON[edit]

  app.put("value") { req -> String in
      struct CellValue: Decodable {
          let value: Int?
      }
      let cellValue = try req.content.decode(CellValue.self)
      return "Done"
  }

Server-side Parameter Access and Error Handling[edit]

    guard let boxIndex = req.parameters.get("boxIndex", as: Int.self),
        let cellIndex = req.parameters.get("cellIndex", as: Int.self) else {
        throw Abort(.badRequest, reason: "boxIndex and cellIndex MUST be integers")
    }

Server-side Returning "No Content"[edit]

  return Response(status: .noContent)