September 2017 Update

This commit is contained in:
Ingy döt Net 2017-09-23 10:01:46 +02:00
parent bba7bfd280
commit ba8067c3b7
14570 changed files with 153136 additions and 63871 deletions

View file

@ -0,0 +1,164 @@
import system'collections.
import system'routines.
import extensions.
import extensions'routines.
type charmatrix = matrix<CharValue>.
const image = (
" ",
" ################# ############# ",
" ################## ################ ",
" ################### ################## ",
" ######## ####### ################### ",
" ###### ####### ####### ###### ",
" ###### ####### ####### ",
" ################# ####### ",
" ################ ####### ",
" ################# ####### ",
" ###### ####### ####### ",
" ###### ####### ####### ",
" ###### ####### ####### ###### ",
" ######## ####### ################### ",
" ######## ####### ###### ################## ###### ",
" ######## ####### ###### ################ ###### ",
" ######## ####### ###### ############# ###### ",
" ").
nbrs = ((0, -1), (1, -1), (1, 0), (1, 1), (0, 1),
(-1, 1), (-1, 0), (-1, -1), (0, -1)).
nbrGroups = (((0, 2, 4), (2, 4, 6)), ((0, 2, 6),
(0, 4, 6))).
charmatrix extension zhangsuenOp
{
$proceed : r : c : toWhite : firstStep
[
if (self[r][c] != $35)
[ ^ false ].
int nn := self numNeighbors(r,c).
if ((nn < 2) || (nn > 6))
[ ^ false ].
if(self numTransitions(r,c) != 1)
[ ^ false ].
ifnot (self atLeastOneIsWhite(r,c,firstStep iif(0,1)))
[ ^ false ].
toWhite append:{ x = c. y = r. }.
^ true.
]
numNeighbors :r : c
[
int count := 0.
0 till(nbrs length - 1) do(:i)
[
if (self[r + nbrs[i][1]][c + nbrs[i][0]] == $35)
[ count := count + 1. ].
].
^ count.
]
numTransitions : r : c
[
int count := 0.
0 till(nbrs length - 1) do(:i)
[
if (self[r + nbrs[i][1]][c + nbrs[i][0]] == $32)
[
if (self[r + nbrs[i + 1][1]][c + nbrs[i + 1][0]] == $35)
[
count := count + 1.
].
].
].
^ count.
]
atLeastOneIsWhite : r : c : step
[
int count := 0.
var group := nbrGroups[step].
0 till:2 do(:i)
[
0 till(group[i] length) seek(:j)
[
var nbr := nbrs[group[i][j]].
if (self[r + nbr[1]][c + nbr[0]] == $32)
[ count := count + 1. ^ true ].
^ false.
].
].
^ count > 1.
]
thinImage
[
bool firstStep := false.
bool hasChanged := true.
var toWhite := List new.
while (hasChanged || firstStep)
[
hasChanged := false.
firstStep := firstStep not.
1 till(self rows - 1) do(:r)
[
1 till(self columns - 1) do(:c)
[
if(self~zhangsuenOp $proceed(r,c,toWhite,firstStep))
[ hasChanged := true ].
].
].
toWhite forEach(:p)[ self[p y][p x] := $32. ].
toWhite clear.
].
]
print
[
var it := self enumerator.
it forEach(:ch) [ console print(ch," ") ].
while (it next)
[
console writeLine.
it forEach(:ch) [ console print(ch," ") ].
].
]
}
program =
[
charmatrix grid := MatrixSpace::
{
rows = image length.
columns = image[0] length.
getAt int:i int:j
= image[i][j].
}.
grid thinImage.
grid print.
console readChar.
].

View file

@ -0,0 +1 @@
FOR ALL (i = 2:n - 1) A(i) = (A(i - 1) + A(i) + A(i + 1))/3

View file

@ -0,0 +1 @@
A(2:N - 1) = (A(1:N - 2) + A(2:N - 1) + A(3:N))/3

View file

@ -0,0 +1,2 @@
FOR ALL (I = 2:N - 1, J = 2:M - 1)
WHERE(DOT(I,J) .NE. 0) DOT(I,J) = ADJUST(DOT,I,J)

View file

@ -0,0 +1 @@
DOT(WHACK(1:WHACKCOUNT).I,WHACK(1:WHACKCOUNT).J) = 0

View file

@ -0,0 +1,106 @@
MODULE ZhangSuenThinning !Image manipulation.
CONTAINS
SUBROUTINE ZST(DOT) !Attempts to thin out thick lines.
INTEGER DOT(:,:) !The image in an array, rows down the page.
TYPE PLACE !This records an array location.
INTEGER I !Via its
INTEGER J !Indices.
END TYPE PLACE !A lot of baggage.
TYPE(PLACE) WHACK(UBOUND(DOT,DIM = 1)*UBOUND(DOT,DIM = 2)) !Allow a whack for every dot.
INTEGER WHACKCOUNT !Counts up those to be wiped out.
LOGICAL WHACKED !Notes if any have been.
INTEGER STEP,I,N,J,M !Assistants.
INTEGER D9(9) !Holds a 3x3 portion.
INTEGER HIT1(3,2),HIT2(3,2) !Lists of elements to inspect for certain tests.
PARAMETER (HIT1 = (/2,6,8, 4,2,6/)) !Two stages.
PARAMETER (HIT2 = (/4,8,6, 2,4,8/)) !Each with two hit lists.
N = UBOUND(DOT,DIM = 1) !Number of rows.
M = UBOUND(DOT,DIM = 2) !Number of columns.
Commence a pass.
10 WHACKED = .FALSE. !No damage so far.
DO STEP = 1,2 !Each pass is in two stages.
WHACKCOUNT = 0 !No dots have been selected for whitewashing.
DO I = 2,N - 1 !Scan down the rows.
DO J = 2,M - 1 !And the columns. Interior dots only.
IF (DOT(I,J).NE.0) THEN !Rule 0: Is the dot black? Eight neighbours are present due to loop control.
D9(1:3) = DOT(I - 1,J - 1:J + 1) !Yes. Form a 3x3 mesh. 1 2 3 not 9 2 3
D9(4:6) = DOT(I ,J - 1:J + 1) !As a 1-D array. 4 5 6 8 1 4
D9(7:9) = DOT(I + 1,J - 1:J + 1) !For eased access. 7 8 9 7 6 5
CALL INSPECT(D9,HIT1(1,STEP),HIT2(1,STEP)) !Apply rules one to four, as specified.
END IF !So much for a black dot.
END DO !On to the next column.
END DO !On to the next row.
IF (WHACKCOUNT.GT.0) THEN !Are any to be wiped out?
DO I = 1,WHACKCOUNT !Yes!
DOT(WHACK(I).I,WHACK(I).J) = 0 !One by one.
END DO !On to the next victim.
Can't use DOT(WHACK(1:WHACKCOUNT).I,WHACK(1:WHACKCOUNT).J) = 0
WHACKED = .TRUE. !There has been a change.
END IF !So much for changes.
END DO !On to the second stage.
IF (WHACKED) GO TO 10 !If there had been changes, perhaps there will be more.
CONTAINS !Some helpers.
SUBROUTINE INSPECT(BLOB,HIT1,HIT2) !Inspect a 3x3 piece according to the four levels of tests as specified.
INTEGER BLOB(9) !The piece. BLOB(5) is DOT(I,J), and is expected to be 1.
INTEGER HIT1(3),HIT2(3) !Two hit lists.
INTEGER TWIRL(9) !traces the periphery of the piece.
PARAMETER (TWIRL = (/2,3,6,9,8,7,4,1,2/)) !Cycle around the periphery.
INTEGER B !A counter. !Rule:
B = SUM(BLOB) - BLOB(5) !1: Count the neighbours having one, not zero.
IF (2 <= B .AND. B <= 6) THEN ! The test. Can't have 2 <= B <= 6, alas.
IF (COUNT(BLOB(TWIRL(1:8)) !2: Counting transitions.
* .LT.BLOB(TWIRL(2:9))) .EQ.1) THEN ! The test of 0 --> positive.
IF (ANY(BLOB(HIT1).EQ.0)) THEN !3: At least one must be white.
IF (ANY(BLOB(HIT2).EQ.0)) THEN !4: Of two sets of three.
WHACKCOUNT = WHACKCOUNT + 1 !Another one down!
WHACK(WHACKCOUNT) = PLACE(I,J) !This is the place.
END IF !Now back out of the nested IF-statements.
END IF !Since the tests must all be passed
END IF !Rather than say three out of four.
END IF !For the given method.
END SUBROUTINE INSPECT!That was weird.
END SUBROUTINE ZST !But so it goes.
SUBROUTINE SHOW(A) !Display an image array on the standard output.
INTEGER A(:,:) !Values are expected to be zero and one.
CHARACTER*1 HIC(0:1) !But I don't want to look at wads of digits.
PARAMETER (HIC = (/".","#"/)) !These offer better contrast.
INTEGER I !A stepper.
DO I = 1,UBOUND(A,DIM = 1) !Work down the given number of rows.
WRITE (6,"(666A1)") HIC(A(I,:)) !Roll a translated line.
END DO !Hopefully, no more than 666 to a line.
END SUBROUTINE SHOW !That was straightforward.
END MODULE ZhangSuenThinning
PROGRAM POKE !Just set up the example.
USE ZhangSuenThinning
INTEGER N,M !Parameters for the example.
PARAMETER (N = 10,M = 32) !Rows and columns.
CHARACTER*(M) CANVAS(N) !Rather than some monster DATA statement,
PARAMETER (CANVAS = (/ !It is easier to prepare a worksheet.
1 " ",
2 " 111111111 11111111 ",
3 " 111 1111 1111 1111 ",
4 " 111 111 111 111 ",
5 " 111 1111 111 ",
6 " 111111111 111 ",
7 " 111 1111 111 111 ",
8 " 111 1111 111 1111 1111 111 ",
9 " 111 1111 111 11111111 111 ",
o " "/))
INTEGER IMAGE(N,M) !The image array. Exactly the required size.
INTEGER I !A stepper.
DO I = 1,N !Read the rows.
READ (CANVAS(I),"(666I1)") IMAGE(I,:) !Presumably, 666 will suffice.
END DO !A blank is taken as a zero with formatted input.
WRITE (6,*) "The initial image..."
CALL SHOW(IMAGE)
WRITE (6,*)
CALL ZST(IMAGE)
WRITE (6,*) "And after 'thinning'..."
CALL SHOW(IMAGE)
END PROGRAM POKE

View file

@ -0,0 +1,106 @@
function Point(x, y) {
this.x = x;
this.y = y;
}
var ZhangSuen = (function () {
function ZhangSuen() {
}
ZhangSuen.image =
[" ",
" ################# ############# ",
" ################## ################ ",
" ################### ################## ",
" ######## ####### ################### ",
" ###### ####### ####### ###### ",
" ###### ####### ####### ",
" ################# ####### ",
" ################ ####### ",
" ################# ####### ",
" ###### ####### ####### ",
" ###### ####### ####### ",
" ###### ####### ####### ###### ",
" ######## ####### ################### ",
" ######## ####### ###### ################## ###### ",
" ######## ####### ###### ################ ###### ",
" ######## ####### ###### ############# ###### ",
" "];
ZhangSuen.nbrs = [[0, -1], [1, -1], [1, 0], [1, 1], [0, 1], [-1, 1], [-1, 0], [-1, -1], [0, -1]];
ZhangSuen.nbrGroups = [[[0, 2, 4], [2, 4, 6]], [[0, 2, 6], [0, 4, 6]]];
ZhangSuen.toWhite = new Array();
;
ZhangSuen.main = function (args) {
ZhangSuen.grid = new Array(ZhangSuen.image.length);
for (var r = 0; r < ZhangSuen.image.length; r++)
ZhangSuen.grid[r] = (ZhangSuen.image[r]).split('');
ZhangSuen.thinImage();
};
ZhangSuen.thinImage = function () {
var firstStep = false;
var hasChanged;
do {
hasChanged = false;
firstStep = !firstStep;
for (var r = 1; r < ZhangSuen.grid.length - 1; r++) {
for (var c = 1; c < ZhangSuen.grid[0].length - 1; c++) {
if (ZhangSuen.grid[r][c] !== '#')
continue;
var nn = ZhangSuen.numNeighbors(r, c);
if (nn < 2 || nn > 6)
continue;
if (ZhangSuen.numTransitions(r, c) !== 1)
continue;
if (!ZhangSuen.atLeastOneIsWhite(r, c, firstStep ? 0 : 1))
continue;
ZhangSuen.toWhite.push(new Point(c, r));
hasChanged = true;
}
}
for (let i = 0; i < ZhangSuen.toWhite.length; i++) {
var p = ZhangSuen.toWhite[i];
ZhangSuen.grid[p.y][p.x] = ' ';
}
ZhangSuen.toWhite = new Array();
} while ((firstStep || hasChanged));
ZhangSuen.printResult();
};
ZhangSuen.numNeighbors = function (r, c) {
var count = 0;
for (var i = 0; i < ZhangSuen.nbrs.length - 1; i++)
if (ZhangSuen.grid[r + ZhangSuen.nbrs[i][1]][c + ZhangSuen.nbrs[i][0]] === '#')
count++;
return count;
};
ZhangSuen.numTransitions = function (r, c) {
var count = 0;
for (var i = 0; i < ZhangSuen.nbrs.length - 1; i++)
if (ZhangSuen.grid[r + ZhangSuen.nbrs[i][1]][c + ZhangSuen.nbrs[i][0]] === ' ') {
if (ZhangSuen.grid[r + ZhangSuen.nbrs[i + 1][1]][c + ZhangSuen.nbrs[i + 1][0]] === '#')
count++;
}
return count;
};
ZhangSuen.atLeastOneIsWhite = function (r, c, step) {
var count = 0;
var group = ZhangSuen.nbrGroups[step];
for (var i = 0; i < 2; i++)
for (var j = 0; j < group[i].length; j++) {
var nbr = ZhangSuen.nbrs[group[i][j]];
if (ZhangSuen.grid[r + nbr[1]][c + nbr[0]] === ' ') {
count++;
break;
}
}
return count > 1;
};
ZhangSuen.printResult = function () {
for (var i = 0; i < ZhangSuen.grid.length; i++) {
var row = ZhangSuen.grid[i];
console.log(row.join(''));
}
};
return ZhangSuen;
}());
ZhangSuen.main(null);

View file

@ -0,0 +1,100 @@
// version 1.1.2
class Point(val x: Int, val y: Int)
val image = arrayOf(
" ",
" ################# ############# ",
" ################## ################ ",
" ################### ################## ",
" ######## ####### ################### ",
" ###### ####### ####### ###### ",
" ###### ####### ####### ",
" ################# ####### ",
" ################ ####### ",
" ################# ####### ",
" ###### ####### ####### ",
" ###### ####### ####### ",
" ###### ####### ####### ###### ",
" ######## ####### ################### ",
" ######## ####### ###### ################## ###### ",
" ######## ####### ###### ################ ###### ",
" ######## ####### ###### ############# ###### ",
" "
)
val nbrs = arrayOf(
intArrayOf( 0, -1), intArrayOf( 1, -1), intArrayOf( 1, 0),
intArrayOf( 1, 1), intArrayOf( 0, 1), intArrayOf(-1, 1),
intArrayOf(-1, 0), intArrayOf(-1, -1), intArrayOf( 0, -1)
)
val nbrGroups = arrayOf(
arrayOf(intArrayOf(0, 2, 4), intArrayOf(2, 4, 6)),
arrayOf(intArrayOf(0, 2, 6), intArrayOf(0, 4, 6))
)
val toWhite = mutableListOf<Point>()
val grid = Array(image.size) { image[it].toCharArray() }
fun thinImage() {
var firstStep = false
var hasChanged: Boolean
do {
hasChanged = false
firstStep = !firstStep
for (r in 1 until grid.size - 1) {
for (c in 1 until grid[0].size - 1) {
if (grid[r][c] != '#') continue
val nn = numNeighbors(r, c)
if (nn !in 2..6) continue
if (numTransitions(r, c) != 1) continue
val step = if (firstStep) 0 else 1
if (!atLeastOneIsWhite(r, c, step)) continue
toWhite.add(Point(c, r))
hasChanged = true
}
}
for (p in toWhite) grid[p.y][p.x] = ' '
toWhite.clear()
}
while (firstStep || hasChanged)
for (row in grid) println(row)
}
fun numNeighbors(r: Int, c: Int): Int {
var count = 0
for (i in 0 until nbrs.size - 1) {
if (grid[r + nbrs[i][1]][c + nbrs[i][0]] == '#') count++
}
return count
}
fun numTransitions(r: Int, c: Int): Int {
var count = 0
for (i in 0 until nbrs.size - 1) {
if (grid[r + nbrs[i][1]][c + nbrs[i][0]] == ' ') {
if (grid[r + nbrs[i + 1][1]][c + nbrs[i + 1][0]] == '#') count++
}
}
return count
}
fun atLeastOneIsWhite(r: Int, c: Int, step: Int): Boolean {
var count = 0;
val group = nbrGroups[step]
for (i in 0..1) {
for (j in 0 until group[i].size) {
val nbr = nbrs[group[i][j]]
if (grid[r + nbr[1]][c + nbr[0]] == ' ') {
count++
break
}
}
}
return count > 1
}
fun main(args: Array<String>) {
thinImage()
}

View file

@ -3,7 +3,7 @@ constant DEBUG = 1;
my @lines = ([.ords X+& 1] for lines); # The low bits Just Work.
my \v = +@lines;
my \h = +@lines[0];
my @black = @lines.map: *.values; # Flatten to 1-dimensional.
my @black = flat @lines.map: *.values; # Flatten to 1-dimensional.
my \p8 = [-h-1, -h+0, -h+1, # Flatland distances to 8 neighbors.
0-1, 0+1,
@ -11,7 +11,7 @@ my \p8 = [-h-1, -h+0, -h+1, # Flatland distances to 8 neighbors.
# Candidates have 8 neighbors and are known black
my @cand = grep { @black[$_] }, do
for 1..v-2 X 1..h-2 -> \y,\x { y*h + x }
for 1..v-2 X 1..h-2 -> (\y,\x) { y*h + x }
repeat while my @goners1 or my @goners2 {
sub seewhite (\w1,\w2) {

View file

@ -2,37 +2,37 @@ class ZhangSuen(str, black="1") {
const NEIGHBOURS = [[-1,0],[-1,1],[0,1],[1,1],[1,0],[1,-1],[0,-1],[-1,-1]] # 8 neighbors
const CIRCULARS = (NEIGHBOURS + [NEIGHBOURS.first]) # P2, ... P9, P2
has r = 0;
has image = [[]];
has r = 0
has image = [[]]
method init {
var s1 = str.lines.map{|line| line.chars.map{|c| c==black ? 1 : 0 }}
var s2 = s1.len.of { s1[0].len.of(0) }
var xr = RangeNum(1, s1.end-1)
var yr = RangeNum(1, s1[0].end-1)
var xr = range(1, s1.end-1)
var yr = range(1, s1[0].end-1)
do {
r = 0;
r = 0
xr.each{|x| yr.each{|y| s2[x][y] = (s1[x][y] - self.zs(s1,x,y,1)) }} # Step 1
xr.each{|x| yr.each{|y| s1[x][y] = (s2[x][y] - self.zs(s2,x,y,0)) }} # Step 2
} while !r.is_zero;
image = s1;
} while !r.is_zero
image = s1
}
method zs(ng,x,y,g) {
(ng[x][y] == 0) ->
|| (ng[x-1][y] + ng[x][y+1] + ng[x+g][y+g - 1] == 3) ->
|| (ng[x+g - 1][y+g] + ng[x+1][y] + ng[x][y-1] == 3) ->
&& return 0;
&& return 0
var bp1 = NEIGHBOURS.map {|p| ng[x+p[0]][y+p[1]] }.sum(0); # B(P1)
return 0 if ((bp1 < 2) || (6 < bp1));
var bp1 = NEIGHBOURS.map {|p| ng[x+p[0]][y+p[1]] }.sum # B(P1)
return 0 if ((bp1 < 2) || (6 < bp1))
var ap1 = 0;
CIRCULARS.map {|p| ng[x+p[0]][y+p[1]] }.each_cons(2, {|p|
++ap1 if (p[0] < p[1]) # A(P1)
var ap1 = 0
CIRCULARS.map {|p| ng[x+p[0]][y+p[1]] }.each_cons(2, {|a,b|
++ap1 if (a < b) # A(P1)
})
return 0 if (ap1 != 1);
return 0 if (ap1 != 1)
r = 1
}