智能机器人编程游戏robocode的运行代码简析

article/2025/6/22 19:20:27

智能机器人编程游戏robocode的运行代码简析
金庆
2007.6.1

阅读robocode1.3的源代码,查看运行的原理。

(转载请注明来源于 金庆的专栏)

主线程Battle.run()
-------------------
主线程是Battle.run(), 循环进行多局的较量。

每一局初始化后,主要是调用runRound()进行战斗。

runRound()内部是一个循环,直到该局结束。
     while  ( ! battleOver)  {
        
// ...
    }
  
循环内,处理子弹移动,死亡事件,雷达扫描,结束判断,重画战场及配音播放,最后wakeupRobots()进入各个机器人的运行片。每个循环称为一个帧。wakeupRobots()应该保证短时间内会执行完毕,即每个时间片的机器人运行是可控的。

wakeupRobots()内部对每个运行中的机器人r(RobotPeer)执行:

     synchronized  (r)  {
        
// This call blocks until the
        
// robot's thread actually wakes up.
        r.wakeup(this);
       
        
if (!r.isSleeping())
              r.wait(TURN_TIME);
    }

    ...
    setSkippedTurns...

r.wakeup()之前线程r应该已经处于睡眠状态,r.wakeup使之运行一个回合,之后机器人仍应回到睡眠状态,即运行到tick()函数中的wait()阻塞状态。如果没有,r.wait(TURN_TIME)就给机器人一点时间进入睡眠。之后还有skippedTurns设置,表示该机器人若不能在指定时间内进入睡眠,如某个事件处理时间太长,无法在一个回合的时间内完成运行,该回合将跳过,并以事件的方式通知机器人。对机器人来说,该执行机会称为一个回合(Turn)。每帧都是一回合。

RobotPeer.wakeup()实现如下:
     public   synchronized   void  wakeup(Battle b)  {
        
if (isSleeping) {
            
// Wake up the thread
            notify();
            
try {
                wait(
10000);
            }
 catch (InterruptedException e) {}
        }

    }
  
此处notify() + wait() 唤醒RobotPeer线程并允许它运行,直到它主动调用tick()来再次进入睡眼(Sleeping),或者10s内还没有调用tick()则超时退出。从下面tick()代码可以看到超时退出时isSleeping == false, 该状态在r.wakeup()之后用来判断是否错过这一回合并设置skippedTurns。


机器人线程RobotPeer
----------------------
RobotPeer本身是Runnable线程。它的run()函数大约如下:

             if  (robot  !=   null {
                robot.run();
            }

            
for  (;;)  {
                tick();
            }

它表示一直执行robot的run(),如果robot.run()退出,就无限次执行tick()。其中robot就是用户自己实现的机器人。循环通过异常来中断,如死亡,获胜,等等。

(Robot, AdvancedRobot是用户自定义机器人的基类,实现了Runnable接口。可是Robot.run()是由RobotPeer.run()来调用的,没有使用到Runnable接口。Robot实现Runnable接口是多余的。)

其中RobotPeer.tick()是一个关键性的函数,它表示机器人本回合的命令完毕,可以进入下一回合。robot.run()中一般是通过间接的tick()调用来进入下一回合,未能及时进入下一回合将错过一个回合。

例如:
public   class  MyFirstRobot  extends  Robot  {

    
public void run() {
        
while (true{
            ahead(
100); // Move ahead 100
            turnGunRight(360); // Spin gun around   
            back(100); // Move back 100
            turnGunRight(360); // Spin gun around
        }

    }

}



其中ahead()和back()将调用peer.move(),而RobotPeer.move()如下:

     public   final   void  move( double  distance)  {
        setMove(distance);
        
do {
            tick(); 
// Always tick at least once
        }
 while (distanceRemaining != 0);
    }


turnGunRight()类似,调用RobotPeer.turnGun(),同样进入tick()循环。

实际上,用户的机器人的任何需要时间才能完成的动作,都是进入了一个循环调用tick(),直到动作完成。

而AdvancedRobot机器人使用一系列如setAhead()这样的非阻塞性调用,然后用execute()交出运行权,来达到更及时有效的控制,其实质就是execute()调用tick()。

tick与turn的概念是一致的,表示机器人的一步,robocod是和下棋一样回合制的。


RobotPeer.tick()
---------------------
RobotPeer.tick()中最重要的程序块是:
     synchronized  ( this {
        
// Notify the battle that we are now asleep.
        
// This ends any pending wait() call in battle.runRound().
        
// Should not actually take place until we release the lock in wait(), below.
        notify();
        isSleeping 
= true;
        
// Notifying battle that we're asleep
        
// Sleeping and waiting for battle to wake us up.
        try {
            wait();
        }
 catch (InterruptedException e) {
            log(
"Wait interrupted");
        }

        isSleeping 
= false;
        
// Notify battle thread, which is waiting in
        
// our wakeup() call, to return.
        
// It's quite possible, by the way, that we'll be back in sleep (above)
        
// before the battle thread actually wakes up
        notify();
    }

大量的注释表明这段代码有点搞脑筋。

这段代码与RobotPeer.wakeup()是用synchronized标为互斥的。Battle.wakeupRobots()中r.wakeup()也是用r对象同步的。

Java概念:synchronized(r)表示以r对象为锁进行同步,使同一时刻只能有一个同步块运行。同步块中可以用wait(ms)暂时释放锁,允许其它同步块运行。wait(ms)可以超时退出来抢回同步锁,或等待其它同步块调用notify()并释放锁后中断。

RobotPeer线程一旦启动,正常情况下应该最终调用tick(),并停在其中的wait()语句上。tick()中的wait()是交出CPU并无限期的等待,直到r.wakeup()中的notify() + wait(10000)。r.wakeup()让RobotPeer从wait()中醒来,运行一圈后再次进入wait()。

tick()的结构是两个notify()中间夹一个wait()。机器人绝大部分时间是在tick()中的wait()处阻塞,等待Battle的唤醒,此时isSleeping == true。

第一个notify()中止Battle.wakeupRobots()中的wait(),第二个notify()中止RobotPeer.wakup()中的wait()。

机器人的wakeup()与tick()是互斥的,它们通过wait/notify来交替运行。


机器人的启动Battle.setupRound()
----------------------------------
robot的开始运行:Battle.setupRound()
对于每个RobotPeer r, 先同步r, 再开始运行r,

     synchronized  (r)  {
        
try {
            log(
"."false);
            r.getRobotThreadManager().start();
            
// Wait for the robot to go to sleep (take action)
            r.wait(waitTime);

        }
 catch (InterruptedException e) {
            log(
"Wait for " + r + " interrupted.");
        }

    }

    
if  ( ! r.isSleeping())  {
        log(
" " + r.getName() + " still has not started after " + waitTime + " ms... giving up.");
    }

waitTime最大是10s,10s内robot必须调用tick()来将自己的状态设为isSleeping, 并交出执行权。否则认为该robot无法启动。


更简单的实现方式
------------------
synchronized/wait/notify,多么乱的一团线啊。从非Java程序员的眼光来看,这只是Battle和各Robot子线程之间的简单同步,没必要用这么难看的实现方式。

Battle只需要通知大家:现在第n回合开始!各个Robot线程只需执行一系列set后及时通知Battle: 本回合我的动作结束。Battle等待所有Robot的回合动作结束,或超时结束,执行实际的移动,碰撞等,再开始下一回合。主线程与子线程之间仅仅需要开始和结束两个事件来同步,如果子线程死循环不会影响到主线程继续下一回合。根本不需要wakeup机制。


参考
[1] Robocode的运行机制
[2] Robocode的线程与执行次序

Tag: runround,robocode,battle,robot,tick,java,运行,线程,robotpeer,代码

(转载请
注明来源于 金庆的专栏)

http://chatgpt.dhexx.cn/article/QR201Wyt.shtml

相关文章

Robocode

原文地址:Robocode 作者:麦麦和阿纳内 什么是Robocode? 其实我对机器人一直很感兴趣。我记得在我还是初中的时候,就知道 AplleⅡ上有一个程序,用它来编写简单的机器人程序,然后相互作战。当时自己还完全不懂编程&…

教你玩Robocode(1)

最近在上网时发现了一个叫做Robocode的游戏。最近我已经对它上瘾了。Robocode官方网站上对Robocode的介绍: Robocode is a programming game, where the goal is to develop a robot battle tank to battle against other tanks in Java or .NET. The robot battles are runni…

Robocode:基础知识及入门示例

文章目录 参考定义坐标系简单的API可Overwrite的方法一个简单示例 参考 百度文库-Robocode 定义 机器人:一些可以旋转、移动、射击、侦测的小型坦克。 机器人的底盘、火炮和雷达系统都可以独立运动,也可以相互“锁定”,一起移动。换句话说…

robocode 相关的总结

基础知识 1. heading 角度系 如图所示,所谓heading角,即从Y轴出发,然后顺时针绕回Y轴的这么个角度区间,取值范围: [0,360] 2. bearing角度系 所谓bearing 角,即从Y轴顺、逆时针出发,绕半圈回到…

世界robocode机器人的四大运动方式分析

摘要:前言Robocode在短短的时间内风靡全球,全世界的robocode爱好者设计出了大量的优秀智能机器人,他们都拥有各自的运动方式,有的很轻易被击中,有的却很难射击。设计一个好的运动方式是优秀robocode机器人取胜的要害。上届世界中级组冠军Fermat就是靠他让敌人难以琢…

Robocode教程1——安装、运行、配置

Robocode 的安装 系统安装最小环境要求: CPU:Pentium2/400MHz以上 内存:64MB以上 硬盘:10M以上 对硬件要求也不是完全绝对的,你用小的机器配置,带来的是比较慢的运行速度。当然具备以上硬件条件后,还要具有Java运行环…

笔记:Istio 组件 基础概念学习

文章目录 1. Istio是什么?1.1 读音1.2 简介1.3 服务网格是什么?1.4 为什么使用Isito?1.5 Istio 是如何诞生的?1.6 为什么我想用 ISTIO?1.7 目前Istio支持哪些部署环境?1.8 架构1.8.1 组件1.8.1.1 Envoy1.8.1.2 Pilot1…

Notes Sixth day-渗透攻击-红队-打入内网

** Notes Sixth day-渗透攻击-红队-打入内网(dayu) ** 作者:大余 时间:2020-09-22 请注意:对于所有笔记中复现的这些终端或者服务器,都是自行搭建的环境进行渗透的。我将使用Kali Linux作为此次学习的攻击者机器。这里使用的技…

Notes Ninth Day-渗透攻击-红队-打入内网

** Notes Ninth Day-渗透攻击-红队-打入内网(dayu) ** 作者:大余 时间:2020-09-25 请注意:对于所有笔记中复现的这些终端或者服务器,都是自行搭建的环境进行渗透的。我将使用Kali Linux作为此次学习的攻击者机器。这里使用的技…

Notes Fifth Day-渗透攻击-红队-信息收集

** Notes first day-渗透攻击-红队-信息收集(dayu) ** 作者:大余 时间:2020-09-20 请注意:对于所有笔记中复现的这些终端或者服务器,都是自行搭建的环境进行渗透的。我将使用Kali Linux作为此次学习的攻击者机器。这里使用的技…

Notes Fifteenth Day-渗透攻击-红队-内部信息搜集

** Notes Fifteenth Day-渗透攻击-红队-内部信息搜集(dayu) ** 作者:大余 时间:2020-10-1 请注意:对于所有笔记中复现的这些终端或者服务器,都是自行搭建的环境进行渗透的。我将使用Kali Linux作为此次学习的攻击者机器。这里…

多个容器一起打包_容器快速入门完全指南

介 绍 容器,以及Docker和Kubernetes之类的容器技术已经日益成为许多开发人员工具包中常见的工具。容器化的核心目标是提供一种更好的方式,以可预测和便于管理的方式在不同的环境中创建、打包以及部署软件。 在本文中,我们将一窥什么是容器&am…

项目经验123

DDDRPC架构 DDD分层架构介绍 DDD(Domain-Driven Design 领域驱动设计),目的是对软件所涉及到的领域进行建模,以应对系统规模过大时引起的软件复杂性的问题。开发团队和领域专家一起通过 通用语言(Ubiquitous Language)去理解和消…

区块链详解

一、比特币简介 区块链(Blockchain)技术源于比特币。在比特币中,为了保证每笔交易可信并不可篡改,中本聪发明了区块链,它通过后一个区块对前一个区块的引用,并以加密技术保证了区块链不可修改。 随着比特…

网络安全面试题目及详解

获取目标站点的绝对路径 如果是iis系统,尝试对参数进行恶意传值,使其出现报错页面对目标网站进行js代码审计,查看是否存在信息泄露出站点的绝对路径使用字典猜解目标站点的绝对路径如果目标是thinkphp框架,尝试访问无效的路径,或者对参数进行而已传值使其报错phpinfo页面泄露站…

云计算基础教程(第2版)笔记——基础篇与技术篇介绍

文章目录 前言 第一篇 基础篇 一 绪论 1.1 云计算的概念以及特征 1.1.1云计算的基本概念 1.1.2云计算的基本特征 1.2 云计算发展简史 1.3 三种业务模式介绍 1. 基础设施即服务(IaaS) 2. 平台即服务(PaaS) 3. 软…

2023年网络安全面试题(渗透测试):详细答案解析与最佳实践分享

如果在数据来源和网络分享方面存在侵权问题,请立即联系我以删除相关内容。 一、一句话木马 1、基本原理 通过利用存在文件上传漏洞的目标网站,将恶意的一行代码或脚本(通常是PHP语言)上传到目标服务器上,从而实现对…

一到两年工作经验的看完这些面试轻松拿offer

Java基础面试题 1、面向对象的特征有哪些方面 面向对象的特征主要有以下几个方面: 抽象:抽象是将一类对象的共同特征总结出来构造类的过程,包括数据抽象和行为抽象两方面。抽象只关注对象有哪些属性和行为,并不关注这些行为的细…

容器快速入门完全指南

介 绍 容器,以及Docker和Kubernetes之类的容器技术已经日益成为许多开发人员工具包中常见的工具。容器化的核心目标是提供一种更好的方式,以可预测和便于管理的方式在不同的环境中创建、打包以及部署软件。 在本文中,我们将一窥什么是容器&a…

JavaWeb编年史(黄金时代)

从JavaWeb编年史的远古时代,一直到白银时代,我们见证了JavaWeb开发模式的大致变迁。说白了,就是不断解耦合的过程。接下来我们来聊聊项目架构的演变,之所以我把它划到了JavaWeb编年史(黄金时代)&#xff0c…