Faces from a mesh: Difference between revisions

m
→‎{{header|Wren}}: Changed to Wren S/H
(Promote to full task status.)
m (→‎{{header|Wren}}: Changed to Wren S/H)
 
(17 intermediate revisions by 11 users not shown)
Line 61:
 
;Task:
'''1.''' Write a routine to check if two perimeter formatted faces have the same perimeter. use Use it oto check if the following pairs of perimeters are the same:
<pre> Q: (8, 1, 3)
R: (1, 3, 8)
Line 77:
Show your output here.
 
=={{header|11l}}==
{{trans|Python}}
 
<syntaxhighlight lang="11l">F perim_equal(p1, =p2)
I p1.len != p2.len | Set(p1) != Set(p2)
R 0B
I any((0 .< p1.len).map(n -> @p2 == (@p1[n ..] [+] @p1[0 .< n])))
R 1B
p2 = reversed(p2)
R any((0 .< p1.len).map(n -> @p2 == (@p1[n ..] [+] @p1[0 .< n])))
 
F edge_to_periphery(e)
V edges = sorted(e)
[Int] p
I !edges.empty
p = [edges[0][0], edges[0][1]]
edges.pop(0)
V last = I !p.empty {p.last} E -1
L !edges.empty
L(ij) edges
V (i, j) = ij
I i == last
p.append(j)
last = j
edges.pop(L.index)
L.break
E I j == last
p.append(i)
last = i
edges.pop(L.index)
L.break
L.was_no_break
R ‘>>>Error! Invalid edge format<<<’
R String(p[0 .< (len)-1])
 
print(‘Perimeter format equality checks:’)
L(eq_check) [(‘Q’, [8, 1, 3],
‘R’, [1, 3, 8]),
(‘U’, [18, 8, 14, 10, 12, 17, 19],
‘V’, [8, 14, 10, 12, 17, 19, 18])]
V (n1, p1, n2, p2) = eq_check
V eq = I perim_equal(p1, p2) {‘==’} E ‘!=’
print(‘ ’n1‘ ’eq‘ ’n2)
 
print("\nEdge to perimeter format translations:")
V edge_d = [‘E’ = [(1, 11), (7, 11), (1, 7)],
‘F’ = [(11, 23), (1, 17), (17, 23), (1, 11)],
‘G’ = [(8, 14), (17, 19), (10, 12), (10, 14), (12, 17), (8, 18), (18, 19)],
‘H’ = [(1, 3), (9, 11), (3, 11), (1, 11)]]
L(name, edges) edge_d
print(‘ ’name‘: ’edges"\n -> "edge_to_periphery(edges))</syntaxhighlight>
 
{{out}}
<pre>
Perimeter format equality checks:
Q == R
U == V
 
Edge to perimeter format translations:
E: [(1, 11), (7, 11), (1, 7)]
-> [1, 7, 11]
F: [(11, 23), (1, 17), (17, 23), (1, 11)]
-> [1, 11, 23, 17]
G: [(8, 14), (17, 19), (10, 12), (10, 14), (12, 17), (8, 18), (18, 19)]
-> [8, 14, 10, 12, 17, 19, 18]
H: [(1, 3), (9, 11), (3, 11), (1, 11)]
-> >>>Error! Invalid edge format<<<
</pre>
 
=={{header|C++}}==
<syntaxhighlight lang="c++">
 
#include <iostream>
#include <vector>
#include <algorithm>
#include <string>
 
typedef std::pair<int32_t, int32_t> Edge;
 
std::string to_string(const int32_t& value) {
return std::to_string(value);
}
 
std::string to_string(const Edge& edge) {
return "(" + std::to_string(edge.first) + ", " + std::to_string(edge.second) + ")";
}
 
template <typename T>
std::string vector_to_string(const std::vector<T>& list) {
std::string result = "[";
for ( uint64_t i = 0; i < list.size() - 1; ++i ) {
result += to_string(list[i]) + ", ";
}
result += to_string(list.back()) + "]";
return result;
}
 
bool is_same_face(const std::vector<int32_t>& list_1, const std::vector<int32_t>& list_2) {
if ( list_1.size() != list_2.size() || list_1.empty() ) {
return false;
}
 
std::vector<int32_t> copy_2(list_2);
for ( int32_t i = 0; i < 2; ++i ) {
int32_t start;
if ( auto iterator = std::find(copy_2.begin(), copy_2.end(), list_1.front()); iterator != copy_2.end() ) {
start = std::distance(copy_2.begin(), iterator);
} else {
return false;
}
std::vector<int32_t> test(copy_2.begin() + start, copy_2.end());
test.insert(test.end(), copy_2.begin(), copy_2.begin() + start);//addAll(copyTwo.subList(0, start));
if ( list_1 == test ) {
return true;
}
std::reverse(copy_2.begin(), copy_2.end());
}
 
return false;
}
 
std::vector<int32_t> to_perimeter_format_face(const std::vector<Edge>& edge_format_face) {
if ( edge_format_face.empty() ) {
return std::vector<int32_t>();
}
 
std::vector<Edge> edges(edge_format_face);
std::vector<int32_t> result;
Edge first_edge = edges.front();
edges.erase(edges.begin());
int next_vertex = first_edge.first;
result.push_back(next_vertex);
 
while ( ! edges.empty() ) {
int32_t index = -1;
for ( Edge edge : edges ) {
if ( edge.first == next_vertex || edge.second == next_vertex ) {
if ( auto iterator = std::find(edges.begin(), edges.end(), edge); iterator != edges.end() ) {
index = std::distance(edges.begin(), iterator);
}
next_vertex = ( next_vertex == edge.first ) ? edge.second : edge.first;
break;
}
}
if ( index == -1 ) {
return std::vector<int32_t>();
}
result.push_back(next_vertex);
edges.erase(edges.begin() + index);
}
 
if ( next_vertex != first_edge.second ) {
return std::vector<int32_t>();
}
return result;
}
 
int main() {
const std::vector<int32_t> perimeter_format_q = { 8, 1, 3 };
const std::vector<int32_t> perimeter_format_r = { 1, 3, 8 };
const std::vector<int32_t> perimeter_format_u = { 18, 8, 14, 10, 12, 17, 19 };
const std::vector<int32_t> perimeter_format_v = { 8, 14, 10, 12, 17, 19, 18 };
 
const std::vector<Edge> edge_format_e = { Edge(1, 11), Edge(7, 11), Edge(1, 7) };
const std::vector<Edge> edge_format_f = { Edge(11, 23), Edge(1, 17), Edge(17, 23), Edge(1, 11) };
const std::vector<Edge> edge_format_g =
{ Edge(8, 14), Edge(17, 19), Edge(10, 12), Edge(10, 14), Edge(12, 17), Edge(8, 18), Edge(18, 19) };
const std::vector<Edge> edge_format_h = { Edge(1, 3), Edge(9, 11), Edge(3, 11), Edge(1, 11) };
 
std::cout << "PerimeterFormat equality checks:" << std::endl;
bool same_face = is_same_face(perimeter_format_q, perimeter_format_r);
std::cout << vector_to_string(perimeter_format_q) << " == "
<< vector_to_string(perimeter_format_r) << ": " << std::boolalpha << same_face << std::endl;
same_face = is_same_face(perimeter_format_u, perimeter_format_v);
std::cout << vector_to_string(perimeter_format_u) << " == "
<< vector_to_string(perimeter_format_v) << ": " << std::boolalpha << same_face << std::endl;
 
std::cout << "\nEdgeFormat to PerimeterFormat conversions:" << std::endl;
std::vector<std::vector<Edge>> edge_format_faces = { edge_format_e, edge_format_f, edge_format_g, edge_format_h };
for ( std::vector<Edge> edge_format_face : edge_format_faces ) {
std::vector<int32_t> perimeter_format_face = to_perimeter_format_face(edge_format_face);
if ( perimeter_format_face.empty() ) {
std::cout << vector_to_string(edge_format_face) << " has invalid edge format" << std::endl;
} else {
std::cout << vector_to_string(edge_format_face) << " => "
<< vector_to_string(perimeter_format_face) << std::endl;
}
}
}
</syntaxhighlight>
{{ out }}
<pre>
PerimeterFormat equality checks:
[8, 1, 3] == [1, 3, 8]: true
[18, 8, 14, 10, 12, 17, 19] == [8, 14, 10, 12, 17, 19, 18]: true
 
EdgeFormat to PerimeterFormat conversions:
[(1, 11), (7, 11), (1, 7)] => [1, 7, 11]
[(11, 23), (1, 17), (17, 23), (1, 11)] => [11, 1, 17, 23]
[(8, 14), (17, 19), (10, 12), (10, 14), (12, 17), (8, 18), (18, 19)] => [8, 18, 19, 17, 12, 10, 14]
[(1, 3), (9, 11), (3, 11), (1, 11)] has invalid edge format
</pre>
 
=={{header|Go}}==
<langsyntaxhighlight lang="go">package main
 
import (
Line 223 ⟶ 425:
}
}
}</langsyntaxhighlight>
 
{{out}}
Line 236 ⟶ 438:
G => [8 14 10 12 17 19 18]
H => Invalid edge format
</pre>
 
=={{header|Haskell}}==
<syntaxhighlight lang="haskell">import Data.List (find, delete, (\\))
import Control.Applicative ((<|>))
 
------------------------------------------------------------
 
newtype Perimeter a = Perimeter [a]
deriving Show
 
instance Eq a => Eq (Perimeter a) where
Perimeter p1 == Perimeter p2 =
null (p1 \\ p2)
&& ((p1 `elem` zipWith const (iterate rotate p2) p1)
|| Perimeter p1 == Perimeter (reverse p2))
 
rotate lst = zipWith const (tail (cycle lst)) lst
 
toEdges :: Ord a => Perimeter a -> Maybe (Edges a)
toEdges (Perimeter ps)
| allDifferent ps = Just . Edges $ zipWith ord ps (tail (cycle ps))
| otherwise = Nothing
where
ord a b = if a < b then (a, b) else (b, a)
 
allDifferent [] = True
allDifferent (x:xs) = all (x /=) xs && allDifferent xs
 
------------------------------------------------------------
 
newtype Edges a = Edges [(a, a)]
deriving Show
 
instance Eq a => Eq (Edges a) where
e1 == e2 = toPerimeter e1 == toPerimeter e2
 
toPerimeter :: Eq a => Edges a -> Maybe (Perimeter a)
toPerimeter (Edges ((a, b):es)) = Perimeter . (a :) <$> go b es
where
go x rs
| x == a = return []
| otherwise = do
p <- find ((x ==) . fst) rs <|> find ((x ==) . snd) rs
let next = if fst p == x then snd p else fst p
(x :) <$> go next (delete p rs)</syntaxhighlight>
 
First task.
 
<pre>λ> Perimeter [8,1,3] == Perimeter [1,3,8]
True
 
λ> Perimeter [8,1,3] == Perimeter [1,8,3]
True
 
λ> Perimeter [18,8,14,10,12,17,19] == Perimeter [8,14,10,12,17,19,18]
True
 
λ> Perimeter [18,8,14,10,12,17,19] == Perimeter [8,14,10,12,17,19]
False
 
λ> Perimeter [18,8,14,10,12,17,19] == Perimeter [8,14,10,12,17,18,19]
False</pre>
 
Second task
<pre>λ> toPerimeter (Edges [(1,11),(7,11),(1,7)])
Just (Perimeter [1,11,7])
 
λ> toPerimeter (Edges [(11,23),(1,17),(17,23),(1,11)])
Just (Perimeter [11,23,17,1])
 
λ> toPerimeter (Edges [(8,14),(17,19),(10,12),(10,14),(12,17),(8,18),(18,19)])
Just (Perimeter [8,14,10,12,17,19,18])
 
λ> toPerimeter (Edges [(1,3),(9,11),(3,11),(1,11)])
Nothing</pre>
 
=={{header|J}}==
First task:
<pre>
NB. construct a list of all rotations of one of the faces
NB. including all rotations of the reversed list.
NB. Find out if the other face is a member of this list.
 
NB. ,&:rotations -> append, but first enlist the rotations.
 
 
rotations=. |."0 1~ i.@#
reverse=: |.
same_perimeter=: e. (,&:rotations reverse)
 
(3, 1, 8)same_perimeter(8, 1, 3)
1
 
(18, 8, 14, 10, 12, 17, 19)same_perimeter(8, 14, 10, 12, 17, 19, 18)
1
</pre>
Secondly:
<syntaxhighlight lang="j">
edge_to_node=: 3 :0
assert. 2 = #/.~ , y [ 'expect each node to appear twice'
oel=. 1 2 {. y
Y=. }. y
while. # Y do.
i =. <. -: 1 i.~ , Y (e."1) {: oel
assert. 0 < # i [ 'isolated edge detected'
oel =. oel , i { Y
Y =. i ({. , (}.~ >:)~) Y
end.
~. , oel
)
</syntaxhighlight>
 
<pre>
boxdraw_j_ 0
 
]TESTS=: ([: < _2 ]\ ".);._2'{}'-.~0 :0
{(1, 11), (7, 11), (1, 7)}
{(11, 23), (1, 17), (17, 23), (1, 11)}
{(8, 14), (17, 19), (10, 12), (10, 14), (12, 17), (8, 18), (18, 19)}
{(1, 3), (9, 11), (3, 11), (1, 11)}
)
┌────┬─────┬─────┬────┐
│1 11│11 23│ 8 14│1 3│
│7 11│ 1 17│17 19│9 11│
│1 7│17 23│10 12│3 11│
│ │ 1 11│10 14│1 11│
│ │ │12 17│ │
│ │ │ 8 18│ │
│ │ │18 19│ │
└────┴─────┴─────┴────┘
 
 
 
edge_to_node ::('failure'"_)&.> TESTS
┌──────┬──────────┬───────────────────┬───────┐
│1 11 7│11 23 17 1│8 14 10 12 17 19 18│failure│
└──────┴──────────┴───────────────────┴───────┘
 
 
edge_to_node _1 {:: TESTS
|assertion failure: edge_to_node
| 2=#/.~,y['expect each node to appear twice'
</pre>
 
=={{header|Java}}==
<syntaxhighlight lang="java">
 
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashSet;
import java.util.List;
 
public final class FacesFromMesh {
 
public static void main(String[] aArgs) {
final List<Integer> perimeterFormatQ = Arrays.asList( 8, 1, 3 );
final List<Integer> perimeterFormatR = Arrays.asList( 1, 3, 8 );
final List<Integer> perimeterFormatU = Arrays.asList( 18, 8, 14, 10, 12, 17, 19 );
final List<Integer> perimeterFormatV = Arrays.asList( 8, 14, 10, 12, 17, 19, 18 );
final List<Edge> edgeFormatE = Arrays.asList( new Edge(1, 11), new Edge(7, 11), new Edge(1, 7) );
final List<Edge> edgeFormatF =
Arrays.asList( new Edge(11, 23), new Edge(1, 17), new Edge(17, 23), new Edge(1, 11) );
final List<Edge> edgeFormatG = Arrays.asList( new Edge(8, 14), new Edge(17, 19),
new Edge(10, 12), new Edge(10, 14), new Edge(12, 17), new Edge(8, 18), new Edge(18, 19) );
final List<Edge> edgeFormatH =
Arrays.asList( new Edge(1, 3), new Edge(9, 11), new Edge(3, 11), new Edge(1, 11) );
System.out.println("PerimeterFormat equality checks:");
boolean sameFace = isSameFace(perimeterFormatQ, perimeterFormatR);
System.out.println(perimeterFormatQ + " == " + perimeterFormatR + ": " + sameFace);
sameFace = isSameFace(perimeterFormatU, perimeterFormatV);
System.out.println(perimeterFormatU + " == " + perimeterFormatV + ": " + sameFace);
 
System.out.println(System.lineSeparator() + "EdgeFormat to PerimeterFormat conversions:");
List<List<Edge>> edgeFormatFaces = List.of( edgeFormatE, edgeFormatF, edgeFormatG, edgeFormatH );
for ( List<Edge> edgeFormatFace : edgeFormatFaces ) {
List<Integer> perimeterFormatFace = toPerimeterFormatFace(edgeFormatFace);
if ( perimeterFormatFace.isEmpty() ) {
System.out.println(edgeFormatFace + " has invalid edge format");
} else {
System.out.println(edgeFormatFace + " => " + perimeterFormatFace);
}
}
}
private static boolean isSameFace(List<Integer> aOne, List<Integer> aTwo) {
if ( aOne.size() != aTwo.size() || aOne.isEmpty() ||
! new HashSet<Integer>(aOne).equals( new HashSet<Integer>(aTwo) )) {
return false;
}
 
List<Integer> copyTwo = new ArrayList<Integer>(aTwo);
for ( int i = 0; i < 2; i++ ) {
int start = copyTwo.indexOf(aOne.get(0));
List<Integer> test = new ArrayList<Integer>(copyTwo.subList(start, copyTwo.size()));
test.addAll(copyTwo.subList(0, start));
if ( aOne.equals(test) ) {
return true;
}
Collections.reverse(copyTwo);
}
return false;
}
private static List<Integer> toPerimeterFormatFace(List<Edge> aEdgeFormatFace) {
if ( aEdgeFormatFace.isEmpty() ) {
return Collections.emptyList();
}
List<Edge> edges = new ArrayList<Edge>(aEdgeFormatFace);
List<Integer> result = new ArrayList<Integer>();
Edge firstEdge = edges.remove(0);
int nextVertex = firstEdge.first;
result.add(nextVertex);
while ( ! edges.isEmpty() ) {
int index = -1;
for ( Edge edge : edges ) {
if ( edge.first == nextVertex || edge.second == nextVertex ) {
index = edges.indexOf(edge);
nextVertex = ( nextVertex == edge.first ) ? edge.second : edge.first;
break;
}
}
if ( index == -1 ) {
return Collections.emptyList();
}
result.add(nextVertex);
edges.remove(index);
}
if ( nextVertex != firstEdge.second ) {
return Collections.emptyList();
}
return result;
}
private static class Edge {
public Edge(int aFirst, int aSecond) {
first = aFirst;
second = aSecond;
}
@Override
public String toString() {
return "(" + first + ", " + second + ")";
}
private int first, second;
}
 
}
</syntaxhighlight>
{{ out }}
<pre>
PerimeterFormat equality checks:
[8, 1, 3] == [1, 3, 8]: true
[18, 8, 14, 10, 12, 17, 19] == [8, 14, 10, 12, 17, 19, 18]: true
 
EdgeFormat to PerimeterFormat conversions:
[(1, 11), (7, 11), (1, 7)] => [1, 7, 11]
[(11, 23), (1, 17), (17, 23), (1, 11)] => [11, 1, 17, 23]
[(8, 14), (17, 19), (10, 12), (10, 14), (12, 17), (8, 18), (18, 19)] => [8, 18, 19, 17, 12, 10, 14]
[(1, 3), (9, 11), (3, 11), (1, 11)] has invalid edge format
</pre>
 
=={{header|Julia}}==
<langsyntaxhighlight lang="julia">iseq(f, g) = any(n -> f == circshift(g, n), 1:length(g))
 
function toface(evec)
Line 274 ⟶ 745:
println(toface(face))
end
</langsyntaxhighlight>{{out}}
<pre>
Faces are equivalent.
Line 283 ⟶ 754:
Invalid edges vector: Tuple{Int64,Int64}[(1, 3), (9, 11), (3, 11), (1, 11)]
</pre>
 
=={{header|Koka}}==
<syntaxhighlight lang="koka">
alias perimeter = list<int>
alias face = (char, perimeter)
alias edge = (int, int)
 
fun isSame(p1: perimeter, p2: perimeter, noSwitch: list<int> = []): div bool
match (p1, p2)
([], []) -> True
(Cons(x1, xs1), Cons(x2, xs2)) | x1 == x2 -> isSame(xs1, xs2)
_ ->
match p2
Nil -> False
Cons(x2, xs2) ->
if noSwitch.any(fn(x') x' == x2) then False else p1.isSame(xs2 ++ [x2], Cons(x2, noSwitch))
 
fun show(f: face)
val (c, p) = f
c.core/show ++ " " ++ p.core/show
 
fun findRemove(l: list<a>, acc: ctx<list<a>>, pred: (a) -> bool): maybe<(a, list<a>)>
match l
[] -> Nothing
Cons(x, xs) -> match pred(x)
True -> Just((x, acc ++. xs))
False -> findRemove(xs, acc ++ ctx Cons(x, _), pred)
 
fun toPerimeter(search: int, edges: list<edge>, acc: ctx<perimeter>): <div,exn> perimeter
match edges
[] -> acc ++. Cons(search, Nil) // Assume the search matches the first edge's missing
_ -> match edges.findRemove(ctx _, fn((a, b)) a == search || b == search)
Just(((a, b), xs')) -> if search == a then
toPerimeter(b, xs', acc ++ ctx Cons(a, _))
else
toPerimeter(a, xs', acc ++ ctx Cons(b, _))
Nothing -> throw("Cannot find the next edge for " ++ search.show ++ " current perimeter is " ++ (acc ++. Nil).show ++ " and the rest of the edges are: " ++ edges.show-list(fn(s) s.show-tuple(show, show)))
 
fun main()
val fp = [(('P', [8, 1, 3]), ('R', [1, 3, 8])),
(('U', [18, 8, 14, 10, 12, 17, 19]), ('V', [8, 14, 10, 12, 17, 19, 18]))]
fp.foreach() fn((f1, f2))
val same = f1.snd.isSame(f2.snd)
print(f1.show ++ (if same then " is " else " is not ") ++ "the same as " ++ f2.show ++ "\n")
val fe = [('E', [(1, 11), (7, 11), (1, 7)]),
('F', [(11, 23), (1, 17), (17, 23), (1, 11)]),
('G', [(8, 14), (17, 19), (10, 12), (10, 14), (12, 17), (8, 18), (18, 19)]),
('H', [(1, 3), (9, 11), (3, 11), (1, 11)])]
fe.foreach() fn((f, edges))
match edges
[] -> ()
Cons((initX, _), edges') ->
val p = toPerimeter(initX, edges', ctx _)
print(f.show ++ " perimeter is " ++ p.show ++ "\n")
</syntaxhighlight>
{{out}}
<pre>
'P' [8,1,3] is the same as 'R' [1,3,8]
'U' [18,8,14,10,12,17,19] is the same as 'V' [8,14,10,12,17,19,18]
'E' perimeter is [1,7,11]
'F' perimeter is [11,1,17,23]
'G' perimeter is [8,18,19,17,12,10,14]
uncaught exception: Cannot find the next edge for 9 current perimeter is [1,11] and the rest of the edges are: [(3,11)]
</pre>
 
=={{header|Lua}}==
<syntaxhighlight lang="lua">-- support
function T(t) return setmetatable(t, {__index=table}) end
table.eql = function(t,u) if #t~=#u then return false end for i=1,#t do if t[i]~=u[i] then return false end end return true end
table.rol = function(t,n) local s=T{} for i=1,#t do s[i]=t[(i+n-1)%#t+1] end return s end
table.rev = function(t) local s=T{} for i=1,#t do s[#t-i+1]=t[i] end return s end
 
-- 1
function pfeq(pf1, pf2)
if #pf1 ~= #pf2 then return false end -- easy case
for w = 0,1 do -- exhaustive cases
local pfw = pf1 -- w:winding
if w==1 then pfw=pfw:rev() end
for r = 0,#pfw do
local pfr = pfw -- r:rotate
if r>0 then pfr=pfr:rol(r) end
if pf2:eql(pfr) then return true end
end
end
return false
end
 
Q = T{8, 1, 3}
R = T{1, 3, 8}
U = T{18, 8, 14, 10, 12, 17, 19}
V = T{8, 14, 10, 12, 17, 19, 18}
print("pfeq(Q,R): ", pfeq(Q, R))
print("pfeq(U,V): ", pfeq(U, V))
 
-- 2
function ef2pf(ef)
local pf, hse = T{}, T{} -- hse:hash of sorted edges
for i,e in ipairs(ef) do table.sort(e) hse[e]=e end
local function nexte(e)
if not e then return ef[1] end
for k,v in pairs(hse) do
if e[2]==v[1] then return v end
if e[2]==v[2] then v[1],v[2]=v[2],v[1] return v end
end
end
local e = nexte()
while e do
pf[#pf+1] = e[1]
hse[e] = nil
e = nexte(e)
end
if #pf ~= #ef then pf=T{"failed to convert edge format to perimeter format"} end
return pf
end
 
E = {{1, 11}, {7, 11}, {1, 7}}
F = {{11, 23}, {1, 17}, {17, 23}, {1, 11}}
G = {{8, 14}, {17, 19}, {10, 12}, {10, 14}, {12, 17}, {8, 18}, {18, 19}}
H = {{1, 3}, {9, 11}, {3, 11}, {1, 11}}
print("ef2pf(E): ", ef2pf(E):concat(","))
print("ef2pf(F): ", ef2pf(F):concat(","))
print("ef2pf(G): ", ef2pf(G):concat(","))
print("ef2pf(H): ", ef2pf(H):concat(","))</syntaxhighlight>
{{out}}
<pre>pfeq(Q,R): true
pfeq(U,V): true
ef2pf(E): 1,11,7
ef2pf(F): 11,23,17,1
ef2pf(G): 8,14,10,12,17,19,18
ef2pf(H): failed to convert edge format to perimeter format</pre>
 
=={{header|Nim}}==
<syntaxhighlight lang="nim">import algorithm, strutils
 
type
Perimeter = seq[int]
Face = tuple[name: char; perimeter: Perimeter]
Edge = tuple[first, last: int]
 
const None = -1 # No point.
 
#---------------------------------------------------------------------------------------------------
 
func isSame(p1, p2: Perimeter): bool =
## Return "true" if "p1" and "p2" represent the same face.
 
if p1.len != p2.len: return false
 
for p in p1:
if p notin p2: return false
 
var start = p2.find(p1[0])
if p1 == p2[start..^1] & p2[0..<start]:
return true
 
let p3 = reversed(p2)
start = p3.find(p1[0])
if p1 == p3[start..^1] & p3[0..<start]:
return true
 
#---------------------------------------------------------------------------------------------------
 
func `$`(perimeter: Perimeter): string =
## Convert a perimeter to a string.
'(' & perimeter.join(", ") & ')'
 
func `$`(face: Face): string =
## Convert a perimeter formatted face to a string.
face.name & $face.perimeter
 
#---------------------------------------------------------------------------------------------------
 
func toPerimeter(edges: seq[Edge]): Perimeter =
## Convert a list of edges to perimeter representation.
## Return an empty perimeter if the list of edges doesn’t represent a face.
 
var edges = edges
let firstEdge = edges.pop() # First edge taken in account.
var nextPoint = firstEdge.first # Next point to search in remaining edges.
result.add(nextpoint)
 
while edges.len > 0:
# Search an edge.
var idx = None
for i, e in edges:
if e.first == nextPoint or e.last == nextPoint:
idx = i
nextPoint = if nextpoint == e.first: e.last else: e.first
break
if idx == None:
return @[] # No edge found containing "newPoint".
 
# Add next point to perimeter and remove the edge.
result.add(nextPoint)
edges.del(idx)
 
# Check that last added point is the expected one.
if nextPoint != firstEdge.last:
return @[]
 
#———————————————————————————————————————————————————————————————————————————————————————————————————
 
when isMainModule:
 
# List of pairs of perimeter formatted faces to compare.
const FP = [(('P', @[8, 1, 3]), ('R', @[1, 3, 8])),
(('U', @[18, 8, 14, 10, 12, 17, 19]), ('V', @[8, 14, 10, 12, 17, 19, 18]))]
 
echo "Perimeter comparison:"
for (p1, p2) in FP:
echo p1, if isSame(p1[1], p2[1]): " is same as " else: "is not same as", p2
 
# List of edge formatted faces.
const FE = {'E': @[(1, 11), (7, 11), (1, 7)],
'F': @[(11, 23), (1, 17), (17, 23), (1, 11)],
'G': @[(8, 14), (17, 19), (10, 12), (10, 14), (12, 17), (8, 18), (18, 19)],
'H': @[(1, 3), (9, 11), (3, 11), (1, 11)]}
 
echo ""
echo "Conversion from edge to perimeter format:"
for (faceName, edges) in FE:
let perimeter = edges.toPerimeter()
echo faceName, ": ", if perimeter.len == 0: "Invalid edge list" else: $perimeter</syntaxhighlight>
 
{{out}}
<pre>Perimeter comparison:
P(8, 1, 3) is same as R(1, 3, 8)
U(18, 8, 14, 10, 12, 17, 19) is same as V(8, 14, 10, 12, 17, 19, 18)
 
Conversion from edge to perimeter format:
E: (1, 11, 7)
F: (1, 17, 23, 11)
G: (18, 8, 14, 10, 12, 17, 19)
H: Invalid edge list</pre>
 
=={{header|Perl}}==
{{trans|Perl 6Raku}}
<langsyntaxhighlight lang="perl">use strict;
use warnings;
use feature 'say';
Line 342 ⟶ 1,047:
[[1, 3], [9, 11], [3, 11], [1, 11]]) {
say show($_) . ' ==> (' . (join ' ', edge_to_periphery(@$_) or 'Invalid edge format') . ')'
}</langsyntaxhighlight>
{{out}}
<pre>Perimeter format equality checks:
Line 353 ⟶ 1,058:
( (8 14) (17 19) (10 12) (10 14) (12 17) (8 18) (18 19) ) ==> (8 14 10 12 17 19 18)
( (1 3) (9 11) (3 11) (1 11) ) ==> Invalid edge format</pre>
 
=={{header|Perl 6}}==
{{works with|Rakudo|2019.11}}
 
<lang perl6>sub check-equivalence ($a, $b) { so $a.Bag eqv $b.Bag }
 
sub edge-to-periphery (@a is copy) {
return Nil unless @a.List.Bag.values.all == 2;
my @b = @a.shift.flat;
while @a > 1 {
for @a.kv -> $k, $v {
if $v[0] == @b.tail {
@b.push: $v[1];
@a.splice($k,1);
last
}
elsif $v[1] == @b.tail {
@b.push: $v[0];
@a.splice($k,1);
last
}
}
}
@b
}
 
say 'Perimeter format equality checks:';
 
for (8, 1, 3), (1, 3, 8),
(18, 8, 14, 10, 12, 17, 19), (8, 14, 10, 12, 17, 19, 18)
-> $a, $b {
say "({$a.join: ', '}) equivalent to ({$b.join: ', '})? ",
check-equivalence($a, $b)
}
 
say "\nEdge to perimeter format translations:";
 
for ((1, 11), (7, 11), (1, 7)),
((11, 23), (1, 17), (17, 23), (1, 11)),
((8, 14), (17, 19), (10, 12), (10, 14), (12, 17), (8, 18), (18, 19)),
((1, 3), (9, 11), (3, 11), (1, 11))
{
.gist.print;
say " ==> ({.&edge-to-periphery || 'Invalid edge format'})";
}</lang>
{{out}}
<pre>Perimeter format equality checks:
(8, 1, 3) equivalent to (1, 3, 8)? True
(18, 8, 14, 10, 12, 17, 19) equivalent to (8, 14, 10, 12, 17, 19, 18)? True
 
Edge to perimeter format translations:
((1 11) (7 11) (1 7)) ==> (1 11 7)
((11 23) (1 17) (17 23) (1 11)) ==> (11 23 17 1)
((8 14) (17 19) (10 12) (10 14) (12 17) (8 18) (18 19)) ==> (8 14 10 12 17 19 18)
((1 3) (9 11) (3 11) (1 11)) ==> (Invalid edge format)</pre>
 
=={{header|Phix}}==
<!--<syntaxhighlight lang="phix">(phixonline)-->
<lang Phix>function perequiv(sequence a, b)
<span style="color: #008080;">with</span> <span style="color: #008080;">javascript_semantics</span>
-- Works by aligning and rotating in one step, so theoretically much faster on massive sets.
<span style="color: #008080;">function</span> <span style="color: #000000;">perequiv</span><span style="color: #0000FF;">(</span><span style="color: #004080;">sequence</span> <span style="color: #000000;">a</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">b</span><span style="color: #0000FF;">)</span>
-- (ahem, faster than multiple rotates, index-only loops would obviously be even faster...)
<span style="color: #000080;font-style:italic;">-- Works by aligning and rotating in one step, so theoretically much faster on massive sets.
bool res = (length(a)==length(b))
-- (ahem, faster than multiple rotates, index-only loops would obviously be even faster...)</span>
if res and length(a)>0 then
<span style="color: #004080;">bool</span> <span style="color: #000000;">res</span> <span style="color: #0000FF;">=</span> <span style="color: #0000FF;">(</span><span style="color: #7060A8;">length</span><span style="color: #0000FF;">(</span><span style="color: #000000;">a</span><span style="color: #0000FF;">)==</span><span style="color: #7060A8;">length</span><span style="color: #0000FF;">(</span><span style="color: #000000;">b</span><span style="color: #0000FF;">))</span>
integer k = find(a[1],b)
<span style="color: #008080;">if</span> <span style="color: #000000;">res</span> <span style="color: #008080;">and</span> <span style="color: #7060A8;">length</span><span style="color: #0000FF;">(</span><span style="color: #000000;">a</span><span style="color: #0000FF;">)></span><span style="color: #000000;">0</span> <span style="color: #008080;">then</span>
if k=0 then
<span style="color: #004080;">integer</span> <span style="color: #000000;">k</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">find</span><span style="color: #0000FF;">(</span><span style="color: #000000;">a</span><span style="color: #0000FF;">[</span><span style="color: #000000;">1</span><span style="color: #0000FF;">],</span><span style="color: #000000;">b</span><span style="color: #0000FF;">)</span>
res = false
<span style="color: #008080;">if</span> <span style="color: #000000;">k</span><span style="color: #0000FF;">=</span><span style="color: #000000;">0</span> <span style="color: #008080;">then</span>
else
<span style="color: #000000;">res</span> <span style="color: #0000FF;">=</span> <span style="color: #004600;">false</span>
-- align with a (ie make b[1]==a[1], by
<span style="color: #008080;">else</span>
-- rotating b k places in one operation)
<span style="color: #000080;font-style:italic;">-- align with a (ie make b[1]==a[1], by
b = b[k..$]&b[1..k-1]
if a!=-- rotating b thenk places in one operation)</span>
<span style="color: #000000;">b</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">b</span><span style="color: #0000FF;">[</span><span style="color: #000000;">k</span><span style="color: #0000FF;">..$]&</span><span style="color: #000000;">b</span><span style="color: #0000FF;">[</span><span style="color: #000000;">1</span><span style="color: #0000FF;">..</span><span style="color: #000000;">k</span><span style="color: #0000FF;">-</span><span style="color: #000000;">1</span><span style="color: #0000FF;">]</span>
-- eg {8,3,4,5} <=> {8,5,4,3}, ie
<span style="color: #008080;">if</span> <span style="color: #000000;">a</span><span style="color: #0000FF;">!=</span><span style="color: #000000;">b</span> <span style="color: #008080;">then</span>
-- rotate *and* keep in alignment.
<span style="color: #000080;font-style:italic;">-- eg {8,3,4,5} &lt;=&gt; {8,5,4,3}, ie
b[2..$] = reverse(b[2..$])
res =-- (a==b)rotate *and* keep in alignment.</span>
<span style="color: #000000;">b</span><span style="color: #0000FF;">[</span><span style="color: #000000;">2</span><span style="color: #0000FF;">..$]</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">reverse</span><span style="color: #0000FF;">(</span><span style="color: #000000;">b</span><span style="color: #0000FF;">[</span><span style="color: #000000;">2</span><span style="color: #0000FF;">..$])</span>
end if
<span style="color: #000000;">res</span> <span style="color: #0000FF;">=</span> <span style="color: #0000FF;">(</span><span style="color: #000000;">a</span><span style="color: #0000FF;">==</span><span style="color: #000000;">b</span><span style="color: #0000FF;">)</span>
end if
<span style="color: #008080;">end</span> <span style="color: #008080;">if</span>
end if
<span style="color: #008080;">end</span> <span style="color: #008080;">if</span>
-- return res
<span style="color: #008080;">end</span> <span style="color: #008080;">if</span>
return {"false","true"}[res+1]
<span style="color: #000080;font-style:italic;">-- return res</span>
end function
<span style="color: #008080;">return</span> <span style="color: #0000FF;">{</span><span style="color: #008000;">"false"</span><span style="color: #0000FF;">,</span><span style="color: #008000;">"true"</span><span style="color: #0000FF;">}[</span><span style="color: #000000;">res</span><span style="color: #0000FF;">+</span><span style="color: #000000;">1</span><span style="color: #0000FF;">]</span>
 
<span style="color: #008080;">end</span> <span style="color: #008080;">function</span>
function edge2peri(sequence edges)
sequence was = edges, res = {}
<span style="color: #008080;">function</span> <span style="color: #000000;">edge2peri</span><span style="color: #0000FF;">(</span><span style="color: #004080;">sequence</span> <span style="color: #000000;">edges</span><span style="color: #0000FF;">)</span>
string error = ""
<span style="color: #004080;">sequence</span> <span style="color: #000000;">was</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">edges</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">res</span> <span style="color: #0000FF;">=</span> <span style="color: #0000FF;">{}</span>
integer lnk = 0
<span style="color: #004080;">string</span> <span style="color: #000000;">error</span> <span style="color: #0000FF;">=</span> <span style="color: #008000;">""</span>
if length(edges)<2 then
<span style="color: #004080;">integer</span> <span style="color: #000000;">lnk</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">0</span>
error = "too short"
<span style="color: #008080;">if</span> <span style="color: #7060A8;">length</span><span style="color: #0000FF;">(</span><span style="color: #000000;">edges</span><span style="color: #0000FF;">)<</span><span style="color: #000000;">2</span> <span style="color: #008080;">then</span>
else
<span style="color: #000000;">error</span> <span style="color: #0000FF;">=</span> <span style="color: #008000;">"too short"</span>
-- edges = sort(edges) -- (see note below)
<span style="color: #008080;">else</span>
res = edges[1]
<span style="color: #000080;font-style:italic;">-- edges = sort(deep_copy(edges)) -- (see note below)</span>
edges = edges[2..$]
<span style="color: #000000;">res</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">deep_copy</span><span style="color: #0000FF;">(</span><span style="color: #000000;">edges</span><span style="color: #0000FF;">[</span><span style="color: #000000;">1</span><span style="color: #0000FF;">])</span>
lnk = res[2]
<span style="color: #000000;">edges</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">edges</span><span style="color: #0000FF;">[</span><span style="color: #000000;">2</span><span style="color: #0000FF;">..$]</span>
while length(edges) and error="" do
<span style="color: #000000;">lnk</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">res</span><span style="color: #0000FF;">[</span><span style="color: #000000;">2</span><span style="color: #0000FF;">]</span>
bool found = false
<span style="color: #008080;">while</span> <span style="color: #7060A8;">length</span><span style="color: #0000FF;">(</span><span style="color: #000000;">edges</span><span style="color: #0000FF;">)</span> <span style="color: #008080;">and</span> <span style="color: #000000;">error</span><span style="color: #0000FF;">=</span><span style="color: #008000;">""</span> <span style="color: #008080;">do</span>
for i=1 to length(edges) do
<span style="color: #004080;">bool</span> <span style="color: #000000;">found</span> <span style="color: #0000FF;">=</span> <span style="color: #004600;">false</span>
integer k = find(lnk,edges[i])
<span style="color: #008080;">for</span> <span style="color: #000000;">i</span><span style="color: #0000FF;">=</span><span style="color: #000000;">1</span> <span style="color: #008080;">to</span> <span style="color: #7060A8;">length</span><span style="color: #0000FF;">(</span><span style="color: #000000;">edges</span><span style="color: #0000FF;">)</span> <span style="color: #008080;">do</span>
if k then
<span style="color: #004080;">integer</span> <span style="color: #000000;">k</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">find</span><span style="color: #0000FF;">(</span><span style="color: #000000;">lnk</span><span style="color: #0000FF;">,</span><span style="color: #000000;">edges</span><span style="color: #0000FF;">[</span><span style="color: #000000;">i</span><span style="color: #0000FF;">])</span>
lnk = edges[i][3-k]
<span style="color: #008080;">if</span> <span style="color: #000000;">k</span> <span style="color: #008080;">then</span>
edges[i..i] = {}
<span style="color: #000000;">lnk</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">edges</span><span style="color: #0000FF;">[</span><span style="color: #000000;">i</span><span style="color: #0000FF;">][</span><span style="color: #000000;">3</span><span style="color: #0000FF;">-</span><span style="color: #000000;">k</span><span style="color: #0000FF;">]</span>
if edges={} then
<span style="color: #000000;">edges</span><span style="color: #0000FF;">[</span><span style="color: #000000;">i</span><span style="color: #0000FF;">..</span><span style="color: #000000;">i</span><span style="color: #0000FF;">]</span> <span style="color: #0000FF;">=</span> <span style="color: #0000FF;">{}</span>
if lnk!=res[1] then error = "oh dear" end if
<span style="color: #008080;">if</span> <span style="color: #000000;">edges</span><span style="color: #0000FF;">={}</span> <span style="color: #008080;">then</span>
else
<span style="color: #008080;">if</span> <span style="color: #000000;">lnk</span><span style="color: #0000FF;">!=</span><span style="color: #000000;">res</span><span style="color: #0000FF;">[</span><span style="color: #000000;">1</span><span style="color: #0000FF;">]</span> <span style="color: #008080;">then</span> <span style="color: #000000;">error</span> <span style="color: #0000FF;">=</span> <span style="color: #008000;">"oh dear"</span> <span style="color: #008080;">end</span> <span style="color: #008080;">if</span>
if find(lnk,res) then error = "oops" end if
<span res &style="color: lnk#008080;">else</span>
<span style="color: #008080;">if</span> <span style="color: #7060A8;">find</span><span style="color: #0000FF;">(</span><span style="color: #000000;">lnk</span><span style="color: #0000FF;">,</span><span style="color: #000000;">res</span><span style="color: #0000FF;">)</span> <span style="color: #008080;">then</span> <span style="color: #000000;">error</span> <span style="color: #0000FF;">=</span> <span style="color: #008000;">"oops"</span> <span style="color: #008080;">end</span> <span style="color: #008080;">if</span>
end if
<span style="color: #000000;">res</span> <span style="color: #0000FF;">&=</span> <span style="color: #000000;">lnk</span>
found = true
<span style="color: #008080;">end</span> <span style="color: #008080;">if</span>
exit
<span style="color: #000000;">found</span> <span style="color: #0000FF;">=</span> <span style="color: #004600;">true</span>
end if
<span style="color: #008080;">exit</span>
end for
if not found then error =<span style="badcolor: link#008080;">end</span> exit<span endstyle="color: #008080;">if</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">for</span>
end while
<span style="color: #008080;">if</span> <span style="color: #008080;">not</span> <span style="color: #000000;">found</span> <span style="color: #008080;">then</span> <span style="color: #000000;">error</span> <span style="color: #0000FF;">=</span> <span style="color: #008000;">"bad link"</span> <span style="color: #008080;">exit</span> <span style="color: #008080;">end</span> <span style="color: #008080;">if</span>
end if
<span style="color: #008080;">end</span> <span style="color: #008080;">while</span>
if length(error) then res = {error,res,lnk,edges,was} end if
<span style="color: #008080;">end</span> <span style="color: #008080;">if</span>
return res
<span style="color: #008080;">if</span> <span style="color: #7060A8;">length</span><span style="color: #0000FF;">(</span><span style="color: #000000;">error</span><span style="color: #0000FF;">)</span> <span style="color: #008080;">then</span> <span style="color: #000000;">res</span> <span style="color: #0000FF;">=</span> <span style="color: #0000FF;">{</span><span style="color: #000000;">error</span><span style="color: #0000FF;">,</span><span style="color: #000000;">res</span><span style="color: #0000FF;">,</span><span style="color: #000000;">lnk</span><span style="color: #0000FF;">,</span><span style="color: #000000;">edges</span><span style="color: #0000FF;">,</span><span style="color: #000000;">was</span><span style="color: #0000FF;">}</span> <span style="color: #008080;">end</span> <span style="color: #008080;">if</span>
end function
<span style="color: #008080;">return</span> <span style="color: #000000;">res</span>
 
<span style="color: #008080;">end</span> <span style="color: #008080;">function</span>
constant ptests = {{{8, 1, 3}, {1, 3, 8}},
{{18, 8, 14, 10, 12, 17, 19}, {8, 14, 10, 12, 17, 19, 18}},
<span style="color: #008080;">constant</span> <span style="color: #000000;">ptests</span> <span style="color: #0000FF;">=</span> <span style="color: #0000FF;">{{{</span><span style="color: #000000;">8</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">1</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">3</span><span style="color: #0000FF;">},</span> <span style="color: #0000FF;">{</span><span style="color: #000000;">1</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">3</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">8</span><span style="color: #0000FF;">}},</span>
-- (check our results below against Go etc)
<span style="color: #0000FF;">{{</span><span style="color: #000000;">18</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">8</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">14</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">10</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">12</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">17</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">19</span><span style="color: #0000FF;">},</span> <span style="color: #0000FF;">{</span><span style="color: #000000;">8</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">14</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">10</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">12</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">17</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">19</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">18</span><span style="color: #0000FF;">}},</span>
{{1,11,7},{1,7,11}},
<span style="color: #000080;font-style:italic;">-- (check our results below against Go etc)</span>
{{11,23,17,1},{1,11,23,17}}}
<span style="color: #0000FF;">{{</span><span style="color: #000000;">1</span><span style="color: #0000FF;">,</span><span style="color: #000000;">11</span><span style="color: #0000FF;">,</span><span style="color: #000000;">7</span><span style="color: #0000FF;">},{</span><span style="color: #000000;">1</span><span style="color: #0000FF;">,</span><span style="color: #000000;">7</span><span style="color: #0000FF;">,</span><span style="color: #000000;">11</span><span style="color: #0000FF;">}},</span>
for i=1 to length(ptests) do
<span style="color: #0000FF;">{{</span><span style="color: #000000;">11</span><span style="color: #0000FF;">,</span><span style="color: #000000;">23</span><span style="color: #0000FF;">,</span><span style="color: #000000;">17</span><span style="color: #0000FF;">,</span><span style="color: #000000;">1</span><span style="color: #0000FF;">},{</span><span style="color: #000000;">1</span><span style="color: #0000FF;">,</span><span style="color: #000000;">11</span><span style="color: #0000FF;">,</span><span style="color: #000000;">23</span><span style="color: #0000FF;">,</span><span style="color: #000000;">17</span><span style="color: #0000FF;">}}}</span>
sequence {p,q} = ptests[i]
<span style="color: #008080;">for</span> <span style="color: #000000;">i</span><span style="color: #0000FF;">=</span><span style="color: #000000;">1</span> <span style="color: #008080;">to</span> <span style="color: #7060A8;">length</span><span style="color: #0000FF;">(</span><span style="color: #000000;">ptests</span><span style="color: #0000FF;">)</span> <span style="color: #008080;">do</span>
printf(1,"%v equivalent to %v: %s\n",{p,q,perequiv(p,q)})
<span style="color: #004080;">sequence</span> <span style="color: #0000FF;">{</span><span style="color: #000000;">p</span><span style="color: #0000FF;">,</span><span style="color: #000000;">q</span><span style="color: #0000FF;">}</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">ptests</span><span style="color: #0000FF;">[</span><span style="color: #000000;">i</span><span style="color: #0000FF;">]</span>
end for
<span style="color: #7060A8;">printf</span><span style="color: #0000FF;">(</span><span style="color: #000000;">1</span><span style="color: #0000FF;">,</span><span style="color: #008000;">"%v equivalent to %v: %s\n"</span><span style="color: #0000FF;">,{</span><span style="color: #000000;">p</span><span style="color: #0000FF;">,</span><span style="color: #000000;">q</span><span style="color: #0000FF;">,</span><span style="color: #000000;">perequiv</span><span style="color: #0000FF;">(</span><span style="color: #000000;">p</span><span style="color: #0000FF;">,</span><span style="color: #000000;">q</span><span style="color: #0000FF;">)})</span>
 
<span style="color: #008080;">end</span> <span style="color: #008080;">for</span>
constant etests = {{{1, 11}, {7, 11}, {1, 7}},
{{11, 23}, {1, 17}, {17, 23}, {1, 11}},
<span style="color: #008080;">constant</span> <span style="color: #000000;">etests</span> <span style="color: #0000FF;">=</span> <span style="color: #0000FF;">{{{</span><span style="color: #000000;">1</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">11</span><span style="color: #0000FF;">},</span> <span style="color: #0000FF;">{</span><span style="color: #000000;">7</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">11</span><span style="color: #0000FF;">},</span> <span style="color: #0000FF;">{</span><span style="color: #000000;">1</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">7</span><span style="color: #0000FF;">}},</span>
{{8, 14}, {17, 19}, {10, 12}, {10, 14}, {12, 17}, {8, 18}, {18, 19}},
<span style="color: #0000FF;">{{</span><span style="color: #000000;">11</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">23</span><span style="color: #0000FF;">},</span> <span style="color: #0000FF;">{</span><span style="color: #000000;">1</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">17</span><span style="color: #0000FF;">},</span> <span style="color: #0000FF;">{</span><span style="color: #000000;">17</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">23</span><span style="color: #0000FF;">},</span> <span style="color: #0000FF;">{</span><span style="color: #000000;">1</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">11</span><span style="color: #0000FF;">}},</span>
{{1, 3}, {9, 11}, {3, 11}, {1, 11}}}
<span style="color: #0000FF;">{{</span><span style="color: #000000;">8</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">14</span><span style="color: #0000FF;">},</span> <span style="color: #0000FF;">{</span><span style="color: #000000;">17</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">19</span><span style="color: #0000FF;">},</span> <span style="color: #0000FF;">{</span><span style="color: #000000;">10</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">12</span><span style="color: #0000FF;">},</span> <span style="color: #0000FF;">{</span><span style="color: #000000;">10</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">14</span><span style="color: #0000FF;">},</span> <span style="color: #0000FF;">{</span><span style="color: #000000;">12</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">17</span><span style="color: #0000FF;">},</span> <span style="color: #0000FF;">{</span><span style="color: #000000;">8</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">18</span><span style="color: #0000FF;">},</span> <span style="color: #0000FF;">{</span><span style="color: #000000;">18</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">19</span><span style="color: #0000FF;">}},</span>
for i=1 to length(etests) do
<span style="color: #0000FF;">{{</span><span style="color: #000000;">1</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">3</span><span style="color: #0000FF;">},</span> <span style="color: #0000FF;">{</span><span style="color: #000000;">9</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">11</span><span style="color: #0000FF;">},</span> <span style="color: #0000FF;">{</span><span style="color: #000000;">3</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">11</span><span style="color: #0000FF;">},</span> <span style="color: #0000FF;">{</span><span style="color: #000000;">1</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">11</span><span style="color: #0000FF;">}}}</span>
printf(1,"%v\n",{edge2peri(etests[i])})
<span style="color: #008080;">for</span> <span style="color: #000000;">i</span><span style="color: #0000FF;">=</span><span style="color: #000000;">1</span> <span style="color: #008080;">to</span> <span style="color: #7060A8;">length</span><span style="color: #0000FF;">(</span><span style="color: #000000;">etests</span><span style="color: #0000FF;">)</span> <span style="color: #008080;">do</span>
end for</lang>
<span style="color: #7060A8;">printf</span><span style="color: #0000FF;">(</span><span style="color: #000000;">1</span><span style="color: #0000FF;">,</span><span style="color: #008000;">"%v\n"</span><span style="color: #0000FF;">,{</span><span style="color: #000000;">edge2peri</span><span style="color: #0000FF;">(</span><span style="color: #000000;">etests</span><span style="color: #0000FF;">[</span><span style="color: #000000;">i</span><span style="color: #0000FF;">])})</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">for</span>
<!--</syntaxhighlight>-->
{{out}}
(second part matches Julia/Perl: un-comment that sort above to match Go/Python/zkl)
Line 500 ⟶ 1,153:
 
=={{header|Python}}==
<langsyntaxhighlight lang="python">def perim_equal(p1, p2):
# Cheap tests first
if len(p1) != len(p2) or set(p1) != set(p2):
Line 549 ⟶ 1,202:
}
for name, edges in edge_d.items():
print(f" {name}: {edges}\n -> {edge_to_periphery(edges)}")</langsyntaxhighlight>
 
{{out}}
Line 565 ⟶ 1,218:
H: {(1, 11), (9, 11), (1, 3), (3, 11)}
-> >>>Error! Invalid edge format<<<</pre>
 
=={{header|Raku}}==
(formerly Perl 6)
{{works with|Rakudo|2019.11}}
 
<syntaxhighlight lang="raku" line>sub check-equivalence ($a, $b) { so $a.Bag eqv $b.Bag }
 
sub edge-to-periphery (@a is copy) {
return Nil unless @a.List.Bag.values.all == 2;
my @b = @a.shift.flat;
while @a > 1 {
for @a.kv -> $k, $v {
if $v[0] == @b.tail {
@b.push: $v[1];
@a.splice($k,1);
last
}
elsif $v[1] == @b.tail {
@b.push: $v[0];
@a.splice($k,1);
last
}
}
}
@b
}
 
say 'Perimeter format equality checks:';
 
for (8, 1, 3), (1, 3, 8),
(18, 8, 14, 10, 12, 17, 19), (8, 14, 10, 12, 17, 19, 18)
-> $a, $b {
say "({$a.join: ', '}) equivalent to ({$b.join: ', '})? ",
check-equivalence($a, $b)
}
 
say "\nEdge to perimeter format translations:";
 
for ((1, 11), (7, 11), (1, 7)),
((11, 23), (1, 17), (17, 23), (1, 11)),
((8, 14), (17, 19), (10, 12), (10, 14), (12, 17), (8, 18), (18, 19)),
((1, 3), (9, 11), (3, 11), (1, 11))
{
.gist.print;
say " ==> ({.&edge-to-periphery || 'Invalid edge format'})";
}</syntaxhighlight>
{{out}}
<pre>Perimeter format equality checks:
(8, 1, 3) equivalent to (1, 3, 8)? True
(18, 8, 14, 10, 12, 17, 19) equivalent to (8, 14, 10, 12, 17, 19, 18)? True
 
Edge to perimeter format translations:
((1 11) (7 11) (1 7)) ==> (1 11 7)
((11 23) (1 17) (17 23) (1 11)) ==> (11 23 17 1)
((8 14) (17 19) (10 12) (10 14) (12 17) (8 18) (18 19)) ==> (8 14 10 12 17 19 18)
((1 3) (9 11) (3 11) (1 11)) ==> (Invalid edge format)</pre>
 
=={{header|Wren}}==
{{trans|Go}}
{{libheader|Wren-sort}}
{{libheader|Wren-seq}}
{{libheader|Wren-fmt}}
<syntaxhighlight lang="wren">import "./sort" for Sort
import "./seq" for Lst
import "./fmt" for Fmt
// Check two perimeters are equal.
var perimEqual = Fn.new { |p1, p2|
var le = p1.count
if (le != p2.count) return false
for (p in p1) {
if (!p2.contains(p)) return false
}
// use copy to avoid mutating 'p1'
var c = p1.toList
for (r in 0..1) {
for (i in 0...le) {
if (Lst.areEqual(c, p2)) return true
// do circular shift to right
Lst.rshift(c)
}
// now process in opposite direction
Lst.reverse(c) // reverses 'c' in place
}
return false
}
var faceToPerim = Fn.new { |face|
// use copy to avoid mutating 'face'
var le = face.count
if (le == 0) return []
var edges = List.filled(le, null)
for (i in 0...le) {
// check edge pairs are in correct order
if (face[i][1] <= face[i][0]) return []
edges[i] = [face[i][0], face[i][1]]
}
// sort edges in ascending order
var cmp = Fn.new { |e1, e2|
if (e1[0] != e2[0]) {
return (e1[0] - e2[0]).sign
}
return (e1[1] - e2[1]).sign
}
Sort.insertion(edges, cmp)
var first = edges[0][0]
var last = edges[0][1]
var perim = [first, last]
// remove first edge
edges.removeAt(0)
le = le - 1
while (le > 0) {
var i = 0
var outer = false
var cont = false
for (e in edges) {
var found = false
if (e[0] == last) {
perim.add(e[1])
last = e[1]
found = true
} else if (e[1] == last) {
perim.add(e[0])
last = e[0]
found = true
}
if (found) {
// remove i'th edge
edges.removeAt(i)
le = le - 1
if (last == first) {
if (le == 0) {
outer = true
break
} else {
return []
}
}
cont = true
break
}
i = i + 1
}
if (outer && !cont) break
}
return perim[0..-2]
}
System.print("Perimeter format equality checks:")
var areEqual = perimEqual.call([8, 1, 3], [1, 3, 8])
System.print(" Q == R is %(areEqual)")
areEqual = perimEqual.call([18, 8, 14, 10, 12, 17, 19], [8, 14, 10, 12, 17, 19, 18])
System.print(" U == V is %(areEqual)")
var e = [[7, 11], [1, 11], [1, 7]]
var f = [[11, 23], [1, 17], [17, 23], [1, 11]]
var g = [[8, 14], [17, 19], [10, 12], [10, 14], [12, 17], [8, 18], [18, 19]]
var h = [[1, 3], [9, 11], [3, 11], [1, 11]]
System.print("\nEdge to perimeter format translations:")
var i = 0
for (face in [e, f, g, h]) {
var perim = faceToPerim.call(face)
if (perim.isEmpty) {
Fmt.print(" $c => Invalid edge format", i + 69) // 'E' is ASCII 69
} else {
Fmt.print(" $c => $n", i + 69, perim)
}
}</syntaxhighlight>
 
{{out}}
<pre>
Perimeter format equality checks:
Q == R is true
U == V is true
 
Edge to perimeter format translations:
E => [1, 7, 11]
E => [1, 11, 23, 17]
E => [8, 14, 10, 12, 17, 19, 18]
E => Invalid edge format
</pre>
 
=={{header|zkl}}==
{{trans|Python}}
<langsyntaxhighlight lang="zkl">fcn perimSame(p1, p2){
if(p1.len() != p2.len()) return(False);
False == p1.filter1('wrap(p){ (not p2.holds(p)) })
Line 584 ⟶ 1,417:
}
p[0,-1] // last element not part of result
}</langsyntaxhighlight>
<langsyntaxhighlight lang="zkl">println("Perimeter format equality checks:");
ps:=T( T( T(8,1,3), T(1,3,8) ),
T( T(18, 8, 14, 10, 12, 17, 19), T(8, 14, 10, 12, 17, 19, 18) ) );
Line 602 ⟶ 1,435:
 
fcn pp(a){ a.concat(", ","(",")") }
fcn ppp(edges){ pp(edges.apply(pp)) }</langsyntaxhighlight>
{{out}}
<pre>
9,476

edits