通过 LinkedList 实现撤消/重做功能

2024-04-06

我正在编写自己的“魔方”应用程序。主要班级Cube有18种旋转方式:

  • RotateAxisXClockWise、RotateAxisXAntiClockWise
  • 顺时针旋转轴 Y、逆时针旋转轴 Y
  • RotateAxisZClockWise、RotateAxisZAntiClockWise

  • 顺时针旋转UpperFace、逆时针旋转UpperFace

  • 顺时针旋转正面、逆时针旋转正面
  • 顺时针旋转右面、逆时针旋转右面
  • RotateBackFace顺时针、RotateBackFace逆时针
  • 顺时针旋转左面、逆时针旋转左面
  • 顺时针旋转下脸、逆时针旋转下脸

是的,它们可以通过参数 Direction 成对连接(例如RotateFrontFace(Direction direction))但目前看来这似乎是合适的。

我想实现撤消/重做功能,并且因为所有方法都具有相同的签名(没有输入参数,无效返回类型),所以它们可以保存在 LinkedList 数据结构中。因此,每次调用其中一种旋转方法时,都会将其添加到链表中。

如果我们从 LinkedList 的开头开始(虽然还没有尝试过)并向结尾前进,那么这将非常有效,因此每次旋转都将完全按照最初的方式执行。

但是撤消呢?如果我从末尾到开头遍历列表,那么应该调用相反的方法(例如,而不是RotateFrontFaceClockWise, RotateFrontFaceAntiClockWise应该调用)。有什么想法如何实施吗?优雅? :)


我不会使用委托引用作为旋转建模的方式,如果主要目的之一是能够执行重做/撤消。我会考虑为每次轮换创建一个数据模型,并存储这些轮换步骤的列表。然后,每个步骤都可以有其自己关联的重做/撤消委托,这允许某人(从任一端)遍历列表以了解发生了哪些操作,并重复或反转它们。

使用面向数据的方法对此类转换进行建模的另一个好处是,它可能会减少类似(但略有不同)版本的数量。RotateXXX( )方法。

编辑:解决您关于这种解决方案可能采取什么形式的问题。

最简单的事情可能是存储Tuple<Action,Action>将每对旋转/取消旋转操作表示为成对的委托。但是,我会考虑使用显式数据结构来描述旋转操作,也许最终包括描述性名称、方向/面属性等。我也会改变你的RotateXXX方法,以便它们是静态方法Cube,并接受一个立方体实例作为参数。这将允许在实例外部对旋转操作进行建模Cube.

public sealed class Rotation
{
    private readonly Action<Cube> _RotateAction;
    private readonly Action<Cube> _UnrotateAction;  // used for undo or backtracking

    private Rotation( Action<Cube> rotateAction, Action<Cube> unrotateAction )
    {
        _RotateAction = rotateAction;
        _UnrotateAction = unrotateAction;
    }

    public void Rotate( Cube cube )   { _RotateAction( cube ); }

    public void Unrotate( Cube cube ) { _Unrotate( cube ); }

    public static readonly RotateFrontFaceClockswise = 
        new Rotation( Cube.RotateFrontFaceClockwise
                      Cube.RotateFrontFaceCounterClockwise );

    public static readonly RotateFrontFaceCounterClockwise = 
        new Rotation( Cube.RotateFrontFaceCounterClockwise,
                      Cube.RotateFrontFaceClockwise );

    public static readonly RotateLeftFaceClockwise = 
        new Rotation( Cube.RotateLeftFaceClockwise,
                      Cube.RotateLeftFaceCounterClockwise );

    public static readonly RotateLeftFaceCounterClockwise = 
        new Rotation( Cube.RotateLeftFaceCounterClockwise,
                      Cube.RotateLeftFaceClockwise );
    // etc..
}

// now we can keep track of the state changes of a cube using:
List<Rotation> cubeRotations = new List<Rotation>();
cubeRotations.Add( Rotation.RotateFrontFaceCounterClockwise );
cubeRotations.Add( Rotation.RotateBackFaceClockwise );
cubeRotations.Add( Rotation.RotateLeftFaceCounterClockwise );

// to apply the rotations to a cube, you simple walk through the data structure
// calling the Rotate( ) method on each:
Cube someCube = new Cube( ... )
foreach( Rotation r in cubeRotations )
{
    r.Rotate( someCube );
}

// to undo these rotations you can walk the like in reverse:
foreach( Rotation r in cubeRotations.Reverse() )
{
    r.Unrotate( someCube );
}
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

通过 LinkedList 实现撤消/重做功能 的相关文章

  • C++ win32设置光标位置

    我知道要使用哪个功能 但我无法让它正常工作 我用了SetCursorPos 唯一的问题是它将光标设置为屏幕坐标而不是窗口坐标 我也尝试过ScreenToClient 但它并没有起作用 这是我的代码 pt x 113 pt y 280 Scr
  • 获取 WSA 错误代码的格式化消息

    我在 win32 C 应用程序中使用winsock2 我将使用 MessageBox 显示可以通过调用 WSAGetLastError 检索的网络错误 我怎样才能做到这一点 我看到 FormatMessage 但我不明白如何使用它 例如 以
  • C# Socket.receive连续接收0字节且循环中不阻塞

    我正在尝试用 C 编写一个最简单的多线程 TCP 服务器 它接收来自多个客户端的数据 每次连接新客户端时 都会建立套接字连接 并将套接字作为参数传递给新类函数 之后运行 while 循环并接收数据 直到客户端连接为止 这里的问题是 sock
  • 如何解决“HTTP 错误 404.3 - 未找到”错误?

    简单的问题 我启动 VS2008 并创建一个新的 WCF 服务应用程序 这将创建一个默认应用程序 并使用一些测试方法来显示它的工作原理 我按 CTRL F5 确实有效 伟大的 但是 它使用 Visual Studio 开发服务器 我不想支持
  • Windows Server / Datacenter:设置 CPU 关联性 > 64 个核心

    SetThreadAffinityMask 允许为 64 个逻辑核心 处理器 设置关联掩码 但是 Windows Datacenter 最多可以有 64 个 CPU 每个 CPU 都有多个内核 请参阅here http social tec
  • Linux 缓冲区溢出环境变量

    我一直在审查不同类型的缓冲区溢出 并遇到了一个我不记得为什么会发生的问题 下面的代码是我尝试执行缓冲区溢出的程序 include
  • JObject ToString 与 StringEnumConverter 不起作用

    我正在尝试序列化一个匿名类 如下所示 public enum ErrorCode A B C var response JObject FromObject new Error new Message Test Code ErrorCode
  • 如何设置属性选择器的值 Expression>

    我需要使用模式工厂的想法将 Person 类实体中的实体属性 Address 与 FactoryEntities 类中的表达式 linq 相关联 看看这就是我所拥有的并且我想要做的 Address address new Address a
  • 在 WinForms 中显示输入对话框

    我想在我的 WinForm 应用程序中显示输入模式 我浏览过网络 但没有找到执行此操作的良好模式 我知道我必须创建另一个表单 并使用 ShowDialog 方法 你是对的 请注意 模式对话框在关闭时不会自动处理 与非模式对话框不同 因此您需
  • 在 C++ 中重用异常处理代码

    我有这两个函数 具有重复的异常处理 其唯一目的是显示错误消息 void func1 noexcept try do task do another task catch const std out of range e show msg O
  • boost::unordered_map 是...有序的吗?

    我有一个 boost unordered map 但它看起来是有序的 给我一种压倒性的 你做错了 的感觉 为什么输出是这样的 我希望底层的哈希算法能够随机化这个顺序 include
  • 提高 ASP.NET/C# 编译速度的最佳方法是什么?

    更新 请将您的答案集中在硬件解决方案上 您使用什么硬件 工具 插件来提高 ASP NET 编译和首次执行速度 我们正在寻找固态硬盘来加快速度 但现在价格确实很高 我现在有两个 RAID 0 的 7200 rpm 硬盘 但我对性能不再满意 所
  • std::atomic 是否会阻止非原子变量对原子变量进行重新排序

    问题很简单 问 如果我有 settings N STNGS used by many threads std atomic
  • 如何存储生成的格式化 C 字符串

    这是一个新手问题 为了创建格式化的 C 字符串 我使用printf like int n 10 printf My number is i 10 但是 怎么样 int n 10 char msg My number is i 10 prin
  • 如何对具有无效值的属性使用 JSON.net 的默认值

    我正在使用 Newtonsoft JSON 库来反序列化来自 Web 服务的响应 问题是某些字段包含无效值 例如 一条记录上的一个字段包含一个 T 表示该字段应该是数字 我想做的是将无效字段的值设置为 null 或其他默认值 我的所有属性都
  • Windows Phone 8.1 应用程序多语言

    我正在使用 Visual Studio 2015 在 SilverLight 中创建 Windows Phone 应用程序 8 1 我正在用英语和阿拉伯语创建多语言应用程序 为此 我在项目中创建了 Strings 文件夹 其中包含 en U
  • 如何在 .NET 6.0 中使用最小 Api 配置 Newtonsoft Json

    I have net6 0具有最少 api 的项目 我想使用NetwtonsoftJson而不是内置的System Text Json用于序列化和反序列化的库 目前我有这个配置JsonOptions并且按预期工作 builder Servi
  • 使用 Entity Framework Core 在运行时迁移

    我正在将 PHP Illuminate 应用程序移植到 ASP NET Core EF Core 其中一部分由类似 Wordpress 的安装过程组成 该过程要求提供数据库凭据 然后创建应用程序运行所需的表 本质上 我想在运行时运行某种迁移
  • 使用全局 Web API 过滤器属性进行 Unity 依赖注入

    参考这个CodePlex 统一文章 http unity codeplex com discussions 446780我能够使用 WebAPI 控制器获取过滤器属性 如下所示 MyFilterAttribute public class
  • 我如何将 C++ 与 VALA 混合起来

    我需要用 C 编写跨平台的 GUI 应用程序 但由于 C 的大多数 GUI 库都有点乏味 而且我对 C NET 非常熟悉 我发现使用 GTK 的代码 Vala 代码非常有趣 并且与其他方式相比有点容易 那么我该如何将 VAlA 与 C 混合

随机推荐