100 一个趣味循环编程练习

发布于 2026-01-31 21:51:59

如题,希望实现如下的表格的自动化排版。

代码越简洁、越高度自动化、越具有强拓展性越好。

对具体的实现方法不做任何限制~优雅即可

image.png

划去线的逻辑不必与此相同(我觉得涂色似乎更显眼,在tabularray框架里应该也更容易实现),能体现不同的条件判断即可。

image.png

由于我也会试试,这里暂不给出MWE.

查看更多

关注者
0
被浏览
256
4 个回答
shadow
shadow 2天前
这个人懒得不得了,竟然啥也没写

用 tikz 实现。

\documentclass[tikz,border=1cm]{standalone}
\begin{document}

\begin{tikzpicture}[
  cell/.style={
    draw,
    line width=0.8pt,
    minimum width=7.2mm,
    minimum height=6mm,
    inner sep=0pt,
    font=\small
  }
]

\def\inset{1mm}

\foreach \x in {1,...,100} {

  
  \pgfmathsetmacro{\row}{int((\x-1)/10)}
  \pgfmathsetmacro{\col}{int((\x-1) - 10*\row)}

  
  \node[cell] (N\x) at ({7.2mm*\col},{-6mm*\row}) {\x};

  
  \ifnum\x=2\relax\else
  \ifnum\x=3\relax\else
  \ifnum\x=5\relax\else
  \ifnum\x=7\relax\else

    
    \pgfmathtruncatemacro{\mii}{mod(\x,2)}
    \ifnum\mii=0
      \draw[thick]
        ([xshift=\inset,yshift=-\inset]N\x.north west) --
        ([xshift=-\inset,yshift=\inset]N\x.south east);

    \else
     
      \pgfmathtruncatemacro{\miii}{mod(\x,3)}
      \ifnum\miii=0
        \draw[thick]
          ([xshift=-\inset,yshift=-\inset]N\x.north east) --
          ([xshift=\inset,yshift=\inset]N\x.south west);

      \else
       
        \pgfmathtruncatemacro{\mv}{mod(\x,5)}
        \ifnum\mv=0
          \draw[thick]
            ([xshift=\inset,yshift=-\inset]N\x.north west) --
            ([xshift=-\inset,yshift=\inset]N\x.south east);
          \draw[thick]
            ([xshift=-\inset,yshift=-\inset]N\x.north east) --
            ([xshift=\inset,yshift=\inset]N\x.south west);

        \else
         
          \pgfmathtruncatemacro{\mvii}{mod(\x,7)}
          \ifnum\mvii=0
            \draw[thick]
              ([xshift=\inset]N\x.west) --
              ([xshift=-\inset]N\x.east);
          \fi
        \fi
      \fi
    \fi

  \fi\fi\fi\fi
}

\end{tikzpicture}

\end{document}

image.png

Sagittarius Rover
这家伙很懒,什么也没写!

基于tabularray的一个自动化方案...

\documentclass{article}
\usepackage{fourier}
\usepackage{xcolor}
\usepackage{tabularray}
\UseTblrLibrary{functional}
\IgnoreSpacesOn
\prgNewFunction \makeHundredCells { } {
  \tlSet \lTmpaTl { } 
  \intStepOneInline {1} {100} {
    \intCaseF { ##1 } {
        { 2 } {  }
        { 3 } {  }
        { 5 } {  }
        { 7 } {  }
    } {
        \intCompareTF { \intMathMod{##1}{2}  } = { 0 } {
          \tlPutRight \lTmpaTl { \SetCell{bg=magenta!50} } 
        }{
            \intCompareTF { \intMathMod{##1}{3} } = { 0 } {
              \tlPutRight \lTmpaTl { \SetCell{bg=cyan!50} } 
            }
            {
                \intCompareTF { \intMathMod{##1}{5} } = { 0 } {
                  \tlPutRight \lTmpaTl { \SetCell{bg=violet!50} } 
                }
                {
                    \intCompareT { \intMathMod{##1}{7} } = { 0 } {
                      \tlPutRight \lTmpaTl { \SetCell{bg=orange!50} } 
                    }
                }
            }
        }
      }
     \intCompareTF { ##1 } = { 1 } {
        \tlPutRight \lTmpaTl { } 
      }{
        \tlPutRight \lTmpaTl { ##1 }
      }
    \intCompareTF { \intMathMod{##1}{10} } = { 0 } {
      \tlPutRight \lTmpaTl { \\ } 
    }{
      \tlPutRight \lTmpaTl { & }
    }
  }
  \prgReturn { \expValue \lTmpaTl }
}
\IgnoreSpacesOff

\begin{document}

\begin{tblr}[evaluate=\makeHundredCells]{
        colspec = {*{10}{X[c]}},
        hlines, vlines,
        rows = {m, ht=3em},
    }
    \makeHundredCells 
\end{tblr}

\end{document}

或者等价的,用逻辑划分更清晰的evaluate = \makeTableBodyprocess = \myTblrProcessor分别控制内容和样式

\documentclass{article}
\usepackage{fourier}
\usepackage{xcolor}
\usepackage{tabularray}
\UseTblrLibrary{functional}
\IgnoreSpacesOn
\tlNew \lBodyTl
\tlNew \lCellValueTl
\prgNewFunction \makeTableBody { } {
  \tlClear \lBodyTl
  \intStepOneInline {1} {100} {
    \tlPutRight \lBodyTl { ##1 }
    \intCompareTF { \intMathMod{##1}{10} } = { 0 } {
      \tlPutRight \lBodyTl { \\ }
    }{
      \tlPutRight \lBodyTl { & }
    }
  }
  \prgReturn { \expValue \lBodyTl }
}
\prgNewFunction \myTblrProcessor { } {
  \intStepOneInline {1} {\arabic{rowcount}} {
    \intStepOneInline {1} {\arabic{colcount}} {
      \tlSet \lCellValueTl { \cellGetText {##1} {####1} }
        \intCompareT { \lCellValueTl } = { 1 } {
          \cellSetText {##1} {####1} { }
        }
        \intCaseF { \lCellValueTl } {
            { 2 } { } { 3 } { } { 5 } { } { 7 } { }
        } {
            \intCompareTF { \intMathMod{\lCellValueTl}{2} } = { 0 } {
              \cellSetStyle {##1} {####1} { bg=magenta!50 }
            }{
              \intCompareTF { \intMathMod{\lCellValueTl}{3} } = { 0 } {
                \cellSetStyle {##1} {####1} { bg=cyan!50 }
              }{
                \intCompareTF { \intMathMod{\lCellValueTl}{5} } = { 0 } {
                  \cellSetStyle {##1} {####1} { bg=violet!50 }
                }{
                  \intCompareT { \intMathMod{\lCellValueTl}{7} } = { 0 } {
                    \cellSetStyle {##1} {####1} { bg=orange!50 }
                  }
                }
              }
            }
        }
    }
  }
}
\IgnoreSpacesOff

\begin{document}

\begin{tblr}[
    evaluate = \makeTableBody
]{
  colspec = {*{10}{X[c]}},
  hlines, vlines,
  rows = {m, ht=3em},
  process = \myTblrProcessor
}
  \makeTableBody
\end{tblr}

\end{document}

image.png

Absinthe
Absinthe 2天前
这家伙很懒,什么也没写!

基于 asymptote 的一个回答:

settings.outformat="pdf"; 
unitsize(1cm);
import primetable;
int nums=100; int cols=10; real dx=1; real dy=0.6;

markPrimeTable(nums,cols,dx,dy,lineMarkers);

newpage();

markPrimeTable(nums,cols,dx,dy,ploymarkers(getPrimeFactors(nums).length));

newpage();

labelPrimeTable(nums,cols,dx,dy,randrgbs(getPrimeFactors(nums).length));

image.png
image.png
image.png

还可以:

settings.outformat="pdf"; 
unitsize(1cm);
import primetable;
int nums=1000; int cols=50; real dx=1; real dy=0.6;

// markPrimeTable(nums,cols,dx,dy,lineMarkers);

// newpage();

markPrimeTable(nums,cols,dx,dy,ploymarkers(getPrimeFactors(nums).length));

newpage();

labelPrimeTable(nums,cols,dx,dy,randrgbs(getPrimeFactors(nums).length));

image.png
image.png

primetable.asy 如下(包含结构体)

private from math access grid;

/*======== 画笔/标注 =========*/
pen[] randrgbs(int n) {
    return sequence(new pen(int){return rgb(unitrand(),unitrand(),unitrand());},n);
}

real defaultangle=45; real defaultxscale=0.5; real defaultyscale=10;

pen NWLine(real angle=defaultangle, real xscale=defaultxscale, real yscale=defaultyscale) {
    return makepen(rotate(angle)*scale(xscale,yscale)*polygon(4));
}
pen NELine(real angle=-defaultangle, real xscale=defaultxscale, real yscale=defaultyscale) {
    return makepen(rotate(angle)*scale(xscale,yscale)*polygon(4));
}
pen NWNELine(real angle=defaultangle, real xscale=defaultxscale, real yscale=defaultyscale) {
    path NWLine=rotate(angle)*scale(xscale,yscale)*polygon(4);
    path NELine=rotate(-angle)*scale(xscale,yscale)*polygon(4);

    real[][] inters=intersections(NWLine,NELine);
    path p=subpath(NELine,inters[1][1],inters[0][1]);

    real[][] inters=intersections(NELine,NWLine);
    path q=subpath(NWLine,inters[2][1],inters[3][1]);

    return makepen(buildcycle(p,q,rotate(180)*p,rotate(180)*q));
}
pen HLine(real xscale=defaultxscale, real yscale=defaultyscale) {
    return makepen(rotate(90)*scale(xscale,yscale)*polygon(4));
}
pen ploypen(int N, real angle=0, real xscale=1, real yscale=1) {
    return makepen(rotate(angle)*scale(xscale,yscale)*polygon(N));
}

pen NWLine=NWLine();
pen NELine=NELine();
pen NWNELine=NWNELine();
pen HLine=HLine();

pen[] lineMarkers=new pen[] {NELine,NWLine,NWNELine,HLine};
pen[] ploymarkers(int n, real scalefactor=6) {
    return sequence(new pen(int i) {return scale(scalefactor)*ploypen(i+3)+opacity(0.4);},n);
}

/*======== 素数判断 =========*/
// 判断是否是素数
bool isPrime(int n) {
    if (n <= 1) { return false; }
    else if ( n == 2) { return true; }
    else if ( n % 2 == 0 ) { return false; }
    else {
        for (int i=3; i<= ceil(sqrt(n)); i+=2) {
            if (n % i == 0) {
                return false;
            }
        }
        return true;
    }
}

// 素因子
int[] getPrimeFactors(int n) {
    int[] op;
    for (int i=1; i<=ceil(sqrt(n)); ++i) {
        if (isPrime(i)) { op.push(i); }
    }
    return op;
}

/*======== 标记/标注表格 =========*/
// 标注数字
void labelnumber(int i, int cols, real dx, real dy, pen p=currentpen) {
    label("$"+(string)i+"$",scale(dx,dy)*((i-1) % cols, -quotient(i-1,cols)),p);
}
// 标记数字
void marknumber(int i, int cols, real dx, real dy, pen p=currentpen) {
    draw("$"+(string)i+"$",scale(dx,dy)*((i-1) % cols, -quotient(i-1,cols)),p);
}
// 绘制表格
void drawTable(int nums, int cols, real dx, real dy) {
    int rows=ceil(nums/cols);
    add(shift(0,-rows*dy)*shift(-0.5dx,0.5dy)*scale(dx,dy)*grid(cols,rows));
}

// 标注素数表格
void markPrimeTable(int nums, int cols, real dx, real dy, pen[] pens) {
    int[] primes=getPrimeFactors(nums);
    drawTable(nums,cols,dx,dy);
    for (int i=2; i<=nums; ++i) {
        bool[] b=sequence(new bool(int j) {return i % primes[j] ==0; }, primes.length);
        int j=find(b);
        if (j == -1) {
            marknumber(i,cols,dx,dy,linewidth(0));
        } else {
            marknumber(i,cols,dx,dy,(i == primes[j] ? nullpen : pens[j]));
        }
    }
}

// 标注素数表格
void labelPrimeTable(int nums, int cols, real dx, real dy, pen[] pens) {
    int[] primes=getPrimeFactors(nums);
    drawTable(nums,cols,dx,dy);
    for (int i=2; i<=nums; ++i) {
        bool[] b=sequence(new bool(int j) {return i % primes[j] ==0; }, primes.length);
        int j=find(b);
        if (j == -1) {
            labelnumber(i,cols,dx,dy,linewidth(0));
        } else {
            labelnumber(i,cols,dx,dy,(i == primes[j] ? nullpen : pens[j]));
        }
    }
}

struct primetable {
    int nums;
    int cols;
    int rows;
    real dx;
    real dy;
    int[] primefactors;
    
    void operator init(int nums, int cols, real dx, real dy) {
        this.nums=nums;
        this.cols=cols;
        this.rows=ceil(nums / cols);
        this.dx=dx;
        this.dy=dy;
        this.primefactors=getPrimeFactors(nums);
    }
}

void mark(primetable pt, pen[] pens) {
    drawTable(pt.nums,pt.cols,pt.dx,pt.dy);
    for (int i=2; i<=pt.nums; ++i) {
        bool[] b=sequence(new bool(int j) {return i % pt.primefactors[j] == 0; }, pt.primefactors.length);
        int j=find(b);
        if (j == -1) {
            marknumber(i,pt.cols,pt.dx,pt.dy,linewidth(0));
        } else {
            marknumber(i,pt.cols,pt.dx,pt.dy,(i == pt.primefactors[j] ? nullpen : pens[j]));
        }
    }
}

void label(primetable pt, pen[] pens) {
    drawTable(pt.nums,pt.cols,pt.dx,pt.dy);
    for (int i=2; i<=pt.nums; ++i) {
        bool[] b=sequence(new bool(int j) {return i % pt.primefactors[j] == 0; }, pt.primefactors.length);
        int j=find(b);
        if (j == -1) {
            marknumber(i,pt.cols,pt.dx,pt.dy,linewidth(0));
        } else {
            marknumber(i,pt.cols,pt.dx,pt.dy,(i == pt.primefactors[j] ? nullpen : pens[j]));
        }
    }
}

利用结构体 primetable 可以较为简洁的绘出

settings.outformat="pdf"; 
unitsize(1cm);
import primetable;
int nums=100; int cols=10; real dx=1; real dy=0.6;
primetable pt=primetable(nums,cols,dx,dy);

mark(pt,lineMarkers);

newpage();

defaultangle=aTan(dx/dy); defaultyscale=15;
pen[] lineMarkers={NELine(),NWLine(),NWNELine(),HLine()};
mark(pt,lineMarkers); newpage();

real angle=aTan(dx/dy); real xscale=0.5; real yscale=15; 
pen[] mylineMarkers2={NELine(-angle,xscale,yscale),
                      NWLine(angle,xscale,yscale),
                      NWNELine(angle,xscale,yscale),
                      HLine(xscale,yscale)};
mark(pt,mylineMarkers2); newpage();

mark(pt,ploymarkers(pt.primefactors.length)); newpage();

label(pt,randrgbs(pt.primefactors.length));

image.png

image.png

image.png

image.png

image.png

撰写答案

请登录后再发布答案,点击登录

发布
问题

分享
好友

手机
浏览

扫码手机浏览