CTSC23 公式编辑器.docx
《CTSC23 公式编辑器.docx》由会员分享,可在线阅读,更多相关《CTSC23 公式编辑器.docx(15页珍藏版)》请在冰豆网上搜索。
CTSC23公式编辑器
公式编辑器解题报告
湖南省长沙市长郡中学胡伟栋
问题简述:
给出键盘的一些操作,要求编一个程序模拟公式编辑器处理这些操作。
公式编辑器支持以下操作:
输入字符、插入分式、插入矩阵、插入一行或一列到矩阵中、光标上下左右移动、光标移到编辑框首、光标移到编辑框尾。
分析:
此题是一道很复杂的模拟题。
此题难点在于其对象的类型比较多:
有字符、矩阵和分式,同时操作比较多:
有光标的上下左右移动、Home、End,矩阵的增加行、列等。
且输出也比较麻烦。
解决此题主要是保持头脑清醒(这一点对做任何模拟题都非常重要)和选择好的数据结构。
这里,整个表达式很像一棵树的样子:
如果一个表达式不是整个表达式,则它必有一个直接的包含它的表达式,这就是它的父表达式;每个表达式都可能有0个或多个子表达式且子表达式之间没有直接关系。
可以用树结构来处理整个表达式。
此题是一个模拟题,不要用到多少算法,只要按照原题所说的一步一步做即可。
具体做法可见参考程序。
参考程序:
program
Maths;
{$ModeDelphi}//引用Delphi模式
const
inf='maths.in';//输入文件
ouf='maths.out';//输出文件
maxChars=100000;//输出的非空字符最大数
type
eleStyle=(eleChar,eleExp,eleMatrix,eleFraction);//表达式的类型
placeType=(pl_None,pl_Home,pl_End);//不移动/移到编缉框开始位置/移到编缉框结束位置
const
hs:
array[eleChar..eleFraction]ofinteger=(0,1,1,2);//不同表达式的初始行数
ws:
array[eleChar..eleFraction]ofinteger=(0,0,1,1);//不同表达式的初始列数
moveSetPlace:
array[-1..1]ofplaceType=(pl_End,pl_None,pl_Home);//向左(-1)/右
(1)移动到子编辑框的位置
ifEnd:
array[-1..1]ofinteger=(1,0,0);//向左(-1)/右
(1)移动是否会到子编辑框的结束位置
canMin:
array[eleChar..eleFraction]ofinteger=(0,0,1,1);//编辑框的光标能向左移的最小位置
type
canvasType=object//所有非空字符输出队列
l:
integer;//字符数
pos:
array[-1..maxChars,1..2]ofinteger;//输出位置
chars:
array[0..maxChars]ofchar;//输出字符,#0表示分数线
procedurePrintChar(y,x:
integer;ch:
char);//在第y行第x列输出一个字符ch
proceduresort(_From,_To:
integer);//将字符按行列位置排序
procedureSave(fileName:
string);//输出到文件
end;
eleType=class//表达式的基类
fParent:
eleType;//父达式
fStyle:
eleStyle;//表达式类型
h,w:
integer;//h为行数,w为列数
pos:
array[1..2]ofinteger;//若当前编辑焦点在这个表达式的子表达式中,则指向对应子表达式的位置
Width,Height,UpHeight,DownHeight:
integer;//输出宽度,高度,对齐行上方的高度,对齐行下方的高度
constructorcreate(parent:
eleType;style:
eleStyle);//构造类并初始化
functiongetS(y,x:
integer):
eleType;//取得y行x列的子表达式
proceduresetS(y,x:
integer;Value:
eleType);//设置y行x列的子表达式
proceduresetFocus(place:
placeType);//设置编辑焦点
proceduremoveHome;//光标移动到行首(虽然只可能在expType子类中调用此过程,但为了便于调用,将它放在基类中)
proceduremoveEnd;//光标移动到行尾(虽然只可能在expType子类中调用此过程,但为了便于调用,将它放在基类中)
proceduremoveUpOrDown(incs:
integer);//光标上移(incs=-1)或下移(incs=1)一行
proceduremoveLeftOrRight(incs:
integer);//光标左移(incs=-1)或右移(incs=1)一行
procedureAddCol;//添加一列
procedureAddRow;//添加一行
procedureAddOne(ele:
eleType);//将一个表达式添加到光标位置(虽然只可能在expType子类中调用此过程,但为了便于调用,将它放在基类中)
proceduregetPrintMessage;//得到输出的信息(应输出行数、列数等)
procedurePrint(HCenter,Left:
integer);//将表达式输出到输出队列中
propertys[y,x:
integer]:
eleTypereadgetSwritesetS;//子表达式。
这是一个属性,取值时相当于调用getS(y,x);给它赋值时相当于调用setS(y,x,value),其中value为所赋的值
end;
charType=class(eleType)//字符子类
Dat:
char;//所存储的运算数或运算符
end;
expType=class(eleType)//编辑框子类
fs:
array[1..1,1..500]ofeleType;//编辑框内的子表达式
end;
matrixType=class(eleType)//矩阵子类
fs:
array[1..10,1..10]ofeleType;//矩阵中的子表达式
Heights,UpHeights,DownHeights,Widths:
array[1..10]ofinteger;//输出时每行对应的高度、对齐行上方的高度、对齐行下方的高度及每列对应的最大宽度
end;
fractionType=class(eleType)//分式子类
fs:
array[1..2,1..1]ofeleType;//分式中的子表达式
end;
var
root,//整个表达式
action:
eleType;//当前的焦点表达式
screen:
canvasType;//输出队列
functionmax(a,b:
integer):
integer;//求a,b的最大值
begin
ifa>bthenmax:
=aelsemax:
=b;
end;
procedurecanvasType.PrintChar(y,x:
integer;ch:
char);
begin
ifch='-'theninc(x)else
ifch=#0thench:
='-';
inc(l);
pos[l,1]:
=y;pos[l,2]:
=x;
chars[l]:
=ch;
end;
procedurecanvasType.sort(_From,_To:
integer);
var
i,j:
integer;
begin
i:
=_From;j:
=_To;pos[-1]:
=pos[(i+j)shr1];
whilei<=jdo
begin
while(pos[i,1]while(pos[j,1]>pos[-1,1])or(pos[j,1]=pos[-1,1])and(pos[j,2]>pos[-1,2])dodec(j);
ifi<=jthen
begin
pos[0]:
=pos[i];pos[i]:
=pos[j];pos[j]:
=pos[0];
chars[0]:
=chars[i];chars[i]:
=chars[j];chars[j]:
=chars[0];
inc(i);dec(j);
end;
end;
ifj>_Fromthensort(_From,j);
ifi<_Tothensort(i,_To);
end;
procedurecanvasType.Save(fileName:
string);
var
cur:
array[1..2]ofinteger;
i,j:
integer;
begin
sort(1,l);
assign(output,fileName);rewrite(output);
cur[1]:
=1;cur[2]:
=1;
fori:
=1toldo
begin
ifcur[1]<>pos[i,1]thencur[2]:
=1;
forj:
=cur[1]+1topos[i,1]do
writeln;
write(chars[i]:
pos[i,2]-cur[2]+1);
cur[1]:
=pos[i,1];
cur[2]:
=pos[i,2]+1;
end;
writeln;
close(output);
end;
constructoreleType.create(parent:
eleType;style:
eleStyle);
var
i:
integer;
begin
fParent:
=parent;
fStyle:
=style;
h:
=hs[style];
w:
=ws[style];
pos[1]:
=1;
pos[2]:
=1;
if(fStyle=eleMatrix)or(fStyle=eleFraction)then//如果是矩阵或分式,则一开始就应该有1或2个子编辑框
fori:
=1tohdo
s[i,1]:
=expType.create(self,eleExp);
end;
functioneleType.getS(y,x:
integer):
eleType;
begin
casefStyleof//对不同的子类得到第y行第x列的子表达式
eleExp:
getS:
=expType(self).fs[y,x];
eleMatrix:
getS:
=matrixType(self).fs[y,x];
eleFraction:
getS:
=fractionType(self).fs[y,x];
elsegetS:
=nil;
end;
end;
procedureeleType.setS(y,x:
integer;value:
eleType);
begin
casefStyleof//对不同的子类设置第y行第x列的子表达式
eleExp:
expType(self).fs[y,x]:
=value;
eleMatrix:
matrixType(self).fs[y,x]:
=value;
eleFraction:
fractionType(self).fs[y,x]:
=value;
end;
end;
procedureeleType.setFocus(place:
placeType);
begin
action:
=self;
caseplaceof//设置焦点时可顺便确定光标位置
pl_Home:
moveHome;
pl_End:
moveEnd;
end;
end;
procedureeleType.moveHome;
begin
pos[2]:
=0;
end;
procedureeleType.moveEnd;
begin
pos[2]:
=w;
end;
procedureeleType.moveUpOrDown(incs:
integer);
begin
if(pos[1]+incs>=1)and(pos[1]+incs<=h)then//当前表达式可以上/下移动则移动
begin
inc(pos[1],incs);
s[pos[1],pos[2]].setFocus(pl_Home);
end
else//当前表达式不可上/下移动则由上一级表达式移动
iffParent<>nilthen
fParent.moveUpOrDown(incs);
end;
procedureeleType.moveLeftOrRight(incs:
integer);
procedureparentMove;//使用上一级表达式移动
begin
iffParent<>nilthen
begin
iffParent.fStyle=eleExpthen
begin
ifincs=-1thendec(fParent.pos[2]);
incs:
=0;
end;
fParent.moveLeftOrRight(incs);
end;
end;
var
p:
integer;
begin
ifincs=0thensetFocus(pl_None)else
if(pos[2]+incsw)thenparentMoveelse//如果当前表达式不能移动,则使用上一级表达式移动
casefStyleof
eleExp:
begin
p:
=max(pos[2],pos[2]+incs);
cases[pos[1],p].fStyleof//如果子表达式是矩阵或分式,则将光标移到子表达式中,否则直接改变光标位置
eleMatrix,eleFraction:
begin
pos[2]:
=p;
withs[pos[1],p]do
begin
pos[1]:
=(h+1)shr1;
pos[2]:
=(1+ifEnd[incs]*(w-1));
s[pos[1],pos[2]].setFocus(moveSetPlace[incs]);
end;
end;
elseinc(pos[2],incs);
end;
end;
eleMatrix:
begin
inc(pos[2],incs);
s[pos[1],pos[2]].setFocus(moveSetPlace[incs]);
end;
elseparentMove;//分式要使用上一级表达式移动
end;
end;
procedureeleType.AddRow;
var
i,j:
integer;
begin
iffStyle=eleMatrixthen//如果当前是一个矩阵,则添加一行,否则看上一级表达式能否添加行
begin
fori:
=hdowntopos[1]do
forj:
=1towdo
s[i+1,j]:
=s[i,j];
inc(h);
forj:
=1towdo
s[pos[1],j]:
=expType.create(self,eleExp);
s[pos[1],pos[2]].setFocus(pl_Home);
end
else
iffParent<>nilthenfParent.AddRow;
end;
procedureeleType.AddCol;
var
i,j:
integer;
begin
iffStyle=eleMatrixthen//如果当前是一个矩阵,则添加一列,否则看上一级表达式能否添加列
begin
forj:
=wdowntopos[2]do
fori:
=1tohdo
s[i,j+1]:
=s[i,j];
inc(w);
fori:
=1tohdo
s[i,pos[2]]:
=expType.create(self,eleExp);
s[pos[1],pos[2]].setFocus(pl_Home);
end
else
iffParent<>nilthenfParent.AddCol;
end;
procedureeleType.AddOne(ele:
eleType);
var
i:
integer;
begin
fori:
=wdowntopos[2]+1do
s[1,i+1]:
=s[1,i];
inc(w);
s[1,pos[2]+1]:
=ele;
moveLeftOrRight
(1);
end;
procedureeleType.getPrintMessage;
var
i,j:
integer;
begin
Width:
=0;UpHeight:
=0;DownHeight:
=0;
casefStyleof
eleChar:
begin
UpHeight:
=0;DownHeight:
=0;
ifcharType(self).Dat='-'thenWidth:
=3elseWidth:
=1;
end;
eleExp:
fori:
=1towdo
begin
s[1,i].getPrintMessage;
inc(Width,s[1,i].Width);
UpHeight:
=max(UpHeight,s[1,i].UpHeight);
DownHeight:
=max(DownHeight,s[1,i].DownHeight);
end;
eleMatrix:
withmatrixType(self)do
begin
fillchar(UpHeights,sizeof(UpHeights),0);
fillchar(DownHeights,sizeof(DownHeights),0);
fillchar(Widths,sizeof(Widths),0);
fori:
=1tohdo
begin
forj:
=1towdo
begin
s[i,j].getPrintMessage;
UpHeights[i]:
=max(UpHeights[i],s[i,j].UpHeight);
DownHeights[i]:
=max(DownHeights[i],s[i,j].DownHeight);
Widths[j]:
=max(Widths[j],s[i,j].Width);
end;
Heights[i]:
=UpHeights[i]+DownHeights[i]+1;
end;
fori:
=1towdo
inc(Width,Widths[i]+1);
inc(Width);
fori:
=1tohshr1do
inc(UpHeight,Heights[i]+1);
dec(UpHeight);
ifodd(h)then
inc(UpHeight,1+UpHeights[hshr1+1]);
fori:
=hdowntoh-hshr1+1do
inc(DownHeight,Heights[i]+1);
dec(DownHeight);
ifodd(h)then
inc(DownHeight,1+DownHeights[hshr1+1]);
end;
eleFraction:
begin
s[1,1].getPrintMessage;
s[2,1].getPrintMessage;
UpHeight:
=s[1,1].Height;
DownHeight:
=s[2,1].Height;
Width:
=max(s[1,1].Width,s[2,1].Width)+2;
end;
end;
Height:
=UpHeight+DownHeight+1;
end;
procedureeleType.Print(HCenter,Left:
integer);
var
Top,L,i,j:
integer;
begin
casefStyleof
eleChar:
Screen.PrintChar(HCenter,Left,charType(self).Dat);
eleExp:
fori:
=1towdo
begin
s[1,i].Print(HCenter,Left);
inc(Left,s[1,i].Width);
end;
eleMatrix:
withmatrixType(self)do