type Token = 'U'|'D'|'L'|'R'|'F'|'B'|'M'|'E'|'S'|'x'|'y'|'z';
type Move = { token: Token; turn: 1 | 2 | 3 };
type Result = { ok: true; moves: Move[] } | { ok: false; error: string };
const TOKENS = new Set('UDLRFBMESxyz'); // 12 valid first chars
export function parse(s: string): Result {
const moves: Move[] = [];
for (const t of s.split(/\s+/).filter(Boolean)) {
const head = t[0];
if (!TOKENS.has(head)) return { ok: false, error: `bad token: ${t}` };
const tail = t.slice(1);
const turn = tail === '' ? 1
: tail === '2' ? 2
: tail === "'" ? 3
: 0;
if (!turn) return { ok: false, error: `bad suffix: ${t}` };
moves.push({ token: head as Token, turn: turn as 1 | 2 | 3 });
}
return { ok: true, moves };
}
String literal union + discriminated Result #[derive(Debug, Clone, Copy)]
pub enum Token { U, D, L, R, F, B, M, E, S, X, Y, Z }
pub struct Move { pub token: Token, pub turn: u8 }
pub fn parse(s: &str) -> Result<Vec<Move>, String> {
s.split_whitespace().map(|t| {
let mut c = t.chars();
let token = match c.next() {
Some('U') => Token::U, Some('D') => Token::D,
Some('L') => Token::L, Some('R') => Token::R,
Some('F') => Token::F, Some('B') => Token::B,
Some('M') => Token::M, Some('E') => Token::E,
Some('S') => Token::S, Some('x') => Token::X,
Some('y') => Token::Y, Some('z') => Token::Z,
_ => return Err(format!("bad token: {t}")),
};
let turn = match c.as_str() {
"" => 1, "2" => 2, "'" => 3,
_ => return Err(format!("bad suffix: {t}")),
};
Ok(Move { token, turn })
}).collect()
}
enum + Result + exhaustive match package scramble
import (
"fmt"
"strings"
)
type Move struct {
Token byte
Turn int
}
const valid = "UDLRFBMESxyz"
func Parse(s string) ([]Move, error) {
var out []Move
for _, t := range strings.Fields(s) { // skips empty tokens
if !strings.ContainsRune(valid, rune(t[0])) {
return nil, fmt.Errorf("bad token: %q", t)
}
var turn int
switch t[1:] {
case "": turn = 1
case "2": turn = 2
case "'": turn = 3
default:
return nil, fmt.Errorf("bad suffix: %q", t)
}
out = append(out, Move{t[0], turn})
}
return out, nil
}
(value, error) + strings.Fields from dataclasses import dataclass
VALID = set("UDLRFBMESxyz") # 12 first chars
@dataclass
class Move:
token: str
turn: int # 1, 2, or 3
class ScrambleError(ValueError): pass
def parse(s: str) -> list[Move]:
out: list[Move] = []
for t in s.split(): # split() collapses runs of whitespace
if not t or t[0] not in VALID:
raise ScrambleError(f"bad token: {t!r}")
match t[1:]:
case "": turn = 1
case "2": turn = 2
case "'": turn = 3
case _: raise ScrambleError(f"bad suffix: {t!r}")
out.append(Move(t[0], turn))
return out
dataclass + match/case with guards #include <string.h>
#include <ctype.h>
typedef struct { char token; int turn; } Move;
// returns 0 on success, -1 on error; writes count to *n_out.
int parse(const char *s, Move *out, int cap, int *n_out) {
int n = 0;
while (*s) {
while (isspace((unsigned char)*s)) s++;
if (!*s) break;
if (n >= cap || !strchr("UDLRFBMESxyz", *s)) return -1;
char head = *s++;
int turn;
if (*s == '\0' || isspace((unsigned char)*s)) turn = 1;
else if (*s == '2') { turn = 2; s++; }
else if (*s == '\'') { turn = 3; s++; }
else return -1;
if (*s && !isspace((unsigned char)*s)) return -1;
out[n++] = (Move){ head, turn };
}
*n_out = n;
return 0;
}
Out param + int error code #include <expected>
#include <string>
#include <vector>
#include <sstream>
enum class Token : char {
U='U', D='D', L='L', R='R', F='F', B='B',
M='M', E='E', S='S', x='x', y='y', z='z',
};
struct Move { Token token; int turn; };
std::expected<std::vector<Move>, std::string> parse(std::string_view s) {
std::vector<Move> out;
std::istringstream in{std::string{s}};
for (std::string t; in >> t; ) {
if (std::string_view{"UDLRFBMESxyz"}.find(t[0]) == std::string_view::npos)
return std::unexpected("bad token: " + t);
int turn = t.size() == 1 ? 1
: t == std::string{t[0]} + "2" ? 2
: t == std::string{t[0]} + "'" ? 3 : 0;
if (!turn) return std::unexpected("bad suffix: " + t);
out.push_back({static_cast<Token>(t[0]), turn});
}
return out;
}
enum class + std::expected (C++23) const std = @import("std");
pub const Move = struct { token: u8, turn: u8 };
pub const ParseError = error{ BadToken, BadSuffix };
pub fn parse(alloc: std.mem.Allocator, s: []const u8) ![]Move {
var out = std.ArrayList(Move).init(alloc);
errdefer out.deinit();
var it = std.mem.tokenizeAny(u8, s, " \t\n");
while (it.next()) |t| {
if (std.mem.indexOfScalar(u8, "UDLRFBMESxyz", t[0]) == null)
return ParseError.BadToken;
const turn: u8 = switch (t.len) {
1 => 1,
2 => switch (t[1]) {
'2' => 2,
'\'' => 3,
else => return ParseError.BadSuffix,
},
else => return ParseError.BadSuffix,
};
try out.append(.{ .token = t[0], .turn = turn });
}
return out.toOwnedSlice();
}
error{} set + !T error union enum Token: Character {
case U, D, L, R, F, B, M, E, S
case x, y, z
}
struct Move { let token: Token; let turn: Int }
enum ScrambleError: Error { case badToken(String), badSuffix(String) }
func parse(_ s: String) throws -> [Move] {
try s.split(whereSeparator: \.isWhitespace).map { piece -> Move in
let t = String(piece)
guard let token = Token(rawValue: t.first!) else {
throw ScrambleError.badToken(t)
}
let turn: Int
switch t.dropFirst() {
case "": turn = 1
case "2": turn = 2
case "'": turn = 3
default: throw ScrambleError.badSuffix(t)
}
return Move(token: token, turn: turn)
}
}
enum + throws + raw-value init enum class Token { U, D, L, R, F, B, M, E, S, x, y, z }
data class Move(val token: Token, val turn: Int)
fun parse(s: String): Result<List<Move>> = runCatching {
s.split(Regex("\\s+")).filter { it.isNotEmpty() }.map { t ->
val token = runCatching { Token.valueOf(t[0].toString()) }
.getOrElse { throw IllegalArgumentException("bad token: $t") }
val turn = when (t.drop(1)) {
"" -> 1
"2" -> 2
"'" -> 3
else -> throw IllegalArgumentException("bad suffix: $t")
}
Move(token, turn)
}
}
sealed class + Result + when import java.util.*;
public class Scramble {
public enum Token { U, D, L, R, F, B, M, E, S, x, y, z }
public record Move(Token token, int turn) {}
public static class ScrambleException extends Exception {
public ScrambleException(String m) { super(m); }
}
public static List<Move> parse(String s) throws ScrambleException {
List<Move> out = new ArrayList<>();
for (String t : s.trim().split("\\s+")) {
if (t.isEmpty()) continue;
Token token;
try { token = Token.valueOf(String.valueOf(t.charAt(0))); }
catch (IllegalArgumentException e) {
throw new ScrambleException("bad token: " + t);
}
int turn = switch (t.substring(1)) {
case "" -> 1;
case "2" -> 2;
case "'" -> 3;
default -> throw new ScrambleException("bad suffix: " + t);
};
out.add(new Move(token, turn));
}
return out;
}
}
enum + record + checked exception // no Token enum, no Move type — just objects and strings.
// every guard here is a runtime check the type system can't see.
const VALID = new Set([...'UDLRFBMESxyz']);
export function parse(s) {
return s.split(/\s+/).filter(Boolean).map((t) => {
if (!VALID.has(t[0])) {
throw new Error(`bad token: ${t}`);
}
const tail = t.slice(1);
const turn = tail === '' ? 1
: tail === '2' ? 2
: tail === "'" ? 3
: null;
if (turn === null) throw new Error(`bad suffix: ${t}`);
return { token: t[0], turn };
});
}
No types + throw; runtime checks only # Mojo: @value auto-derives copy/init/del.
# fn = strict types; Optional[List[Move]] for parse failure.
# No native enum yet — String holds the token char.
@value
struct Move:
var token: String
var turn: Int
fn parse(s: String) -> Optional[List[Move]]:
alias VALID = "UDLRFBMESxyz"
var out = List[Move]()
for t in s.split():
if len(t) == 0: continue
var head = String(t[0])
if VALID.find(head) < 0: return None
var rest = String(t[1:])
var turn: Int
if rest == "": turn = 1
elif rest == "2": turn = 2
elif rest == "'": turn = 3
else: return None
out.append(Move(head, turn))
return out
@value struct + Optional[List[Move]] using System;
using System.Collections.Generic;
public enum Token { U, D, L, R, F, B, M, E, S, x, y, z }
public record Move(Token Token, int Turn);
public static class Scramble
{
public static List<Move> Parse(string s)
{
var moves = new List<Move>();
foreach (var t in s.Split(default(char[]),
StringSplitOptions.RemoveEmptyEntries))
{
if (!Enum.TryParse<Token>(t[..1], out var token))
throw new FormatException($"bad token: {t}");
int turn = t[1..] switch
{
"" => 1,
"2" => 2,
"'" => 3,
_ => throw new FormatException($"bad suffix: {t}"),
};
moves.Add(new Move(token, turn));
}
return moves;
}
}
record + enum + switch expression require 'set'
VALID = Set.new("UDLRFBMESxyz".chars)
Move = Struct.new(:token, :turn)
class ScrambleError < StandardError; end
def parse(s)
s.split.map do |t|
raise ScrambleError, "bad token: #{t}" unless VALID.include?(t[0])
turn = case t[1..]
when '' then 1
when '2' then 2
when "'" then 3
else raise ScrambleError, "bad suffix: #{t}"
end
Move.new(t[0], turn)
end
end
Duck-typed + Struct + case/when <?php
enum Token: string {
case U = 'U'; case D = 'D'; case L = 'L'; case R = 'R';
case F = 'F'; case B = 'B'; case M = 'M'; case E = 'E';
case S = 'S'; case X = 'x'; case Y = 'y'; case Z = 'z';
}
readonly class Move {
public function __construct(public Token $token, public int $turn) {}
}
function parse(string $s): array {
$out = [];
foreach (preg_split('/\\s+/', trim($s)) as $t) {
if ($t === '') continue;
$token = Token::tryFrom($t[0]);
if (!$token) throw new ValueError("bad token: $t");
$turn = match (substr($t, 1)) {
'' => 1,
'2' => 2,
"'" => 3,
default => throw new ValueError("bad suffix: $t"),
};
$out[] = new Move($token, $turn);
}
return $out;
}
PHP 8.1 enum + match expression -- Lua: no enum, no Result type. Idiom: return value, err.
local VALID = {}
for c in ("UDLRFBMESxyz"):gmatch(".") do VALID[c] = true end
local function parse(s)
local out = {}
for t in s:gmatch("%S+") do
local head = t:sub(1, 1)
if not VALID[head] then
return nil, "bad token: " .. t
end
local tail = t:sub(2)
local turn
if tail == "" then turn = 1
elseif tail == "2" then turn = 2
elseif tail == "'" then turn = 3
else
return nil, "bad suffix: " .. t
end
out[#out + 1] = { token = head, turn = turn }
end
return out
end
Multi-return (value, err) + gmatch %S+ -- Haskell: ADT for Token, Either for failure. mapM threads errors.
data Token = U | D | L | R | F | B
| M | E | S | X | Y | Z
deriving (Show, Eq)
data Move = Move { token :: Token, turn :: Int } deriving Show
parse :: String -> Either String [Move]
parse = mapM parseOne . words
where
parseOne [] = Left "empty token"
parseOne (h:rs) = Move <$> tokenOf h <*> turnOf rs
tokenOf c = case c of
'U' -> Right U; 'D' -> Right D; 'L' -> Right L; 'R' -> Right R
'F' -> Right F; 'B' -> Right B; 'M' -> Right M; 'E' -> Right E
'S' -> Right S; 'x' -> Right X; 'y' -> Right Y; 'z' -> Right Z
_ -> Left ("bad token: " ++ [c])
turnOf "" = Right 1
turnOf "2" = Right 2
turnOf "'" = Right 3
turnOf r = Left ("bad suffix: " ++ r)
ADT (Token / Move) + Either String