zoukankan      html  css  js  c++  java
  • 连点成图:享受创建图形的乐趣

          定位

          本文适合于想要使用 wxpython 进行 python gui 编程的筒鞋。 读完本文后,应当能了解 wxpython 编写基本 GUI 的知识,以及熟悉策略设计模式的使用。   

           缘起

           

             发现这个游戏还挺有意思的, 不如自己来开发个?   主要设计思路如下:

              1.  使用 wxpython 做基本的 GUI , 可以生成 n * n 的初始点阵图 , n = (2, 25)  ;

              2.  使用 Python 实现策略模式; 编写了一个可扩展的小框架, 只要编写 xxxStrategyOfLinkpoints , 并添加到 strategyManager.strategiesForlinkPoints 即可; 实现委托模式, 绘图策略相关的接口均由 LinkPointStrategy 来提供, 由 StrategyManager 来管理; StrategyManager  使用单例模式来实现;

              3.  点阵图的算法, 程序员自然是使用程序生成, 既有趣也很锻炼算法思维连带激发创造力哦。已经对点阵图的点联接实现了抽象, 只需要当做 (0,0) - (n-1,n-1) 的二维矩阵来考虑。 算法需要生成一个列表, 列表中的每个元素是一个点对元组 ((x1,y1), (x2, y2)), 每个点是一个元组,包含该点的逻辑坐标。 不需要涉及点的实际坐标。

              4.  实现拖拽的创作模式, 在鼠标按下时获取位置, 检测是否有效点范围并记录起始点, 在鼠标释放时记下结束点并取出起始点进行绘图。 

                   不足之处是, 在鼠标释放之前, 所绘制的直线是不可见的, 这一点用户体验不佳。暂时没有找到方法在鼠标移动过程中实时绘线后再删除。

              5.  回退机制: 只能回到过去和现在, 无法回到过去的未来。比如从 A 到 X, 然后回退到 R, 接着前进到 S', 那么之前的 S 到 X 的部分都将丢失。

                   鉴于数据量比较少, 采用简单的方案。 保持一份工作状态的列表以及一个指向某个工作状态的指针。 回退或前进只是移动指针。如果回退后push, 那么需要将回退前的回退点之后的部分截掉。

              6.  保存和从文件恢复功能。 采用可读的文本形式, 便于分析和调试。

     

             改进点:

                 1.  从欣赏模式到创作模式或保存文件的过程中会有“未响应”的问题, 用户体验不佳;

                 2.  创建常用简单图案的函数, 更方便地使用算法组合出更复杂更美妙的图案;

                 3.  关卡设置。

                           

                 你也来试试吧! 如果有兴趣做成移动游戏, 那就更棒了!

              

           

          

          源程序:

      linkpointsUI.py 

          

    # -*- coding: utf8 -*-
    # -------------------------------------------------------------------------------
    # Name:        linkpointsUI.py
    # Purpose:     a game which links points to a gragh and enjoy
    #
    # Author:      qin.shuq
    #
    # Created:      12/06/2014
    # Copyright:   (c) qin.shuq 2014
    # Licence:     ONLY BE USED FOR STUDY
    #-------------------------------------------------------------------------------
    
    
    import wx
    import time
    import math
    import os
    import threading
    import copy
    from LinkPointStrategy import *
    
    
    class LinkPointsFrame(wx.Frame):
        '''
           generate dotSize * dotSize dotted graph and app ui
        '''
        def __init__(self, parent, title, dotSize=18, uiSize=(810,560)):
            wx.Frame.__init__(self, parent, title=title, size=uiSize)
            self.mainPanel = None            # 主面板,用于绘制点阵图
            self.dc = None                   # 用于绘制图形的对象
            self.dotSize = dotSize           # 点阵图大小设定,形成 dotSize * dotSize 点阵图
            self.displayDemoTimer = None     # 欣赏模式下自动显示已有创作的定时器
            self.validPointsRange = set()    # 拖拽模式时有效点的范围  set([px, py])
            self.isCreateMode = False        # 是否创作模式
            self.origin = 10                 # 原点的实际坐标
            self.pointRadius = 3             # 点使用实心圆圈表示,增大点击范围
            self.mousePostion = MousePositionEachPressAndRelease()   # 拖拽时记录下鼠标所在位置
            self.currWork = []               # 记录创作模式的当前工作以便于保存
            self.history = WorkHistory()     # 记录当前工作状态的历史,便于回退及前进
    
            panelSize = self.GetClientSize()
    
            topBottomMargin = 20
            leftRightMargin = 30
            uiWidth = panelSize[0] - leftRightMargin
            panelHeight = panelSize[1] - topBottomMargin
    
            self.intervalBetweenPoints = (panelHeight-self.origin*2) / (self.dotSize-1)
    
            self.validPointsRange = self.obtainRealCoordsOfDottedPoints()
    
            self.mainPanelSize = (panelHeight, panelHeight)
            self.ctrlPanelSize = (uiWidth - self.mainPanelSize[0], panelHeight)
    
            self.initUI()
            self.Centre()
    
    
        def initUI(self):
    
            ### UI Design follows top-down thinking and down-top building
    
            bigPanel = wx.Panel(self, name="WhileWindow")
            font = wx.Font(12, wx.ROMAN, wx.NORMAL, wx.NORMAL)
    
            hboxLayout = wx.BoxSizer(wx.HORIZONTAL)
            self.mainpanel = wx.Panel(bigPanel, name="mainPanel", size=self.mainPanelSize)
            self.mainpanel.SetBackgroundColour('#fffff0')
    
            self.mainpanel.Bind(wx.EVT_KEY_DOWN, self.onKeyDown)
            self.mainpanel.Bind(wx.EVT_LEFT_DOWN, self.mouseLeftPressHandler)
            #self.mainpanel.Bind(wx.EVT_MOTION, self.mouseMoveHandler)
            self.mainpanel.Bind(wx.EVT_LEFT_UP, self.mouseLeftReleaseHandler)
    
    
            ctrlPanel = wx.Panel(bigPanel, name="ctrlPanel", size=self.ctrlPanelSize)
    
            hboxLayout.Add(self.mainpanel, 0, wx.EXPAND|wx.ALL, 10)
            hboxLayout.Add(ctrlPanel, 0, wx.EXPAND|wx.ALL, 10)
            bigPanel.SetSizer(hboxLayout)
    
            topPanel = wx.Panel(ctrlPanel, name="topPanel")
            tipInfo ="How to Play: 
    
    Just link points to build a graph, 
    So Easy And Enjoy Yourself !
    
    "
            keyInfo = "Press ESC to quit. 
    Press z to back.
    Press x to forward.
    "
            staticText = wx.StaticText(topPanel, label=decodeUTF8(tipInfo+keyInfo))
            staticText.SetFont(font)
    
            btnBoxSizer = wx.GridSizer(8,2, 10, 5)
    
            buttonSize = (100, 30)
            enterCreateModeBtn = wx.Button(ctrlPanel, name="createMode", label=decodeUTF8("创作模式"), size=buttonSize)
            enterDemoModeBtn = wx.Button(ctrlPanel, name="demoMode", label=decodeUTF8("欣赏模式"), size=buttonSize)
            saveBtn = wx.Button(ctrlPanel, name="SaveWork", label=decodeUTF8("保存工作"), size=buttonSize)
            restoreBtn = wx.Button(ctrlPanel, name="restore", label=decodeUTF8("恢复已存工作"), size=buttonSize)
    
            self.Bind(wx.EVT_BUTTON, self.enterCreateMode, enterCreateModeBtn)
            self.Bind(wx.EVT_BUTTON, self.enterDemoMode, enterDemoModeBtn)
            self.Bind(wx.EVT_BUTTON, self.saveWork, saveBtn)
            self.Bind(wx.EVT_BUTTON, self.restoreWork, restoreBtn)
    
            btnBoxSizer.Add(enterCreateModeBtn, 0, wx.ALL)
            btnBoxSizer.Add(enterDemoModeBtn, 0, wx.ALL)
            btnBoxSizer.Add(saveBtn,0, wx.ALL)
            btnBoxSizer.Add(restoreBtn,0, wx.ALL)
    
            vboxLayout = wx.BoxSizer(wx.VERTICAL)
            vboxLayout.Add(topPanel, 1, wx.EXPAND|wx.ALL, 5)
            vboxLayout.Add(btnBoxSizer, 1, wx.EXPAND|wx.ALL, 5)
            ctrlPanel.SetSizer(vboxLayout)
    
            self.Show(True)
    
            # show demo
            self.displayDemoTimer = wx.Timer(self)
            self.Bind(wx.EVT_TIMER, self.displayDemoGraph, self.displayDemoTimer)
            self.createDemoForUsage()
            self.displayDemoInTimer()
    
    
        def enterCreateMode(self, event):
            self.mainpanel.SetFocus()   # 使键盘事件获得响应
            self.isCreateMode = True
            if self.displayDemoTimer:
                self.displayDemoTimer.Stop()
            self.createNewDottedGraph()
            self.history.clear()
            self.currWork = []
    
    
        def enterDemoMode(self, event):
            self.mainpanel.SetFocus()
            self.isCreateMode = False
            self.displayDemoTimer.Start(100, oneShot=True)
    
    
        def createNewDottedGraph(self):
            '''
                清空屏幕, 重新绘制点阵图
            '''
            if self.dc:
                self.dc.Clear()
            self.dc = wx.ClientDC(self.mainpanel)
            self.dc.SetPen(wx.Pen('GREEN'))
            self.dc.SetBrush(wx.Brush('GREEN'))
            for xcoord in range(self.origin, self.mainPanelSize[0] + self.intervalBetweenPoints, self.intervalBetweenPoints):
                for ycoord in range(self.origin, self.mainPanelSize[1] + self.intervalBetweenPoints, self.intervalBetweenPoints):
                    self.dc.DrawPoint(xcoord, ycoord)
                    self.dc.DrawCircle(xcoord,ycoord, self.pointRadius)
    
    
        def createDemoForUsage(self):
            '''
                展示创建图案的接口用法
            '''
            self.createNewDottedGraph()
            linkpointsStrategy = LinkPointStrategy(self.dotSize)
            allLines = linkpointsStrategy.obtainAllLinesByLinkPoints()
            self.drawGraph(allLines)
    
            ### demo for registering user-defined strategy
            def myStrategy(allPoints, size):
                return [(point, (point[0]+1, point[1]+1)) for point in allPoints if (point[0] == point[1] and point[0]<size-1)]
    
            LinkPointStrategy.registerStrategy("my", myStrategy)
            LinkPointStrategy.setStrategy("my")
            self.createNewDottedGraph()
            self.drawGraph(linkpointsStrategy.obtainAllLinesByLinkPoints())
    
    
        def displayDemoGraph(self, event):
            linkpointsStrategy = LinkPointStrategy(self.dotSize)
            allStrategies = linkpointsStrategy.getAllStrategies()
            for strategyName in allStrategies:
                self.createNewDottedGraph()
                linkpointsStrategy.setStrategy(strategyName)
                self.drawGraph(linkpointsStrategy.obtainAllLinesByLinkPoints())
                time.sleep(2)
    
    
        def displayDemoInTimer(self):
            '''
                欣赏模式下使用定时器自动展示已创建的图案
            '''
            self.displayDemoTimer.Start(100, oneShot=True)
    
    
        def drawGraphForRealCoords(self, allLines):
            '''
               根据已生成的所有线的设置绘制图案
               一条线是一个元组: ((x1,y1), (x2, y2)) xi, yi 是实际坐标
            '''
            for line in allLines:
                self.dc.DrawLine(line[0][0], line[0][1], line[1][0], line[1][1])
    
        def drawGraph(self, allLines):
            '''
               根据已生成的所有线的设置绘制图案
               一条线是一个元组: ((x1,y1), (x2, y2)) xi, yi 是逻辑坐标
            '''
            #print '***************************************'
            for line in allLines:
                #print line[0][0], ' ', line[0][1], ' ', line[1][0], ' ', line[1][1]
                x1 = self.obtainRealCoords(line[0][0])
                y1 = self.obtainRealCoords(line[0][1])
                x2 = self.obtainRealCoords(line[1][0])
                y2 = self.obtainRealCoords(line[1][1])
                self.dc.DrawLine(x1, y1, x2, y2)
    
    
        def mouseLeftPressHandler(self, event):
            '''
               拖拽时鼠标按下时的动作
            '''
            if self.isCreateMode:
                pos = event.GetPosition()
                nearestPoint = self.nearestPoint(pos)
                if nearestPoint:
                    self.mousePostion.pushPressPos(nearestPoint[0], nearestPoint[1])
                else:
                    showMsgDialog('请将鼠标放于点的位置进行拖拽!', '提示')
    
    
        def mouseMoveHandler(self, event):
            '''
               拖拽时鼠标移动的动作
            '''
            pass
            # if event.Dragging() and event.LeftIsDown():
            #     pressPos = self.mousePostion.getPressPos()
            #     lastPos = self.mousePostion.getLastMovePos()
            #     moveNowPos = event.GetPosition()
            #     self.mousePostion.pushMovePos(moveNowPos[0], moveNowPos[1])
            #     #self.dc.DrawLine(pressPos[0], pressPos[1], moveNowPos[0], moveNowPos[1])
            # event.Skip()
    
    
        def mouseLeftReleaseHandler(self, event):
            '''
               拖拽时鼠标释放时的动作
            '''
            if self.isCreateMode:
                nearestStart = self.mousePostion.getPressPos()
                releasePos = event.GetPosition()
                nearestEnd = self.nearestPoint(releasePos)
                if nearestEnd:
                    self.dc.DrawLine(nearestStart[0], nearestStart[1], nearestEnd[0], nearestEnd[1])
                    self.currWork.append((nearestStart, nearestEnd))
                    self.history.push(copy.copy(self.currWork))
                else:
                    showMsgDialog('请将鼠标放于点的位置进行拖拽!', '提示')
    
    
        def onKeyDown(self, event):
            #self.history.show()
            kc=event.GetKeyCode()
            if kc == wx.WXK_ESCAPE:
                ret = wx.MessageBox(decodeUTF8("确定要退出程序吗?"), decodeUTF8("询问"),
                                    wx.YES_NO|wx.NO_DEFAULT,self)
                if ret == wx.YES:
                    self.Close()
    
            if kc == 90:  # press z
                lastWork = self.history.back()
                if lastWork is None:
                    showMsgDialog('已经位于最开始的地方,无法回退!', '提示')
                    return
                self.createNewDottedGraph()
                self.drawGraphForRealCoords(lastWork)
                self.currWork = copy.copy(lastWork)
            elif kc == 88:  # press x
                nextWork = self.history.forward()
                if nextWork is None:
                    showMsgDialog('已经位于最后的状态,无法向前!', '提示')
                    return
                self.createNewDottedGraph()
                self.drawGraphForRealCoords(nextWork)
                self.currWork = copy.copy(nextWork)
            #self.history.show()
    
    
        def obtainRealCoordsOfDottedPoints(self):
            '''
               获取点阵图中所有点的实际坐标
            '''
            validPointsRange = set()
            for localXCoord in range(self.dotSize):
                for localYCoord in range(self.dotSize):
                    validPointsRange.add((self.obtainRealCoords(localXCoord), self.obtainRealCoords(localYCoord)))
            return validPointsRange
    
    
        def nearestPoint(self, point):
            '''
                鼠标按下或释放时判断鼠标位置是否处于有效点的范围,并获取最近的有效点用于连线
                 如果鼠标位置未处于有效点的位置,则返回 None
            '''
            if point in self.validPointsRange:
                return point
            tolerance = self.intervalBetweenPoints/4  ### 允许用户点击离有效点范围很近的地方
            for validPoint in self.validPointsRange:
                if self.distance(point, validPoint) <= self.pointRadius + tolerance:
                    return validPoint
            return None
    
        def distance(self, point1, point2):
            return math.hypot(point1[0]-point2[0], point1[1]-point2[1])
    
        def obtainRealCoords(self, localCoord):
            '''
                将逻辑坐标 (x,y) 转换为 实际坐标 (real_x, real_y).
                eg. 假设原点坐标是 (15,15), 点间隔为 (30, 30), 则 (1,1) -> (45,45)
                这样在绘图时就可以专注于以逻辑坐标来思考,摒弃实际坐标的细节干扰
            '''
            return self.origin+localCoord*self.intervalBetweenPoints
    
        def saveWork(self, event):
            self.mainpanel.SetFocus()
            file_wildcard = "files(*.lp)|*.lp|All files(*.*)|*.*"
            dlg = wx.FileDialog(self, "Save as ...", os.getcwd(), "default.lp",
                                style = wx.SAVE | wx.OVERWRITE_PROMPT, wildcard = file_wildcard)
            f_work = None
            if dlg.ShowModal() != wx.ID_OK:
                dlg.Destroy()
                return
            filename = dlg.GetPath()
            if not os.path.splitext(filename)[1]: #如果没有文件名后缀
                filename = filename + '.lp'
            f_work = open(filename, 'w')
            dlg.Destroy()
    
            f_work.write("LINK POINTS FILE.
    ")
            for (startPoint , endPoint) in self.currWork:
                f_work.write(str(startPoint[0]) + ' ' + str(startPoint[1]) + ' ' + str(endPoint[0]) + ' ' + str(endPoint[1]) + '
    ')
            f_work.close()
            showMsgDialog('工作保存成功!^_^', '提示')
    
        def restoreWork(self, event):
            self.mainpanel.SetFocus()
            file_wildcard = "files(*.lp)|*.lp|All files(*.*)|*.*"
            dlg = wx.FileDialog(self, "Open file...", os.getcwd(), style = wx.OPEN, wildcard = file_wildcard)
            if dlg.ShowModal() != wx.ID_OK:
                dlg.Destroy()
                return
    
            filename = dlg.GetPath()
            f_work = open(filename)
            lines = f_work.readlines()
            f_work.close()
            dlg.Destroy()
    
            self.history.clear()
            if lines[0].strip() != 'LINK POINTS FILE.':
                showMsgDialog('文件类型无效,请打开后缀为.lp的文件!', '提示')
            else:
                self.createNewDottedGraph()
                self.currWork = []
                for line in lines[1:]:
                    pointCoords = line.strip().split(' ')
                    if len(pointCoords) != 4:
                        showMsgDialog('文件内容已损坏!', '提示')
                        return
                    startPointX = pointCoords[0]
                    startPointY = pointCoords[1]
                    endPointX = pointCoords[2]
                    endPointY = pointCoords[3]
                    try:
                        self.dc.DrawLine(int(startPointX), int(startPointY), int(endPointX), int(endPointY))
                        self.currWork.append( ((int(startPointX), int(startPointY)), (int(endPointX), int(endPointY))) )
                    except:
                        showMsgDialog('文件内容已损坏!', '提示')
                        return
                self.history.push(self.currWork)
                showMsgDialog('成功恢复工作,自动进入创作模式!^_^ ', '提示')
                self.isCreateMode = True
    
    
    class MousePositionEachPressAndRelease(object):
        '''
            mousePosition: [(xpress, ypress), (xlastMove, ylastMove)]
        '''
        def __init__(self):
            self.mousePosition = []
    
        def pushPressPos(self, xcoord, ycoord):
            self.mousePosition.insert(0, (xcoord, ycoord))
    
        def pushMovePos(self, xcoord, ycoord):
            self.mousePosition.insert(1, (xcoord, ycoord))
    
        def getPressPos(self):
            return self.mousePosition[0]
    
        def getLastMovePos(self):
            return  self.mousePosition[1]
    
    class WorkHistory(object):
        '''
            保存工作快照列表,实现回退功能
        '''
        def __init__(self):
            self.worksnapshots = [[]]
            self.currPoint = 0
    
        def push(self, currWork):
            ### 如果在回退操作之后立即 push , 则回退之前从回退点之后的动作都将清空
            self.currPoint+=1
            self.worksnapshots = self.worksnapshots[0: self.currPoint]
            self.worksnapshots.append(currWork)
    
    
        def back(self):
            if self.currPoint <= 0:
                return None
            else:
                self.currPoint-=1
                return self.worksnapshots[self.currPoint]
    
        def forward(self):
            if self.currPoint >= len(self.worksnapshots)-1:
                return None
            else:
                self.currPoint+=1
                return self.worksnapshots[self.currPoint]
    
        def clear(self):
            self.worksnapshots = [[]]
            self.currPoint = 0
    
        def show(self):
            print "curr point: ", self.currPoint
            for snapshot in self.worksnapshots:
                print snapshot
    
    # utils
    def decodeUTF8(msg):
        return msg.decode('utf8')
    
    def showMsgDialog(msg, title):
        dialog = wx.MessageDialog(None, decodeUTF8(msg), decodeUTF8(title), wx.YES_DEFAULT)
        dialog.ShowModal()
        dialog.Destroy()
    
    def main():
    
        app = wx.App(False)
        frame = LinkPointsFrame(None, decodeUTF8('连点成图: 享受创建图形的乐趣'))
        app.MainLoop()
    
    
    if __name__ == '__main__':
        main()

        LinkPointStrategy.py

        

    # -*- coding: utf8 -*-
    # -------------------------------------------------------------------------------
    # Name:        LinkPointStrategy.py
    # Purpose:     varieties of algorithms for linking points
    #
    # Author:      qin.shuq
    #
    # Created:     11/29/2014
    # Copyright:   (c) qin.shuq 2014
    # Licence:     ONLY BE USED FOR STUDY
    # -------------------------------------------------------------------------------
    
    def linesForDiamond(centerPoint, radius):
        '''
           centerPoint: (localXCoord, localYCoord)
           radius: the distance from points in diamond to centerpoint
        '''
        centerx = centerPoint[0]
        centery = centerPoint[1]
        leftPoint = (centerx-1, centery)
        rightPoint = (centerx+1, centery)
        topPoint = (centerx, centery-1)
        bottomPoint = (centerx, centery+1)
        return [(leftPoint, topPoint), (topPoint, rightPoint), (rightPoint, bottomPoint), (bottomPoint, leftPoint)]
    
    def repeatedDiamondStrategy(allPoints, size):
        allLines = []
        radius = 2
        for point in allPoints:
            if not isOutOfBound(point, radius, size):
                allLines.extend(linesForDiamond(point, radius))
        return allLines
    
    def isOutOfBound(centerPoint, radius, dotSize):
        if centerPoint[0] <= radius-1 or centerPoint[0] + radius >= dotSize:
            return True
        if centerPoint[1] <= radius-1 or centerPoint[1] + radius >= dotSize:
            return True
        return False
    
    def simpleLoopStrategyOfLinkpoints(allPoints, size):
        pairs = []
        for i in range(size):
            if i*2 <= size-1:
                pairs.append((i, size-1-i))
        allLines = []
        for pair in pairs:
            allLines.append( ((pair[0], pair[0]), (pair[0], pair[1])) )
            allLines.append( ((pair[0], pair[0]), (pair[1], pair[0])) )
            allLines.append( ((pair[0], pair[1]), (pair[1], pair[1])) )
            allLines.append( ((pair[1], pair[0]), (pair[1], pair[1])) )
        return allLines
    
    
    def loopStrategyOfLinkpoints(allPoints, size):
        pairs = []
        for i in range(size):
            if i*2 <= size-1:
                pairs.append((i, size-1-i))
        allLines = []
        for pair in pairs:
            begin = (pair[0], pair[0])
            end = (pair[1], pair[1])
            for localXCoord in range(pair[0], pair[1], 1):
                allLines.append(((pair[0], localXCoord), (pair[0], localXCoord+1)))
                allLines.append(((pair[1], localXCoord), (pair[1], localXCoord+1)))
            for localYCoord in range(pair[0], pair[1], 1):
                allLines.append(((localYCoord, pair[0]), (localYCoord+1, pair[0])))
                allLines.append(((localYCoord, pair[1]), (localYCoord+1, pair[1])))
        return allLines
    
    
    def defaultStrategyOfLinkpoints(allPoints, size):
        return [( point, (point[0]+1, point[1]+1) )
                    for point in allPoints if not isRightOrButtomBoundPoint(point, size)]
    
    
    def isRightOrButtomBoundPoint(point, size):
        localXCoord = point[0]
        localYCoord = point[1]
        return localXCoord == size-1 or localYCoord == size-1
    
    
    def singleton(cls):
        '''
           Implements Singleton pattern in python.
           From  http://blog.csdn.net/ghostfromheaven/article/details/7671853
        '''
        instances = {}
        def _singleton(*args, **kw):
            if cls not in instances:
                instances[cls] = cls(*args, **kw)
            return instances[cls]
        return _singleton
    
    @singleton
    class StrategyManager(object):
    
        def __init__(self):
            self.strategiesForlinkPoints = {
                'default': defaultStrategyOfLinkpoints,
                'loop': loopStrategyOfLinkpoints,
                'simpleLoop': simpleLoopStrategyOfLinkpoints,
                'diamond': repeatedDiamondStrategy
            }
            self.DEFAULT_STRATEGY = self.strategiesForlinkPoints['default']
            self.CURR_STRATEGY = self.DEFAULT_STRATEGY
    
        def getStrategy(self, strategyName):
            strategyForLinkPoints = self.strategiesForlinkPoints.get(strategyName)
            if strategyForLinkPoints is None:
                raise Exception('No stragegy named "%s". You can write one. ' % strategyName)
            return strategyForLinkPoints
    
        def registerStrategy(self, strategyName, strategyForLinkPoints):
            oldStrategy = self.strategiesForlinkPoints.get(strategyName)
            if oldStrategy:
                self.strategiesForlinkPoints['old_' + strategyName] = oldStrategy
            self.strategiesForlinkPoints[strategyName] = strategyForLinkPoints
    
        def setCurrStrategy(self, strategyName):
            self.CURR_STRATEGY = self.getStrategy(strategyName)
    
        def getCurrStratety(self):
            return self.CURR_STRATEGY
    
        def getAllStrategies(self):
            return self.strategiesForlinkPoints.keys()
    
    
    class LinkPointStrategy(object):
        '''
           just think in a dotted graph of  (0,0) - (dotSize-1, dotSize-1) with interval of points = 1
           (0,0), (0,1), ... , (0, dotSize-1)
           (1,0), (1,1), ... , (1, dotSize-1)
            ... ,  ... , ... ,  ...
           (dotSize-1,0), (dotSize-1, 1), ..., (dotSize-1, dotSize-1)
           and output a set of [((x1,y1), (x2,y2)), ..., ((xm,ym), (xn,yn))]
        '''
    
        strategyManager = StrategyManager()
    
        def __init__(self, dotSize):
            self.dotSize = dotSize
            self.allPoints = []
    
            for localXCoord in range(dotSize):
                for localYCoord in range(dotSize):
                    self.allPoints.append((localXCoord, localYCoord))
    
    
        @classmethod
        def setStrategy(cls, strategyName):
            cls.strategyManager.setCurrStrategy(strategyName)
    
        @classmethod
        def getStrategy(cls, strategyName):
            return cls.strategyManager.getStrategy(strategyName)
    
        @classmethod
        def registerStrategy(cls, strategyName, strategyFunc):
            cls.strategyManager.registerStrategy(strategyName, strategyFunc)
    
        @classmethod
        def getAllStrategies(cls):
            return cls.strategyManager.getAllStrategies()
    
        def obtainAllLinesByLinkPoints(self):
            '''
               generate all lines between points according to given strategy which is a algorithm of linking points
               line: a tuple of (x1, y1, x2, y2)
               note: (x1, y1, x2, y2) are local coordinates which will be converted into real coordinates upon drawing
            '''
            currStrategy = LinkPointStrategy.strategyManager.getCurrStratety()
            return currStrategy(self.allPoints, self.dotSize)
    
    if __name__ == '__main__':
        strategyManager = StrategyManager()
        anoStrategyManager = StrategyManager()
        assert id(strategyManager) == id(anoStrategyManager)
  • 相关阅读:
    [root@py ~]# watch -n 1 ifconfig 求解释
    25 个常用的 Linux iptables 规则
    linux shell 字符串操作(长度,查找,替换)详解
    linux高级网络配置 ip别名,接口绑定
    初始版本控制工具-Git
    详解 TCP 连接的“ 三次握手 ”与“ 四次挥手 ”
    wireshark_users
    wireshark抓包基础步骤及PPPOE拨号抓包过程分析
    ARP原理与ARP攻击
    PPPOE 详解
  • 原文地址:https://www.cnblogs.com/lovesqcc/p/4132341.html
Copyright © 2011-2022 走看看