Repository: HaliteChallenge/Halite
Branch: master
Commit: 822cfb693843
Files: 701
Total size: 2.9 MB
Directory structure:
gitextract_7mjz_vb8/
├── .gitattributes
├── .gitignore
├── .travis.yml
├── CONTRIBUTING.md
├── LICENSE
├── README.md
├── admin/
│ ├── checkTaskCompletion.py
│ ├── commandRunner.py
│ ├── cost.py
│ ├── cron/
│ │ ├── haliteEmailer.py
│ │ ├── install.sh
│ │ ├── linkChecker.py
│ │ └── workerChecker.py
│ ├── md/
│ │ ├── DISASTER.md
│ │ ├── INSTALL.md
│ │ ├── SPEC.md
│ │ └── STARTER_PACKAGE_CHECKLIST.md
│ ├── rankReset.py
│ └── updateOrgs.py
├── airesources/
│ ├── C/
│ │ ├── MyBot.c
│ │ ├── RandomBot.c
│ │ ├── hlt.h
│ │ ├── runGame.bat
│ │ └── runGame.sh
│ ├── C++/
│ │ ├── MyBot.cpp
│ │ ├── RandomBot.cpp
│ │ ├── hlt.hpp
│ │ ├── networking.hpp
│ │ ├── runGame.bat
│ │ └── runGame.sh
│ ├── CSharp/
│ │ ├── Halite.csproj
│ │ ├── HaliteHelper.cs
│ │ ├── MyBot.cs
│ │ ├── Properties/
│ │ │ └── AssemblyInfo.cs
│ │ ├── RandomBot.cs
│ │ ├── runGame.bat
│ │ └── runGame.sh
│ ├── Clojure/
│ │ ├── .gitignore
│ │ ├── README.md
│ │ ├── project.clj
│ │ ├── runGame.bat
│ │ ├── runGame.sh
│ │ └── src/
│ │ ├── MyBot.clj
│ │ ├── RandomBot.clj
│ │ ├── game.clj
│ │ └── io.clj
│ ├── Go/
│ │ ├── MyBot.go
│ │ ├── RandomBot.go
│ │ ├── runGame.bat
│ │ ├── runGame.sh
│ │ └── src/
│ │ └── hlt/
│ │ ├── gamemap.go
│ │ └── networking.go
│ ├── Java/
│ │ ├── Direction.java
│ │ ├── GameMap.java
│ │ ├── InitPackage.java
│ │ ├── Location.java
│ │ ├── Move.java
│ │ ├── MyBot.java
│ │ ├── Networking.java
│ │ ├── RandomBot.java
│ │ ├── Site.java
│ │ ├── runGame.bat
│ │ └── runGame.sh
│ ├── JavaScript/
│ │ ├── MyBot.js
│ │ ├── RandomBot.js
│ │ ├── hlt.js
│ │ ├── networking.js
│ │ ├── runGame.bat
│ │ └── runGame.sh
│ ├── Julia/
│ │ ├── MyBot.jl
│ │ ├── RandomBot.jl
│ │ ├── hlt.jl
│ │ ├── networking.jl
│ │ ├── runGame.bat
│ │ └── runGame.sh
│ ├── OCaml/
│ │ ├── MyBot.ml
│ │ ├── README.md
│ │ ├── RandomBot.ml
│ │ ├── debug.ml
│ │ ├── halite.ml
│ │ ├── runGame.bat
│ │ ├── runGame.sh
│ │ └── td.ml
│ ├── PHP/
│ │ ├── MyBot.php
│ │ ├── RandomBot.php
│ │ ├── hlt.php
│ │ ├── networking.php
│ │ ├── runGame.bat
│ │ └── runGame.sh
│ ├── Python/
│ │ ├── MyBot.py
│ │ ├── RandomBot.py
│ │ ├── hlt.py
│ │ ├── runGame.bat
│ │ └── runGame.sh
│ ├── Ruby/
│ │ ├── MyBot.rb
│ │ ├── RandomBot.rb
│ │ ├── game_map.rb
│ │ ├── location.rb
│ │ ├── move.rb
│ │ ├── networking.rb
│ │ ├── runGame.bat
│ │ ├── runGame.sh
│ │ └── site.rb
│ ├── Rust/
│ │ ├── Cargo.toml
│ │ ├── runGame.bat
│ │ ├── runGame.sh
│ │ └── src/
│ │ ├── MyBot.rs
│ │ ├── RandomBot.rs
│ │ └── hlt/
│ │ ├── mod.rs
│ │ ├── networking.rs
│ │ └── types.rs
│ ├── Scala/
│ │ ├── Bot.scala
│ │ ├── Direction.scala
│ │ ├── Env.scala
│ │ ├── Grid.scala
│ │ ├── Move.scala
│ │ ├── MyBot.scala
│ │ ├── RandomBot.scala
│ │ ├── Runner.scala
│ │ ├── runGame.bat
│ │ └── runGame.sh
│ └── Sockets/
│ ├── HaliteSocketHelper.cs
│ ├── SocketNetworking.java
│ ├── pipe_socket_translator.py
│ ├── socket_networking.hpp
│ └── socket_networking.py
├── appveyor.yml
├── environment/
│ ├── Makefile
│ ├── core/
│ │ ├── Halite.cpp
│ │ ├── Halite.hpp
│ │ ├── hlt.hpp
│ │ └── json.hpp
│ ├── install.sh
│ ├── main.cpp
│ ├── make.bat
│ ├── networking/
│ │ ├── Networking.cpp
│ │ └── Networking.hpp
│ └── tclap/
│ ├── Arg.h
│ ├── ArgException.h
│ ├── ArgTraits.h
│ ├── CmdLine.h
│ ├── CmdLineInterface.h
│ ├── CmdLineOutput.h
│ ├── Constraint.h
│ ├── DocBookOutput.h
│ ├── HelpVisitor.h
│ ├── IgnoreRestVisitor.h
│ ├── Makefile.am
│ ├── Makefile.in
│ ├── MultiArg.h
│ ├── MultiSwitchArg.h
│ ├── OptionalUnlabeledTracker.h
│ ├── StandardTraits.h
│ ├── StdOutput.h
│ ├── SwitchArg.h
│ ├── UnlabeledMultiArg.h
│ ├── UnlabeledValueArg.h
│ ├── ValueArg.h
│ ├── ValuesConstraint.h
│ ├── VersionVisitor.h
│ ├── Visitor.h
│ ├── XorHandler.h
│ └── ZshCompletionOutput.h
├── tests/
│ ├── environment/
│ │ ├── Fail10Bot.py
│ │ ├── FailInitBot.py
│ │ ├── ModBot.py
│ │ ├── Timeout10Bot.py
│ │ ├── TimeoutInitBot.py
│ │ ├── hlt.py
│ │ ├── networking.py
│ │ └── testenv.py
│ ├── install.sh
│ ├── runTests.sh
│ ├── scalabilityTests/
│ │ └── main.py
│ ├── setupMysql.py
│ ├── travisTests.ini
│ ├── website/
│ │ ├── APITest.php
│ │ ├── GameTest.php
│ │ ├── HistoryTest.php
│ │ ├── UserTest.php
│ │ └── testFile.txt
│ └── worker/
│ ├── languageBot/
│ │ ├── LANGUAGE
│ │ └── run.sh
│ ├── loseBot/
│ │ ├── MyBot.py
│ │ └── run.sh
│ ├── testWorker.py
│ └── winBot/
│ ├── MyBot.py
│ └── run.sh
├── visualizer/
│ ├── .editorconfig
│ ├── .gitattributes
│ ├── index.html
│ ├── index.js
│ ├── main.js
│ └── package.json
├── website/
│ ├── .htaccess
│ ├── 404.php
│ ├── about.php
│ ├── advanced_command_line.php
│ ├── advanced_development.php
│ ├── advanced_game_server.php
│ ├── advanced_libraries.php
│ ├── advanced_replay_file.php
│ ├── advanced_strategy.php
│ ├── advanced_third_party.php
│ ├── advanced_writing_sp.php
│ ├── api/
│ │ ├── API.class.php
│ │ ├── manager/
│ │ │ ├── .htaccess
│ │ │ ├── ManagerAPI.php
│ │ │ ├── api.php
│ │ │ ├── trueskillMatchQuality.py
│ │ │ └── updateTrueskill.py
│ │ └── web/
│ │ ├── .htaccess
│ │ ├── WebsiteAPI.php
│ │ ├── api.php
│ │ └── openNewWorker.py
│ ├── archiveEnvironment.sh
│ ├── archiveStarterPackages.sh
│ ├── assets/
│ │ └── favicons/
│ │ ├── browserconfig.xml
│ │ └── manifest.json
│ ├── associate.php
│ ├── basics_faqs.php
│ ├── basics_improve_random.php
│ ├── basics_intro_halite.php
│ ├── basics_quickstart.php
│ ├── composer.json
│ ├── cron/
│ │ ├── backupDatabase
│ │ └── backupWebsite
│ ├── downloads.php
│ ├── email.php
│ ├── game.php
│ ├── includes/
│ │ ├── dropdowns.php
│ │ ├── footer.php
│ │ ├── header.php
│ │ ├── leaderTable.php
│ │ ├── learn_sidebar.php
│ │ ├── login_form.php
│ │ ├── navbar.php
│ │ └── register_form.php
│ ├── index.php
│ ├── install.sh
│ ├── leaderboard.php
│ ├── lib/
│ │ ├── bootstrap/
│ │ │ ├── bootstrap/
│ │ │ │ ├── alerts.less
│ │ │ │ ├── badges.less
│ │ │ │ ├── bootstrap.less
│ │ │ │ ├── breadcrumbs.less
│ │ │ │ ├── button-groups.less
│ │ │ │ ├── buttons.less
│ │ │ │ ├── carousel.less
│ │ │ │ ├── close.less
│ │ │ │ ├── code.less
│ │ │ │ ├── component-animations.less
│ │ │ │ ├── dropdowns.less
│ │ │ │ ├── forms.less
│ │ │ │ ├── glyphicons.less
│ │ │ │ ├── grid.less
│ │ │ │ ├── input-groups.less
│ │ │ │ ├── jumbotron.less
│ │ │ │ ├── labels.less
│ │ │ │ ├── list-group.less
│ │ │ │ ├── media.less
│ │ │ │ ├── mixins/
│ │ │ │ │ ├── alerts.less
│ │ │ │ │ ├── background-variant.less
│ │ │ │ │ ├── border-radius.less
│ │ │ │ │ ├── buttons.less
│ │ │ │ │ ├── center-block.less
│ │ │ │ │ ├── clearfix.less
│ │ │ │ │ ├── forms.less
│ │ │ │ │ ├── gradients.less
│ │ │ │ │ ├── grid-framework.less
│ │ │ │ │ ├── grid.less
│ │ │ │ │ ├── hide-text.less
│ │ │ │ │ ├── image.less
│ │ │ │ │ ├── labels.less
│ │ │ │ │ ├── list-group.less
│ │ │ │ │ ├── nav-divider.less
│ │ │ │ │ ├── nav-vertical-align.less
│ │ │ │ │ ├── opacity.less
│ │ │ │ │ ├── pagination.less
│ │ │ │ │ ├── panels.less
│ │ │ │ │ ├── progress-bar.less
│ │ │ │ │ ├── reset-filter.less
│ │ │ │ │ ├── reset-text.less
│ │ │ │ │ ├── resize.less
│ │ │ │ │ ├── responsive-visibility.less
│ │ │ │ │ ├── size.less
│ │ │ │ │ ├── tab-focus.less
│ │ │ │ │ ├── table-row.less
│ │ │ │ │ ├── text-emphasis.less
│ │ │ │ │ ├── text-overflow.less
│ │ │ │ │ └── vendor-prefixes.less
│ │ │ │ ├── mixins.less
│ │ │ │ ├── modals.less
│ │ │ │ ├── navbar.less
│ │ │ │ ├── navs.less
│ │ │ │ ├── normalize.less
│ │ │ │ ├── pager.less
│ │ │ │ ├── pagination.less
│ │ │ │ ├── panels.less
│ │ │ │ ├── popovers.less
│ │ │ │ ├── print.less
│ │ │ │ ├── progress-bars.less
│ │ │ │ ├── responsive-embed.less
│ │ │ │ ├── responsive-utilities.less
│ │ │ │ ├── scaffolding.less
│ │ │ │ ├── tables.less
│ │ │ │ ├── theme.less
│ │ │ │ ├── thumbnails.less
│ │ │ │ ├── tooltip.less
│ │ │ │ ├── type.less
│ │ │ │ ├── utilities.less
│ │ │ │ ├── variables.less
│ │ │ │ └── wells.less
│ │ │ ├── bootswatch.less
│ │ │ ├── build.less
│ │ │ ├── build.sh
│ │ │ ├── output.css
│ │ │ └── variables.less
│ │ ├── swiftmailer/
│ │ │ ├── .gitattributes
│ │ │ ├── .gitignore
│ │ │ ├── .travis.yml
│ │ │ ├── CHANGES
│ │ │ ├── LICENSE
│ │ │ ├── README
│ │ │ ├── VERSION
│ │ │ ├── composer.json
│ │ │ ├── lib/
│ │ │ │ ├── classes/
│ │ │ │ │ ├── Swift/
│ │ │ │ │ │ ├── Attachment.php
│ │ │ │ │ │ ├── ByteStream/
│ │ │ │ │ │ │ ├── AbstractFilterableInputStream.php
│ │ │ │ │ │ │ ├── ArrayByteStream.php
│ │ │ │ │ │ │ ├── FileByteStream.php
│ │ │ │ │ │ │ └── TemporaryFileByteStream.php
│ │ │ │ │ │ ├── CharacterReader/
│ │ │ │ │ │ │ ├── GenericFixedWidthReader.php
│ │ │ │ │ │ │ ├── UsAsciiReader.php
│ │ │ │ │ │ │ └── Utf8Reader.php
│ │ │ │ │ │ ├── CharacterReader.php
│ │ │ │ │ │ ├── CharacterReaderFactory/
│ │ │ │ │ │ │ └── SimpleCharacterReaderFactory.php
│ │ │ │ │ │ ├── CharacterReaderFactory.php
│ │ │ │ │ │ ├── CharacterStream/
│ │ │ │ │ │ │ ├── ArrayCharacterStream.php
│ │ │ │ │ │ │ └── NgCharacterStream.php
│ │ │ │ │ │ ├── CharacterStream.php
│ │ │ │ │ │ ├── ConfigurableSpool.php
│ │ │ │ │ │ ├── DependencyContainer.php
│ │ │ │ │ │ ├── DependencyException.php
│ │ │ │ │ │ ├── EmbeddedFile.php
│ │ │ │ │ │ ├── Encoder/
│ │ │ │ │ │ │ ├── Base64Encoder.php
│ │ │ │ │ │ │ ├── QpEncoder.php
│ │ │ │ │ │ │ └── Rfc2231Encoder.php
│ │ │ │ │ │ ├── Encoder.php
│ │ │ │ │ │ ├── Encoding.php
│ │ │ │ │ │ ├── Events/
│ │ │ │ │ │ │ ├── CommandEvent.php
│ │ │ │ │ │ │ ├── CommandListener.php
│ │ │ │ │ │ │ ├── Event.php
│ │ │ │ │ │ │ ├── EventDispatcher.php
│ │ │ │ │ │ │ ├── EventListener.php
│ │ │ │ │ │ │ ├── EventObject.php
│ │ │ │ │ │ │ ├── ResponseEvent.php
│ │ │ │ │ │ │ ├── ResponseListener.php
│ │ │ │ │ │ │ ├── SendEvent.php
│ │ │ │ │ │ │ ├── SendListener.php
│ │ │ │ │ │ │ ├── SimpleEventDispatcher.php
│ │ │ │ │ │ │ ├── TransportChangeEvent.php
│ │ │ │ │ │ │ ├── TransportChangeListener.php
│ │ │ │ │ │ │ ├── TransportExceptionEvent.php
│ │ │ │ │ │ │ └── TransportExceptionListener.php
│ │ │ │ │ │ ├── FailoverTransport.php
│ │ │ │ │ │ ├── FileSpool.php
│ │ │ │ │ │ ├── FileStream.php
│ │ │ │ │ │ ├── Filterable.php
│ │ │ │ │ │ ├── Image.php
│ │ │ │ │ │ ├── InputByteStream.php
│ │ │ │ │ │ ├── IoException.php
│ │ │ │ │ │ ├── KeyCache/
│ │ │ │ │ │ │ ├── ArrayKeyCache.php
│ │ │ │ │ │ │ ├── DiskKeyCache.php
│ │ │ │ │ │ │ ├── KeyCacheInputStream.php
│ │ │ │ │ │ │ ├── NullKeyCache.php
│ │ │ │ │ │ │ └── SimpleKeyCacheInputStream.php
│ │ │ │ │ │ ├── KeyCache.php
│ │ │ │ │ │ ├── LoadBalancedTransport.php
│ │ │ │ │ │ ├── MailTransport.php
│ │ │ │ │ │ ├── Mailer/
│ │ │ │ │ │ │ ├── ArrayRecipientIterator.php
│ │ │ │ │ │ │ └── RecipientIterator.php
│ │ │ │ │ │ ├── Mailer.php
│ │ │ │ │ │ ├── MemorySpool.php
│ │ │ │ │ │ ├── Message.php
│ │ │ │ │ │ ├── Mime/
│ │ │ │ │ │ │ ├── Attachment.php
│ │ │ │ │ │ │ ├── CharsetObserver.php
│ │ │ │ │ │ │ ├── ContentEncoder/
│ │ │ │ │ │ │ │ ├── Base64ContentEncoder.php
│ │ │ │ │ │ │ │ ├── NativeQpContentEncoder.php
│ │ │ │ │ │ │ │ ├── PlainContentEncoder.php
│ │ │ │ │ │ │ │ ├── QpContentEncoder.php
│ │ │ │ │ │ │ │ ├── QpContentEncoderProxy.php
│ │ │ │ │ │ │ │ └── RawContentEncoder.php
│ │ │ │ │ │ │ ├── ContentEncoder.php
│ │ │ │ │ │ │ ├── EmbeddedFile.php
│ │ │ │ │ │ │ ├── EncodingObserver.php
│ │ │ │ │ │ │ ├── Grammar.php
│ │ │ │ │ │ │ ├── Header.php
│ │ │ │ │ │ │ ├── HeaderEncoder/
│ │ │ │ │ │ │ │ ├── Base64HeaderEncoder.php
│ │ │ │ │ │ │ │ └── QpHeaderEncoder.php
│ │ │ │ │ │ │ ├── HeaderEncoder.php
│ │ │ │ │ │ │ ├── HeaderFactory.php
│ │ │ │ │ │ │ ├── HeaderSet.php
│ │ │ │ │ │ │ ├── Headers/
│ │ │ │ │ │ │ │ ├── AbstractHeader.php
│ │ │ │ │ │ │ │ ├── DateHeader.php
│ │ │ │ │ │ │ │ ├── IdentificationHeader.php
│ │ │ │ │ │ │ │ ├── MailboxHeader.php
│ │ │ │ │ │ │ │ ├── OpenDKIMHeader.php
│ │ │ │ │ │ │ │ ├── ParameterizedHeader.php
│ │ │ │ │ │ │ │ ├── PathHeader.php
│ │ │ │ │ │ │ │ └── UnstructuredHeader.php
│ │ │ │ │ │ │ ├── Message.php
│ │ │ │ │ │ │ ├── MimeEntity.php
│ │ │ │ │ │ │ ├── MimePart.php
│ │ │ │ │ │ │ ├── ParameterizedHeader.php
│ │ │ │ │ │ │ ├── SimpleHeaderFactory.php
│ │ │ │ │ │ │ ├── SimpleHeaderSet.php
│ │ │ │ │ │ │ ├── SimpleMessage.php
│ │ │ │ │ │ │ └── SimpleMimeEntity.php
│ │ │ │ │ │ ├── MimePart.php
│ │ │ │ │ │ ├── NullTransport.php
│ │ │ │ │ │ ├── OutputByteStream.php
│ │ │ │ │ │ ├── Plugins/
│ │ │ │ │ │ │ ├── AntiFloodPlugin.php
│ │ │ │ │ │ │ ├── BandwidthMonitorPlugin.php
│ │ │ │ │ │ │ ├── Decorator/
│ │ │ │ │ │ │ │ └── Replacements.php
│ │ │ │ │ │ │ ├── DecoratorPlugin.php
│ │ │ │ │ │ │ ├── ImpersonatePlugin.php
│ │ │ │ │ │ │ ├── Logger.php
│ │ │ │ │ │ │ ├── LoggerPlugin.php
│ │ │ │ │ │ │ ├── Loggers/
│ │ │ │ │ │ │ │ ├── ArrayLogger.php
│ │ │ │ │ │ │ │ └── EchoLogger.php
│ │ │ │ │ │ │ ├── MessageLogger.php
│ │ │ │ │ │ │ ├── Pop/
│ │ │ │ │ │ │ │ ├── Pop3Connection.php
│ │ │ │ │ │ │ │ └── Pop3Exception.php
│ │ │ │ │ │ │ ├── PopBeforeSmtpPlugin.php
│ │ │ │ │ │ │ ├── RedirectingPlugin.php
│ │ │ │ │ │ │ ├── Reporter.php
│ │ │ │ │ │ │ ├── ReporterPlugin.php
│ │ │ │ │ │ │ ├── Reporters/
│ │ │ │ │ │ │ │ ├── HitReporter.php
│ │ │ │ │ │ │ │ └── HtmlReporter.php
│ │ │ │ │ │ │ ├── Sleeper.php
│ │ │ │ │ │ │ ├── ThrottlerPlugin.php
│ │ │ │ │ │ │ └── Timer.php
│ │ │ │ │ │ ├── Preferences.php
│ │ │ │ │ │ ├── ReplacementFilterFactory.php
│ │ │ │ │ │ ├── RfcComplianceException.php
│ │ │ │ │ │ ├── SendmailTransport.php
│ │ │ │ │ │ ├── SignedMessage.php
│ │ │ │ │ │ ├── Signer.php
│ │ │ │ │ │ ├── Signers/
│ │ │ │ │ │ │ ├── BodySigner.php
│ │ │ │ │ │ │ ├── DKIMSigner.php
│ │ │ │ │ │ │ ├── DomainKeySigner.php
│ │ │ │ │ │ │ ├── HeaderSigner.php
│ │ │ │ │ │ │ ├── OpenDKIMSigner.php
│ │ │ │ │ │ │ └── SMimeSigner.php
│ │ │ │ │ │ ├── SmtpTransport.php
│ │ │ │ │ │ ├── Spool.php
│ │ │ │ │ │ ├── SpoolTransport.php
│ │ │ │ │ │ ├── StreamFilter.php
│ │ │ │ │ │ ├── StreamFilters/
│ │ │ │ │ │ │ ├── ByteArrayReplacementFilter.php
│ │ │ │ │ │ │ ├── StringReplacementFilter.php
│ │ │ │ │ │ │ └── StringReplacementFilterFactory.php
│ │ │ │ │ │ ├── SwiftException.php
│ │ │ │ │ │ ├── Transport/
│ │ │ │ │ │ │ ├── AbstractSmtpTransport.php
│ │ │ │ │ │ │ ├── Esmtp/
│ │ │ │ │ │ │ │ ├── Auth/
│ │ │ │ │ │ │ │ │ ├── CramMd5Authenticator.php
│ │ │ │ │ │ │ │ │ ├── LoginAuthenticator.php
│ │ │ │ │ │ │ │ │ ├── NTLMAuthenticator.php
│ │ │ │ │ │ │ │ │ ├── PlainAuthenticator.php
│ │ │ │ │ │ │ │ │ └── XOAuth2Authenticator.php
│ │ │ │ │ │ │ │ ├── AuthHandler.php
│ │ │ │ │ │ │ │ └── Authenticator.php
│ │ │ │ │ │ │ ├── EsmtpHandler.php
│ │ │ │ │ │ │ ├── EsmtpTransport.php
│ │ │ │ │ │ │ ├── FailoverTransport.php
│ │ │ │ │ │ │ ├── IoBuffer.php
│ │ │ │ │ │ │ ├── LoadBalancedTransport.php
│ │ │ │ │ │ │ ├── MailInvoker.php
│ │ │ │ │ │ │ ├── MailTransport.php
│ │ │ │ │ │ │ ├── NullTransport.php
│ │ │ │ │ │ │ ├── SendmailTransport.php
│ │ │ │ │ │ │ ├── SimpleMailInvoker.php
│ │ │ │ │ │ │ ├── SmtpAgent.php
│ │ │ │ │ │ │ ├── SpoolTransport.php
│ │ │ │ │ │ │ └── StreamBuffer.php
│ │ │ │ │ │ ├── Transport.php
│ │ │ │ │ │ ├── TransportException.php
│ │ │ │ │ │ └── Validate.php
│ │ │ │ │ └── Swift.php
│ │ │ │ ├── dependency_maps/
│ │ │ │ │ ├── cache_deps.php
│ │ │ │ │ ├── message_deps.php
│ │ │ │ │ ├── mime_deps.php
│ │ │ │ │ └── transport_deps.php
│ │ │ │ ├── mime_types.php
│ │ │ │ ├── preferences.php
│ │ │ │ ├── swift_init.php
│ │ │ │ ├── swift_required.php
│ │ │ │ ├── swift_required_pear.php
│ │ │ │ └── swiftmailer_generate_mimes_config.php
│ │ │ ├── phpunit.xml.dist
│ │ │ └── tests/
│ │ │ ├── IdenticalBinaryConstraint.php
│ │ │ ├── StreamCollector.php
│ │ │ ├── SwiftMailerSmokeTestCase.php
│ │ │ ├── SwiftMailerTestCase.php
│ │ │ ├── _samples/
│ │ │ │ ├── charsets/
│ │ │ │ │ ├── iso-2022-jp/
│ │ │ │ │ │ └── one.txt
│ │ │ │ │ ├── iso-8859-1/
│ │ │ │ │ │ └── one.txt
│ │ │ │ │ └── utf-8/
│ │ │ │ │ ├── one.txt
│ │ │ │ │ ├── three.txt
│ │ │ │ │ └── two.txt
│ │ │ │ ├── dkim/
│ │ │ │ │ ├── dkim.test.priv
│ │ │ │ │ └── dkim.test.pub
│ │ │ │ ├── files/
│ │ │ │ │ └── data.txt
│ │ │ │ └── smime/
│ │ │ │ ├── CA.srl
│ │ │ │ ├── ca.crt
│ │ │ │ ├── ca.key
│ │ │ │ ├── create-cert.sh
│ │ │ │ ├── encrypt.crt
│ │ │ │ ├── encrypt.key
│ │ │ │ ├── encrypt2.crt
│ │ │ │ ├── encrypt2.key
│ │ │ │ ├── intermediate.crt
│ │ │ │ ├── intermediate.key
│ │ │ │ ├── sign.crt
│ │ │ │ ├── sign.key
│ │ │ │ ├── sign2.crt
│ │ │ │ └── sign2.key
│ │ │ ├── acceptance/
│ │ │ │ └── Swift/
│ │ │ │ ├── AttachmentAcceptanceTest.php
│ │ │ │ ├── ByteStream/
│ │ │ │ │ └── FileByteStreamAcceptanceTest.php
│ │ │ │ ├── CharacterReaderFactory/
│ │ │ │ │ └── SimpleCharacterReaderFactoryAcceptanceTest.php
│ │ │ │ ├── DependencyContainerAcceptanceTest.php
│ │ │ │ ├── EmbeddedFileAcceptanceTest.php
│ │ │ │ ├── Encoder/
│ │ │ │ │ ├── Base64EncoderAcceptanceTest.php
│ │ │ │ │ ├── QpEncoderAcceptanceTest.php
│ │ │ │ │ └── Rfc2231EncoderAcceptanceTest.php
│ │ │ │ ├── EncodingAcceptanceTest.php
│ │ │ │ ├── KeyCache/
│ │ │ │ │ ├── ArrayKeyCacheAcceptanceTest.php
│ │ │ │ │ └── DiskKeyCacheAcceptanceTest.php
│ │ │ │ ├── MessageAcceptanceTest.php
│ │ │ │ ├── Mime/
│ │ │ │ │ ├── AttachmentAcceptanceTest.php
│ │ │ │ │ ├── ContentEncoder/
│ │ │ │ │ │ ├── Base64ContentEncoderAcceptanceTest.php
│ │ │ │ │ │ ├── NativeQpContentEncoderAcceptanceTest.php
│ │ │ │ │ │ ├── PlainContentEncoderAcceptanceTest.php
│ │ │ │ │ │ └── QpContentEncoderAcceptanceTest.php
│ │ │ │ │ ├── EmbeddedFileAcceptanceTest.php
│ │ │ │ │ ├── HeaderEncoder/
│ │ │ │ │ │ └── Base64HeaderEncoderAcceptanceTest.php
│ │ │ │ │ ├── MimePartAcceptanceTest.php
│ │ │ │ │ └── SimpleMessageAcceptanceTest.php
│ │ │ │ ├── MimePartAcceptanceTest.php
│ │ │ │ └── Transport/
│ │ │ │ └── StreamBuffer/
│ │ │ │ ├── AbstractStreamBufferAcceptanceTest.php
│ │ │ │ ├── BasicSocketAcceptanceTest.php
│ │ │ │ ├── ProcessAcceptanceTest.php
│ │ │ │ ├── SocketTimeoutTest.php
│ │ │ │ ├── SslSocketAcceptanceTest.php
│ │ │ │ └── TlsSocketAcceptanceTest.php
│ │ │ ├── acceptance.conf.php.default
│ │ │ ├── bootstrap.php
│ │ │ ├── bug/
│ │ │ │ └── Swift/
│ │ │ │ ├── Bug111Test.php
│ │ │ │ ├── Bug118Test.php
│ │ │ │ ├── Bug206Test.php
│ │ │ │ ├── Bug274Test.php
│ │ │ │ ├── Bug34Test.php
│ │ │ │ ├── Bug35Test.php
│ │ │ │ ├── Bug38Test.php
│ │ │ │ ├── Bug518Test.php
│ │ │ │ ├── Bug51Test.php
│ │ │ │ ├── Bug534Test.php
│ │ │ │ ├── Bug71Test.php
│ │ │ │ ├── Bug76Test.php
│ │ │ │ └── BugFileByteStreamConsecutiveReadCallsTest.php
│ │ │ ├── fixtures/
│ │ │ │ └── MimeEntityFixture.php
│ │ │ ├── smoke/
│ │ │ │ └── Swift/
│ │ │ │ └── Smoke/
│ │ │ │ ├── AttachmentSmokeTest.php
│ │ │ │ ├── BasicSmokeTest.php
│ │ │ │ ├── HtmlWithAttachmentSmokeTest.php
│ │ │ │ └── InternationalSmokeTest.php
│ │ │ ├── smoke.conf.php.default
│ │ │ └── unit/
│ │ │ └── Swift/
│ │ │ ├── ByteStream/
│ │ │ │ └── ArrayByteStreamTest.php
│ │ │ ├── CharacterReader/
│ │ │ │ ├── GenericFixedWidthReaderTest.php
│ │ │ │ ├── UsAsciiReaderTest.php
│ │ │ │ └── Utf8ReaderTest.php
│ │ │ ├── CharacterStream/
│ │ │ │ └── ArrayCharacterStreamTest.php
│ │ │ ├── DependencyContainerTest.php
│ │ │ ├── Encoder/
│ │ │ │ ├── Base64EncoderTest.php
│ │ │ │ ├── QpEncoderTest.php
│ │ │ │ └── Rfc2231EncoderTest.php
│ │ │ ├── Events/
│ │ │ │ ├── CommandEventTest.php
│ │ │ │ ├── EventObjectTest.php
│ │ │ │ ├── ResponseEventTest.php
│ │ │ │ ├── SendEventTest.php
│ │ │ │ ├── SimpleEventDispatcherTest.php
│ │ │ │ ├── TransportChangeEventTest.php
│ │ │ │ └── TransportExceptionEventTest.php
│ │ │ ├── KeyCache/
│ │ │ │ ├── ArrayKeyCacheTest.php
│ │ │ │ └── SimpleKeyCacheInputStreamTest.php
│ │ │ ├── Mailer/
│ │ │ │ └── ArrayRecipientIteratorTest.php
│ │ │ ├── MailerTest.php
│ │ │ ├── MessageTest.php
│ │ │ ├── Mime/
│ │ │ │ ├── AbstractMimeEntityTest.php
│ │ │ │ ├── AttachmentTest.php
│ │ │ │ ├── ContentEncoder/
│ │ │ │ │ ├── Base64ContentEncoderTest.php
│ │ │ │ │ ├── PlainContentEncoderTest.php
│ │ │ │ │ └── QpContentEncoderTest.php
│ │ │ │ ├── EmbeddedFileTest.php
│ │ │ │ ├── HeaderEncoder/
│ │ │ │ │ ├── Base64HeaderEncoderTest.php
│ │ │ │ │ └── QpHeaderEncoderTest.php
│ │ │ │ ├── Headers/
│ │ │ │ │ ├── DateHeaderTest.php
│ │ │ │ │ ├── IdentificationHeaderTest.php
│ │ │ │ │ ├── MailboxHeaderTest.php
│ │ │ │ │ ├── ParameterizedHeaderTest.php
│ │ │ │ │ ├── PathHeaderTest.php
│ │ │ │ │ └── UnstructuredHeaderTest.php
│ │ │ │ ├── MimePartTest.php
│ │ │ │ ├── SimpleHeaderFactoryTest.php
│ │ │ │ ├── SimpleHeaderSetTest.php
│ │ │ │ ├── SimpleMessageTest.php
│ │ │ │ └── SimpleMimeEntityTest.php
│ │ │ ├── Plugins/
│ │ │ │ ├── AntiFloodPluginTest.php
│ │ │ │ ├── BandwidthMonitorPluginTest.php
│ │ │ │ ├── DecoratorPluginTest.php
│ │ │ │ ├── LoggerPluginTest.php
│ │ │ │ ├── Loggers/
│ │ │ │ │ ├── ArrayLoggerTest.php
│ │ │ │ │ └── EchoLoggerTest.php
│ │ │ │ ├── PopBeforeSmtpPluginTest.php
│ │ │ │ ├── RedirectingPluginTest.php
│ │ │ │ ├── ReporterPluginTest.php
│ │ │ │ ├── Reporters/
│ │ │ │ │ ├── HitReporterTest.php
│ │ │ │ │ └── HtmlReporterTest.php
│ │ │ │ └── ThrottlerPluginTest.php
│ │ │ ├── Signers/
│ │ │ │ ├── DKIMSignerTest.php
│ │ │ │ ├── OpenDKIMSignerTest.php
│ │ │ │ └── SMimeSignerTest.php
│ │ │ ├── StreamFilters/
│ │ │ │ ├── ByteArrayReplacementFilterTest.php
│ │ │ │ ├── StringReplacementFilterFactoryTest.php
│ │ │ │ └── StringReplacementFilterTest.php
│ │ │ └── Transport/
│ │ │ ├── AbstractSmtpEventSupportTest.php
│ │ │ ├── AbstractSmtpTest.php
│ │ │ ├── Esmtp/
│ │ │ │ ├── Auth/
│ │ │ │ │ ├── CramMd5AuthenticatorTest.php
│ │ │ │ │ ├── LoginAuthenticatorTest.php
│ │ │ │ │ ├── NTLMAuthenticatorTest.php
│ │ │ │ │ └── PlainAuthenticatorTest.php
│ │ │ │ └── AuthHandlerTest.php
│ │ │ ├── EsmtpTransport/
│ │ │ │ └── ExtensionSupportTest.php
│ │ │ ├── EsmtpTransportTest.php
│ │ │ ├── FailoverTransportTest.php
│ │ │ ├── LoadBalancedTransportTest.php
│ │ │ ├── MailTransportTest.php
│ │ │ ├── SendmailTransportTest.php
│ │ │ └── StreamBufferTest.php
│ │ └── xss.js
│ ├── local_visualizer.php
│ ├── organizationWhitelist.txt
│ ├── privacy_policy.php
│ ├── recent_games.php
│ ├── robots.txt
│ ├── rules_contest.php
│ ├── rules_game.php
│ ├── script/
│ │ ├── associate.js
│ │ ├── backend.js
│ │ ├── basics_intro_halite.js
│ │ ├── email.js
│ │ ├── game.js
│ │ ├── general.js
│ │ ├── index.js
│ │ ├── leaderTable.js
│ │ ├── leaderboard.js
│ │ ├── localVisualizer.js
│ │ ├── parsereplay.js
│ │ ├── recent_games.js
│ │ ├── status.js
│ │ ├── user.js
│ │ └── visualizer.js
│ ├── sql/
│ │ ├── dummyData.sql
│ │ ├── importDummyData.sh
│ │ ├── install.sh
│ │ └── schema.sql
│ ├── status.php
│ ├── style/
│ │ ├── general.css
│ │ └── learn.css
│ ├── terms_of_service.php
│ ├── tutorials/
│ │ ├── basic/
│ │ │ ├── BasicBot.cpp
│ │ │ ├── BasicBot.java
│ │ │ ├── BasicBot.py
│ │ │ └── BasicBot.rs
│ │ ├── bfs/
│ │ │ └── BfsBot.java
│ │ ├── machinelearning/
│ │ │ ├── MattBot.py
│ │ │ ├── TrainMatt.py
│ │ │ ├── hlt.py
│ │ │ ├── my_model_architecture.json
│ │ │ ├── my_model_weights.h5
│ │ │ └── networking.py
│ │ └── random/
│ │ ├── ImprovedRandom.cpp
│ │ ├── ImprovedRandom.java
│ │ └── ImprovedRandom.py
│ └── user.php
└── worker/
├── Dockerfile
├── archive.py
├── backend.py
├── buildDocker.sh
├── changeAPIKey.py
├── compiler.py
├── install.sh
├── runGame.sh
├── startWorkerScreen.sh
├── stopWorkerScreen.sh
└── worker.py
================================================
FILE CONTENTS
================================================
================================================
FILE: .gitattributes
================================================
# Linguist ignore
website/lib/* linguist-vendored=false
environment/core/json.hpp linguist-vendored=false
environment/tclap/* linguist-vendored=false
# Auto detect text files and perform LF normalization
* text=auto
# Custom for Visual Studio
*.cs diff=csharp
# Standard to msysgit
*.doc diff=astextplain
*.DOC diff=astextplain
*.docx diff=astextplain
*.DOCX diff=astextplain
*.dot diff=astextplain
*.DOT diff=astextplain
*.pdf diff=astextplain
*.PDF diff=astextplain
*.rtf diff=astextplain
*.RTF diff=astextplain
================================================
FILE: .gitignore
================================================
###################
## Visual Studio ##
###################
# User-specific files
*.suo
*.user
*.userosscache
*.sln.docstates
# User-specific files (MonoDevelop/Xamarin Studio)
*.userprefs
# Build results
[Dd]ebug/
[Dd]ebugPublic/
[Rr]elease/
[Rr]eleases/
x64/
x86/
build/
bld/
[Bb]in/
[Oo]bj/
# Visual Studo 2015 cache/options directory
.vs/
# MSTest test Results
[Tt]est[Rr]esult*/
[Bb]uild[Ll]og.*
# NUNIT
*.VisualState.xml
TestResult.xml
# Build Results of an ATL Project
[Dd]ebugPS/
[Rr]eleasePS/
dlldata.c
*_i.c
*_p.c
*_i.h
*.ilk
*.meta
*.obj
*.pch
*.pdb
*.pgc
*.pgd
*.rsp
*.sbr
*.tlb
*.tli
*.tlh
*.tmp
*.tmp_proj
*.log
*.vspscc
*.vssscc
.builds
*.pidb
*.svclog
*.scc
# Chutzpah Test files
_Chutzpah*
# Visual C++ cache files
ipch/
*.aps
*.ncb
*.opensdf
*.sdf
*.cachefile
# Visual Studio profiler
*.psess
*.vsp
*.vspx
# TFS 2012 Local Workspace
$tf/
# Guidance Automation Toolkit
*.gpState
# ReSharper is a .NET coding add-in
_ReSharper*/
*.[Rr]e[Ss]harper
*.DotSettings.user
# JustCode is a .NET coding addin-in
.JustCode
# TeamCity is a build add-in
_TeamCity*
# DotCover is a Code Coverage Tool
*.dotCover
# NCrunch
_NCrunch_*
.*crunch*.local.xml
# MightyMoose
*.mm.*
AutoTest.Net/
# Web workbench (sass)
.sass-cache/
# Installshield output folder
[Ee]xpress/
# DocProject is a documentation generator add-in
DocProject/buildhelp/
DocProject/Help/*.HxT
DocProject/Help/*.HxC
DocProject/Help/*.hhc
DocProject/Help/*.hhk
DocProject/Help/*.hhp
DocProject/Help/Html2
DocProject/Help/html
# Click-Once directory
publish/
# Publish Web Output
*.[Pp]ublish.xml
*.azurePubxml
# TODO: Comment the next line if you want to checkin your web deploy settings
# but database connection strings (with potential passwords) will be unencrypted
*.pubxml
*.publishproj
# NuGet Packages
*.nupkg
# The packages folder can be ignored because of Package Restore
**/packages/*
# except build/, which is used as an MSBuild target.
!**/packages/build/
# Uncomment if necessary however generally it will be regenerated when needed
#!**/packages/repositories.config
# Windows Azure Build Output
csx/
*.build.csdef
# Windows Store app package directory
AppPackages/
# Others
*.[Cc]ache
ClientBin/
[Ss]tyle[Cc]op.*
~$*
*~
*.dbmdl
*.dbproj.schemaview
*.pfx
*.publishsettings
node_modules/
bower_components/
# RIA/Silverlight projects
Generated_Code/
# Backup & report files from converting an old project file
# to a newer Visual Studio version. Backup files are not needed,
# because we have git ;-)
_UpgradeReport_Files/
Backup*/
UpgradeLog*.XML
UpgradeLog*.htm
# SQL Server files
*.mdf
*.ldf
# Business Intelligence projects
*.rdl.data
*.bim.layout
*.bim_*.settings
# Microsoft Fakes
FakesAssemblies/
# Node.js Tools for Visual Studio
.ntvs_analysis.dat
# Visual Studio 6 build log
*.plg
# Visual Studio 6 workspace options file
*.opt
#Java
*.class
# Mobile Tools for Java (J2ME)
.mtj.tmp/
# Package Files #
*.jar
*.war
*.ear
# virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml
hs_err_pid*
#Doc Ordner
*.class
*.pkh
*.ctxt
*.bluej
.DS_Store
#Friggin VS
*.sln
*.vcxproj
*.vcxproj.filters
*.vcxproj.user
*.vcxproj
Halite/Visualizer/Visualizer.vcxproj
Halite/Visualizer/Visualizer.exe
############
## Python ##
############
__pycache__/
*.py[cod]
*$py.class
# C extensions
*.so
# Distribution / packaging
.Python
env/
build/
develop-eggs/
dist/
eggs/
.eggs/
*.o
lib64/
parts/
sdist/
var/
*.egg-info/
.installed.cfg
*.egg
# PyInstaller
# Usually these files are written by a python script from a template
# before PyInstaller builds the exe, so as to inject date/other infos into it.
*.manifest
*.spec
# Installer logs
pip-log.txt
pip-delete-this-directory.txt
# Unit test / coverage reports
htmlcov/
.tox/
.coverage
.coverage.*
.cache
nosetests.xml
coverage.xml
*,cover
.hypothesis/
# Translations
*.mo
*.pot
# Django stuff:
*.log
# Sphinx documentation
docs/_build/
# PyBuilder
target/
#############
## Clojure ##
#############
pom.xml
*jar
airesources/Clojure/lib
native
.lein-failures
checkouts
.lein-deps-sum
#############
## Node.js ##
#############
# Logs
logs
npm-debug.log*
# Runtime data
pids
*.pid
*.seed
*.pid.lock
# Directory for instrumented libs generated by jscoverage/JSCover
lib-cov
# Coverage directory used by tools like istanbul
coverage
# nyc test coverage
.nyc_output
# Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files)
.grunt
# node-waf configuration
.lock-wscript
# Compiled binary addons (http://nodejs.org/api/addons.html)
build/Release
# Dependency directories
node_modules
jspm_packages
# Optional npm cache directory
.npm
# Optional eslint cache
.eslintcache
# Optional REPL history
.node_repl_history
# Output of 'npm pack'
*.tgz
# Yarn Integrity file
.yarn-integrity
##############
## Composer ##
##############
composer.phar
vendor/
composer.lock
##########
## Atom ##
##########
.atom-build.yml
##########
## Rust ##
##########
target/
Cargo.lock
**/*.rs.bk
###########
## OCaml ##
###########
*.annot
*.cmo
*.cma
*.cmi
*.a
*.o
*.cmx
*.cmxs
*.cmxa
# ocamlbuild working directory
_build/
# ocamlbuild targets
*.byte
*.native
# oasis generated files
setup.data
setup.log
############
## Halite ##
############
Values.sql
storage/
config.php
workingPath/
*.ini
!travisTests.ini
*.swp
*.gch
*.exe
environment/halite
worker/halite
git_pull.php
*.zip
*.7z
*.gz
!BasicJavaBot.zip
# VS Code
.vscode
airesources/C++/MyBot
airesources/C++/BasicBot
airesources/*/halite
leaderboard.png
worker/[0-9]*
environment/visualizer
environment/shaders
environment/fonts
HaliteEnvironment-Mac
HaliteEnvironment-Debian
downloads/
keys/
starterpackages/
*.pem
*.ppk
*.hlt
!interestingGame.hlt
google*.html
screenlog.*
*.dll
node_modules
/dist
================================================
FILE: .travis.yml
================================================
sudo: required
dist: trusty
language: cpp
services:
- mysql
addons:
apt:
packages:
- mysql-server-5.6
- mysql-client-core-5.6
- mysql-client-5.6
install:
- cd ~/build/HaliteChallenge/Halite/tests
- cp travisTests.ini tests.ini
- cp travisTests.ini ../halite.ini
- cd ~/build/HaliteChallenge/Halite/website
- sudo ./install.sh
- cd ~/build/HaliteChallenge/Halite/worker
- sudo ./install.sh 123
- cd ~/build/HaliteChallenge/Halite/tests
- sudo ./install.sh
- export CXX="g++-4.9"
script:
- cd ~/build/HaliteChallenge/Halite/tests/
- sudo ./runTests.sh
notifications:
slack: halite:HnrNM3effc9q8ZVvT7PqsSYC
================================================
FILE: CONTRIBUTING.md
================================================
# Halite Contributing Guide
If you find a bug or have a feature request, please [open an issue](https://github.com/HaliteChallenge/Halite/issues/new).
Want to help out? Have you implemented a patch or a new feature? Send us a pull request! If you are looking for things to do, check out [our open issues](https://github.com/HaliteChallenge/Halite/issues).
## Common Contributions
### Writing a Starter Package
If you'd like to write a starter package for a new language, see this [guide](https://halite.io/advanced_writing_sp.php).
### Adding Your Company or University
Edit [this whitelist](https://github.com/HaliteChallenge/Halite/edit/master/website/organizationWhitelist.txt) and send us a pull request. If you need to change your email, head [here](https://halite.io/email.php). We'll make sure to tag all members of your organization who have already signed up.
## Folder Contents
- `admin/` - A collection of administrative resources (ex. a technical specification)
- `airesources/` - The language-specific starter kits for writing bots
- `environment/` - The halite game engine
- `tests/` - All of the project's unit and integration tests
- `website/` - The website that hosts the competition. Includes the API that manages the game servers.
- `worker/` - The source for the worker servers that compile bots and run games safely
## Installing the website on Ubuntu
Clone the repo:
git clone https://github.com/HaliteChallenge/Halite.git
Run the website install script with root user permissions. This will install php, apache, python (and some python modules), and composer (and some composer packages):
cd website; sudo ./install.sh
Run the database install script with root user permissions. This will install mysql and insert our schema into a database titled Halite.
cd sql; sudo ./install.sh
Create a `halite.ini` file using your favorite text editor in the root project directory. Place information about your local database setup in there. Your `halite.ini` file should look like this;
[database]
hostname = 127.0.0.1
username = YOUR_LOCAL_MYSQL_USERNAME
password = YOUR_LOCAL_MYSQL_PASSWORD
name = Halite
================================================
FILE: LICENSE
================================================
The MIT License
Copyright (c) 2016 Michael Truell and Benjamin Spector
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
================================================
FILE: README.md
================================================
# Halite
[](https://travis-ci.org/HaliteChallenge/Halite)
[](https://raw.githubusercontent.com/HaliteChallenge/Halite/master/LICENSE)
Halite is a programming competition. Contestants write bots to play an original multi-player turn-based strategy game played on a rectangular grid. For more information about the game, visit [our website](http://halite.io).
## Contributing
See [the Contributing Guide](CONTRIBUTING.md).
## Questions
See [the Forums](http://2016.forums.halite.io) and [our Discord chat](https://discordapp.com/invite/rbVDB4n).
## Authors
Halite was primarily created by [Ben Spector](https://github.com/Sydriax) and [Michael Truell](https://github.com/truell20) for Two Sigma during their summer 2016 internship.
Many others contributed to Halite's developement, including [Matt Adereth](https://github.com/adereth), [Trammell Hudson](https://github.com/osresearch), and Jaques Clapauch from Two Sigma and [Arnaud Sahuguet](https://github.com/sahuguet) and [Scot Spinner](https://github.com/awesomescot) from Cornell Tech. Halite's participants, including [Nick Malaguti](https://github.com/nmalaguti), [Travis Erdman](https://github.com/erdman), and [Janzert](https://github.com/janzert), have also been instrumental to the project.
================================================
FILE: admin/checkTaskCompletion.py
================================================
#!/usr/bin/env python3
import configparser
import time
from datetime import datetime
import pymysql
parser = configparser.ConfigParser()
parser.read("../halite.ini")
DB_CONFIG = parser["database"]
def check_compiles(db):
db.begin()
with db.cursor() as cursor:
cursor.execute("SELECT COUNT(*) FROM User WHERE compileStatus != 0")
return cursor.fetchone()['COUNT(*)']
def check_workers(db, start_time):
db.begin()
with db.cursor() as cursor:
cursor.execute("SELECT workerID, lastRequestTime FROM Worker ORDER BY workerID")
workers = cursor.fetchall()
waiting = list()
for w in workers:
if w["lastRequestTime"] < start_time:
waiting.append(w)
return waiting
def main():
if ("compState" not in parser or "noGameTasks" not in parser["compState"] or
not parser["compState"]["noGameTasks"]):
print(parser["compState"]["noGameTasks"])
print("Game tasks still activated. Disable in halite.ini [compState] noGameTasks")
return
start_time = datetime.now()
db = pymysql.connect(host=DB_CONFIG['hostname'], user=DB_CONFIG['username'], passwd=DB_CONFIG['password'], db=DB_CONFIG['name'], cursorclass=pymysql.cursors.DictCursor)
compiles = 1
workers = [1]
while compiles or workers:
compiles = check_compiles(db)
workers = check_workers(db, start_time)
if compiles:
print("Waiting for %d more compiles to complete." % (compiles,))
if workers:
print("Waiting for workers: ", end="")
print(", ".join(str(w["workerID"]) for w in workers[:5]), end="")
if len(workers) > 5:
print(" and %d more" % (len(workers) - 5,))
else:
print()
time.sleep(5)
db.begin()
with db.cursor() as cursor:
cursor.execute("SELECT MAX(gameID) FROM Game")
max_game = cursor.fetchone()["MAX(gameID)"]
print("All tasks completed, last gameID %d." % (max_game,))
if __name__ == "__main__":
main()
================================================
FILE: admin/commandRunner.py
================================================
import pymysql
import threading
import configparser
import sys
import os
import os.path
def runOnWorker(worker, keyPath, command):
print("########"+worker['ipAddress']+"########")
os.system("ssh -oStrictHostKeyChecking=no -i \""+keyPath+"\" ubuntu@"+worker['ipAddress']+" '"+command+"'")
print("########"+worker['ipAddress']+"########")
parser = configparser.ConfigParser()
parser.read("../halite.ini")
DB_CONFIG = parser["database"]
keyPath = os.path.join("../", parser["aws"]["keyfilepath"])
db = pymysql.connect(host=DB_CONFIG["hostname"], user=DB_CONFIG['username'], passwd=DB_CONFIG['password'], db=DB_CONFIG['name'], cursorclass=pymysql.cursors.DictCursor)
cursor = db.cursor()
cursor.execute("select * from Worker")
workers = cursor.fetchall()
command = sys.argv[1]
isAsync = False if len(sys.argv) < 3 else int(sys.argv[2]) == 1
if isAsync:
threads = []
for worker in workers:
t = threading.Thread(target=runOnWorker, args = (worker, keyPath, command))
t.daemon = True
t.start()
threads.append(t)
for t in threads:
t.join()
else:
for worker in workers:
runOnWorker(worker, keyPath, command)
================================================
FILE: admin/cost.py
================================================
dimensions = [(1, 20), (2, 25), (3, 30), (4, 35), (3, 40), (2, 45), (1, 50)]
averagePlayersPerGame = 4
playersPerServers = 15.6
perServerCost = 3*4.68
averagePlayers = 4000
totalTime = 0
totalMatches = 0
for dimension in dimensions:
totalMatches += dimension[0]
totalTime += dimension[0] * (15000 + pow(dimension[1], 3)*10/3)
timePerPlayerPerMatch = totalTime*averagePlayers/(averagePlayersPerGame*(averagePlayers/playersPerServers)*totalMatches)
print("Time per match per player in minutes: " + str(timePerPlayerPerMatch/(60*1000)))
costPerPlayer = perServerCost/playersPerServers
print("Cost per player: " + str(costPerPlayer))
totalCost = perServerCost*(averagePlayers/playersPerServers)
print("Total cost: " + str(totalCost))
================================================
FILE: admin/cron/haliteEmailer.py
================================================
import smtplib
from email.mime.text import MIMEText
def sendEmail(senderEmail, senderPassword, subject, body, recipient):
print("Sending email")
msg = MIMEText(body, "html")
msg['Subject'] = subject
msg['From'] = senderEmail
msg['To'] = recipient
s = smtplib.SMTP('smtp.gmail.com:587')
s.ehlo()
s.starttls();
s.login(senderEmail, senderPassword)
s.sendmail(senderEmail, [recipient], msg.as_string())
s.quit()
================================================
FILE: admin/cron/install.sh
================================================
apt-get update
apt-get install -y python3 python3-pip linkchecker
pip3 install configparser pymysql
================================================
FILE: admin/cron/linkChecker.py
================================================
#!/usr/bin/env python3
import configparser
import subprocess
import haliteEmailer
parser = configparser.ConfigParser()
parser.read("../../halite.ini")
HALITE_EMAIL = parser["email"]["email"]
HALITE_EMAIL_PASSWORD = parser["email"]["password"]
command = 'linkchecker --ignore-url=^mailto: --timeout=20 https://halite.io/'
proc = subprocess.Popen(command, shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
stdout, stderr = proc.communicate()
stdout = stdout.decode('utf-8')
stderr = stderr.decode('utf-8')
if stdout.split("\n")[-3].find("0 errors") == -1:
haliteEmailer.sendEmail(HALITE_EMAIL, HALITE_EMAIL_PASSWORD, "LINK ALERT", "There seem to be some broken links on http://halite.io/.
Here is what was given as the output of \""+command+"\" (You will probably want more verbose output and so will have to run the command yourself).
STDOUT:
"+stderr+"
STDERR:
"+stderr+"", HALITE_EMAIL)
================================================
FILE: admin/cron/workerChecker.py
================================================
#!/usr/bin/env python3
import configparser
import pymysql
import haliteEmailer
parser = configparser.ConfigParser()
parser.read("../../halite.ini")
DB_CONFIG = parser["database"]
HALITE_EMAIL = parser["email"]["email"]
HALITE_EMAIL_PASSWORD = parser["email"]["password"]
db = pymysql.connect(host=DB_CONFIG["hostname"], user=DB_CONFIG['username'], passwd=DB_CONFIG['password'], db=DB_CONFIG['name'])
cursor = db.cursor()
cursor.execute("select * from Worker WHERE TIMESTAMPDIFF(MINUTE, lastRequestTime, NOW()) > 30")
results = cursor.fetchall()
if len(results) == 0:
print("All good!")
else:
message = "Some workers haven't communicated with the manager in a while!
"
haliteEmailer.sendEmail(HALITE_EMAIL, HALITE_EMAIL_PASSWORD, str(len(results))+" workers down", message, HALITE_EMAIL)
================================================
FILE: admin/md/DISASTER.md
================================================
# Disaster Scenarios
### Restarting each component
#### Mysql DB
SSH into the AWS instance hosting the database.
$ sudo service mysql restart
#### Website backend and Manger
SSH into the AWS instance hosting the website and manager.
$ sudo service apache2 restart
#### Workers
On your local machine, assuming that your halite.ini is configured correctly and the database is up:
$ cd admin
$ python3 commandRunner.py 'cd Halite/worker; sudo ./stopWorkerScreen.sh; ./startWorkerScreen.sh'
Let's go over that last line. The `commandRunner.py` script uses ssh to run arbitrary bash commands on all of our workers. You pass it your desired bash command as a command line arguement (in this case `cd Halite/worker; ...`). The `sudo ./stopWorkerScreen.sh` command will kill all of the screens on a worker (and therefore the process that is running `worker.py`) and will stop and remove all docker containers on a worker. `./startWorkerScreen.sh` starts a detached screen and runs `python3 worker.py` in it.
***Note:*** This will have to be updated soon. AWS doesn't let you login as root over ssh.
### Bad bot submitted
### Account DDOS
### Renew/Reinstall SSL
Run:
$ certbot-auto --apache -d halite.io -d www.halite.io
You will be presented with a couple of cursese menus. Renewing the certificate should be tried first. "Easy" (both http and https) should be picked instead of "Secure."
### Restarting from MySQL database backup
***These steps will delete all data in the production db***
Login to the backup server over SFTP using your favorite SFTP client ([Filezilla](https://filezilla-project.org/) is quite good). Navigate into the `/backup/db` folder. Grab the newest file (also the file that starts with the biggest number as these files are named by the timestamp when they were created).
Transfer this file to the home directory of the DB server directly or by downloading it to your local computer, logging into the DB server over SFTP, and then uploading it to the DB server.
SSH into the db server, and:
$ echo "drop database Halite; create database Halite;" | mysql -u root -p
$ mysql -u root -p Halite < NAME_OF_THE_SQL_FILE.sql
================================================
FILE: admin/md/INSTALL.md
================================================
# Installation
If you have not already:
git clone https://github.com/HaliteChallenge/Halite.git
### Website/Manager Server Setup
$ cd website && ./install.sh
Check that you are on php >= 5.6 and mysql >= 5.6.5:
$ `php -v; mysql -V
Symlink the repo to /var/www:
ln -s ~/Halite /var/www
Create and write a halite.ini file in the root directory of the project
Finish Apache setup:
* [Allow the following of symlinks by apache](http://superuser.com/questions/244245/how-do-i-get-apache-to-follow-symlinks)
* [Allow .htaccess override](http://stackoverflow.com/a/22526144)
* [Redirect root directory to website directory](http://serverfault.com/questions/9992/how-to-get-apache2-to-redirect-to-a-subdirectory)
* [Increase your max file upload size (worker's posting large replays, users posting big bot archives)](http://stackoverflow.com/questions/2184513/php-change-the-maximum-upload-file-size)
To setup automatic backups on the website server, copy the `backupWebsite` file in the `Halite/website/cron` folder into the server's `/etc/cron.hourly` folder, change the IP address in the file to that of the backup server, and make sure that the ssh key of the website server is in the `~/.ssh/authorized_keys` file on the backup server. Once copied, mark the `backupWebsite` file as executable and give cron permission to execute it like so:
cd /etc/cron.hourly
chmod +x backupWebsite
chmod 755 backupWebsite
### Database server setup
$ cd website/sql && ./install.sh
Add a superuser by wildcarding its host and allowing remote login. In the MySQL shell:
CREATE USER 'superuser'@'%' IDENTIFIED BY 'SOME_RANDOM_PASSWORD';
GRANT ALL PRIVILEGES ON *.* TO 'superuser'@'%' IDENTIFIED BY 'SOME_RANDOM_PASSWORD' WITH GRANT OPTION;
FLUSH PRIVILEGES;
To finish superuser setup, comment out `bind-address = 127.0.0.1` in `/etc/mysql/my.cnf`, and:
$ sudo service mysql restart
For ease of use of the mysql on the command line and for install scripts to be guranteed to run smoothly, please edit your `~/.my.cnf` to include these lines:
[mysqldump]
user=MYSQL_USERNAME
password=MYSQL_PASSWORD
[client]
user=MYSQL_USERNAME
password=MYSQL_PASSWORD
To setup automatic backups on the db server, copy the `backupDatabase` file in the `Halite/website/cron` folder into the server's `/etc/cron.hourly` folder, change the IP address in the file to the one of the backup server, and make sure that the ssh key of the db server is in the `~/.ssh/authorized_keys` file on the backup server. Once copied, mark the `backupDatabase` file as executable and give anyone permission to execute it like so:
cd /etc/cron.hourly
chmod +x backupDatabase
chmod 755 backupDatabase
### Worker server setup
***Note:*** Make sure that your `halite.ini` file points to the proper AWS key pair.
On your local machine:
$ cd website/php && python3 openNewWorker.py
================================================
FILE: admin/md/SPEC.md
================================================
# Halite Specification
Halite is an online programming challenge. Users write bots to play a simple, original game with the following rule set:
* Bots may move their pieces either north, south, east, or west every turn or choose to remain still.
* If a piece stays still, it gains strength equal to the production value of the current tile that it is on.
* If a piece moves onto a piece with the same owner, their strengths combine. Strength values are cut off at 255.
* A piece inflicts damage equal to its strength onto all adjacent pieces that are not maps squares but have a different owner and onto to all coinciding pieces that have a different owner (this includes map squares).
* When a piece has a strength < 0, it dies.
Users develop their bots locally using our game engine, zip and submit their source to our website when they are ready to test out their bot, and watch as their bot plays against others and is ranked on our leaderboard.
**Note:** This spec details how the project currently fuctions. Changes will be made before the public launch.
### Environment
The environment is written in C++ with no dependencies. The environment starts bot processes using the start commands given to it through the command line. It then communicates with bots over stdin and stdout, sending them the map and recieving their moves. A switch to using sockets for bot communication is planned. The environment outputs a replay file, with the `hlt` extension, which may be visualized [here](http://halite.io/game.php).
### Website
The frontend of halite.io is written in HTML, CSS, and Javascript. The Bootstrap 3 CSS library is used for styling. The Pixi javascript library is used for our game visualizer. The JQuery library is used for DOM manipulation and for AJAX calls. HTML files are classified as PHP files to allow the easy including of repeating HTML elements (i.e. the navigation bar). No templating is used at all on the frontend. All interactions with our backend are done through REST calls made through the JQuery AJAX library.
The backend is written in PHP. Apache is used as its webserver.
The server on which the website is hosted also hosts the manager.
To update the version of the site on the server, just:
cd ~/Halite && git pull
### HCE
The "HCE"(Halite Competition Environment) is what we call the system of servers that compiles the source code of each contestant, runs games between bots, and ranks each submission. The system consists of many worker servers and one manager server.
Worker servers query the manager server for tasks, either a compile task or a game task. If there is any bot that needs to be compiled, the manager will respond with a compile task. If there are no compile tasks, the manager will respond with a game task, which is chosen like so:
* A seed plager is chosen by picking the bot with the highest `rand()*(sigma^2)`. "Sigma" is the level of uncertainty in the Trueskill score of a bot
* An allowed rank difference `d` is computed as: `5 / rand()^0.65`
* The number of players `n` is picked at random from a range of 2-6
* The other `n-1` players are chosen at random from the players within `d`
* The width and height of the map is chosen from a range of 20-50
Once given the ID of the bot(s) that they are compiling/running, workers query the manager for the executables and source of each bot. After compilation, the resulting binary+source mix is posted to the manager. These are removed from the disk on the worker server on completion of a task.
During both compilation and runtime, bots are run within their own Docker container. Networking, RAM, CPU, and disk access is limited.
### Database
A MySQL server (5.7.1) is used as the database for the project. Our MySQL server runs on RDS.
### File Storage
Error logs, replay files, and bot source are hosted on AWS S3 standard storage.
### Forums
[The discourse forum software](https://www.discourse.org/) is used. User authentication is handled on our end through [discourse's sso](https://meta.discourse.org/t/official-single-sign-on-for-discourse/13045). The forums are run on their own server (2 GB of RAM, Ubuntu 14.04 64 bit). Automated emails are sent through halite@halite.io, using gmail as a service provider. We will migrate away from gmail for the public launch since they have quite a low cap on the number of messages per day.
### Backups
RDS backups are turned on.
### Admin Tools
A simple python script (`manager/commandRunner.py`) is used to run arbitrary commands on all of the workers listed in the `halite.ini` file.
A status page located at `halite.io/status.php` includes the time since every worker has queried the manager, the throughput of the HCE, and general stats about our user base. Google analytics is included on the site.
### Monitoring Tools
We use a series of cron jobs to alert us if one of the workers hasn't responded for a number of minutes and to alert us if there are any broken links on the site.
We plan on setting up pingdom/pagerduty to alert us of downtime.
### Configuration Files
An INI file, titled `halite.ini` and located in the root directory of the project, is used for all of our project configurations. Here is a sample halite.ini file:
```
[hce]
managerURl = http://localhost/manager/
apiKey = 1234
secretFolder = FAKE_FOLDER_NAME
[workerIPs]
FAKE_WORKER_NAME = 123.456.789.000
[email]
email = FAKE_EMAIL
password = FAKE_PASSWORD
[database]
hostname = localhost
username = root
password = pass123
name = MAIN_DB_NAME
[sso]
secret = SECRET_KEY_FORUMS
url = SINGLE_SIGN_ON_FORUMS
[forums]
apiUsername = FAKE_USERNAME
apiKey = 1234567890
[encrypt]
salt = abc123456789
[aws]
accesskey = 1234556
secretaccesskey = 1234561238378
amiid = ami-2d39803a
keyname = RandomKeyName
instancetype = t2.nano
securitygroupname = security-group-name
keyfilepath = NameOfKeyFile.pem
```
### Server Setup
Each of our servers run Ubuntu 14.04. A brief textual description of our server setup:
* One server runs the website and manager.
* Another server runs the database.
* Another server runs the forums.
* Another server runs a series of cron jobs that check for broken links or downed workers.
* Each worker runs is on its own server.
Below is a basic diagram of our server setup.

================================================
FILE: admin/md/STARTER_PACKAGE_CHECKLIST.md
================================================
Starter Package Checklist
* Make sure all proper files are present (MyBot, RandomBot, runGame.sh, runGame.bat)
* Add dependencies to docker file
* Test on game servers
* Add to archive script
* Add to downloads
* Update game server reference
================================================
FILE: admin/rankReset.py
================================================
#!/usr/bin/env python3
import configparser
import pymysql
parser = configparser.ConfigParser()
parser.read("../halite.ini")
DB_CONFIG = parser["database"]
def main():
confirm = input("This will clear all current ranks, are you sure? [y/N] ")
if confirm != "y":
return
db = pymysql.connect(host=DB_CONFIG["hostname"], user=DB_CONFIG['username'], passwd=DB_CONFIG['password'], db=DB_CONFIG['name'], cursorclass=pymysql.cursors.DictCursor)
cursor = db.cursor()
cursor.execute("SELECT COUNT(*) FROM User WHERE isRunning=1")
num_active = cursor.fetchone()['COUNT(*)']
cursor.execute("INSERT INTO UserHistory (userID, versionNumber, lastRank, lastNumPlayers, lastNumGames) SELECT userID, numSubmissions, rank, %d, numGames FROM User WHERE isRunning=1" % (num_active,))
cursor.execute("UPDATE User SET numSubmissions=numSubmissions+1, numGames=0, mu=25.0, sigma=8.333 WHERE isRunning=1")
db.commit()
db.close()
print("All ranks successfully reset.")
if __name__ == "__main__":
main()
================================================
FILE: admin/updateOrgs.py
================================================
import configparser
import pymysql
import urllib.request
parser = configparser.ConfigParser()
parser.read("../halite.ini")
DB_CONFIG = parser["database"]
db = pymysql.connect(host=DB_CONFIG["hostname"], user=DB_CONFIG['username'], passwd=DB_CONFIG['password'], db=DB_CONFIG['name'], cursorclass=pymysql.cursors.DictCursor)
cursor = db.cursor()
cursor.execute("select email, userID, organization from User")
users = cursor.fetchall()
orgs = [line.strip().split(" - ") for line in open("../website/organizationWhitelist.txt").readlines()]
for user in users:
if user["email"] == None:
continue
realUserOrg = "Other"
try:
emailDomain = user["email"].split("@")[1]
except:
pass
for org in orgs:
if emailDomain == org[1]:
realUserOrg = org[0]
break
if (realUserOrg != "Other" or user["organization"] == "") and realUserOrg != user["organization"]:
print("%s, %s, %s" % (realUserOrg, user["organization"], user["email"]))
cursor.execute("update User set organization = '"+realUserOrg+"' where userID="+str(user["userID"]))
db.commit()
================================================
FILE: airesources/C/MyBot.c
================================================
#include
#include
#include
#include "hlt.h"
#define BOT_NAME "MyCBot"
int main(void) {
GAME game;
int x, y, direction;
srand(time(NULL));
game = GetInit();
SendInit(BOT_NAME);
while (1) {
GetFrame(game);
for (x = 0 ; x < game.width ; x++) {
for (y = 0 ; y < game.height ; y++) {
if (game.owner[x][y] == game.playertag) {
direction = rand() % 5;
SetMove(game, x, y, direction);
}
}
}
SendFrame(game);
}
return 0;
}
================================================
FILE: airesources/C/RandomBot.c
================================================
#include
#include
#include
#include "hlt.h"
#define BOT_NAME "RandomCBot"
int main(void) {
GAME game;
int x, y, direction;
srand(time(NULL));
game = GetInit();
SendInit(BOT_NAME);
while (1) {
GetFrame(game);
for (x = 0 ; x < game.width ; x++) {
for (y = 0 ; y < game.height ; y++) {
if (game.owner[x][y] == game.playertag) {
direction = rand() % 5;
SetMove(game, x, y, direction);
}
}
}
SendFrame(game);
}
return 0;
}
================================================
FILE: airesources/C/hlt.h
================================================
/*
In general, none of the public functions return pointers,
nor do they take pointer arguments.
Useful functions:
GAME GetInit()
void SendInit(char *botname)
void GetFrame(GAME game)
void SetMove(GAME game, int x, int y, int direction)
void SendFrame(GAME game)
Convenience functions:
SITE GetSiteFromXY(GAME game, int x, int y)
SITE GetSiteFromMovement(GAME game, int src_x, int src_y, int direction)
Pssst! More documentation and some better bots are at:
https://github.com/fohristiwhirl/chalite
*/
#include
#include
#define STILL 0
#define NORTH 1
#define EAST 2
#define SOUTH 3
#define WEST 4
typedef struct Site_struct {
int x;
int y;
int owner;
int strength;
int production;
} SITE;
typedef struct Game_struct {
int width;
int height;
int playertag;
int ** moves;
int ** owner;
int ** production;
int ** strength;
} GAME;
int ** __new_2d_int_array(int width, int height) {
int x;
int **result;
result = malloc(sizeof(int*) * width);
if (result == NULL) {
printf("Malloc 1 failed in __new_2d_int_array()\n");
exit(1);
}
for (x = 0 ; x < width ; x++) {
result[x] = malloc(sizeof(int) * height);
if (result[x] == NULL) {
printf("Malloc 2 failed in __new_2d_int_array()\n");
exit(1);
}
}
return result;
}
int __getnextint() {
int ch;
int result = 0;
int seen_any_digits = 0;
while (1) {
ch = getchar();
if (ch == EOF) {
printf("EOF received. Halite engine quit?\n");
exit(1);
}
if (ch >= 48 && ch <= 57) {
seen_any_digits = 1;
result *= 10;
result += ch - 48;
} else {
if (seen_any_digits) {
return result;
}
}
}
return 54321; // Never get here.
}
void __parseproduction(GAME game) {
int x, y;
for (y = 0 ; y < game.height ; y++) {
for (x = 0 ; x < game.width ; x++) {
game.production[x][y] = __getnextint();
}
}
return;
}
void __parsemap(GAME game) {
int x, y;
int run;
int owner;
int total_set;
int set_this_run;
x = 0;
y = 0;
total_set = 0;
set_this_run = 0;
while (total_set < game.width * game.height) {
run = __getnextint();
owner = __getnextint();
for (set_this_run = 0 ; set_this_run < run ; set_this_run++) {
game.owner[x][y] = owner;
total_set++;
x++;
if (x == game.width) {
x = 0;
y += 1;
}
}
}
for (y = 0 ; y < game.height ; y++) {
for (x = 0 ; x < game.width ; x++) {
game.strength[x][y] = __getnextint();
}
}
return;
}
GAME GetInit() {
GAME game;
game.playertag = __getnextint();
game.width = __getnextint();
game.height = __getnextint();
game.moves = __new_2d_int_array(game.width, game.height);
game.owner = __new_2d_int_array(game.width, game.height);
game.production = __new_2d_int_array(game.width, game.height);
game.strength = __new_2d_int_array(game.width, game.height);
__parseproduction(game);
__parsemap(game);
return game;
}
void SendInit(char *botname) {
printf("%s\n", botname);
fflush(stdout);
}
void GetFrame(GAME game) {
int x, y;
__parsemap(game);
// Reset the moves array while we're at it.
for (x = 0 ; x < game.width ; x++) {
for (y = 0 ; y < game.height ; y++) {
game.moves[x][y] = STILL;
}
}
return;
}
int __sanitise_x(GAME game, int x) {
if (x < 0) {
x += -(x / game.width) * game.width + game.width; // Can make x == width, so must still use % next
}
x %= game.width;
return x;
}
int __sanitise_y(GAME game, int y) {
if (y < 0) {
y += -(y / game.height) * game.height + game.height; // Can make y == height, so must still use % next
}
y %= game.height;
return y;
}
SITE GetSiteFromXY(GAME game, int x, int y) {
SITE result;
x = __sanitise_x(game, x);
y = __sanitise_y(game, y);
result.x = x;
result.y = y;
result.owner = game.owner[result.x][result.y];
result.production = game.production[result.x][result.y];
result.strength = game.strength[result.x][result.y];
return result;
}
SITE GetSiteFromMovement(GAME game, int src_x, int src_y, int direction) {
SITE result;
int x, y;
x = src_x;
y = src_y;
switch (direction) {
case NORTH:
y--;
break;
case EAST:
x++;
break;
case SOUTH:
y++;
break;
case WEST:
x--;
break;
}
x = __sanitise_x(game, x);
y = __sanitise_y(game, y);
result = GetSiteFromXY(game, x, y);
return result;
}
void SetMove(GAME game, int x, int y, int direction) {
x = __sanitise_x(game, x);
y = __sanitise_y(game, y);
game.moves[x][y] = direction;
return;
}
void SendFrame(GAME game) {
int x, y;
for (x = 0 ; x < game.width ; x++) {
for (y = 0 ; y < game.height ; y++) {
if (game.moves[x][y] != STILL && game.owner[x][y] == game.playertag) {
printf("%d %d %d ", x, y, game.moves[x][y]);
}
}
}
printf("\n");
fflush(stdout);
return;
}
================================================
FILE: airesources/C/runGame.bat
================================================
gcc MyBot.c -o MyBot.exe
gcc RandomBot.c -o RandomBot.exe
.\halite.exe -d "30 30" "MyBot.exe" "RandomBot.exe"
================================================
FILE: airesources/C/runGame.sh
================================================
#!/bin/bash
gcc MyBot.c -o MyBot.o
gcc RandomBot.c -o RandomBot.o
./halite -d "30 30" "./MyBot.o" "./RandomBot.o"
================================================
FILE: airesources/C++/MyBot.cpp
================================================
#include
#include
#include
#include
#include
#include
#include
#include "hlt.hpp"
#include "networking.hpp"
int main() {
srand(time(NULL));
std::cout.sync_with_stdio(0);
unsigned char myID;
hlt::GameMap presentMap;
getInit(myID, presentMap);
sendInit("MyC++Bot");
std::set moves;
while(true) {
moves.clear();
getFrame(presentMap);
for(unsigned short a = 0; a < presentMap.height; a++) {
for(unsigned short b = 0; b < presentMap.width; b++) {
if (presentMap.getSite({ b, a }).owner == myID) {
moves.insert({ { b, a }, (unsigned char)(rand() % 5) });
}
}
}
sendFrame(moves);
}
return 0;
}
================================================
FILE: airesources/C++/RandomBot.cpp
================================================
#include
#include
#include
#include
#include
#include
#include
#include "hlt.hpp"
#include "networking.hpp"
int main() {
srand(time(NULL));
std::cout.sync_with_stdio(0);
unsigned char myID;
hlt::GameMap presentMap;
getInit(myID, presentMap);
sendInit("RandomC++Bot");
std::set moves;
while(true) {
moves.clear();
getFrame(presentMap);
for(unsigned short a = 0; a < presentMap.height; a++) {
for(unsigned short b = 0; b < presentMap.width; b++) {
if (presentMap.getSite({ b, a }).owner == myID) {
moves.insert({ { b, a }, (unsigned char)(rand() % 5) });
}
}
}
sendFrame(moves);
}
return 0;
}
================================================
FILE: airesources/C++/hlt.hpp
================================================
#ifndef HLT_H
#define HLT_H
#include
#include
#include
#define STILL 0
#define NORTH 1
#define EAST 2
#define SOUTH 3
#define WEST 4
const int DIRECTIONS[] = {STILL, NORTH, EAST, SOUTH, WEST};
const int CARDINALS[] = {NORTH, EAST, SOUTH, WEST};
namespace hlt{
struct Location{
unsigned short x, y;
};
static bool operator<(const Location& l1, const Location& l2) {
return ((l1.x + l1.y)*((unsigned int)l1.x + l1.y + 1) / 2) + l1.y < ((l2.x + l2.y)*((unsigned int)l2.x + l2.y + 1) / 2) + l2.y;
}
struct Site{
unsigned char owner;
unsigned char strength;
unsigned char production;
};
class GameMap{
public:
std::vector< std::vector > contents;
unsigned short width, height; //Number of rows & columns, NOT maximum index.
GameMap() {
width = 0;
height = 0;
contents = std::vector< std::vector >(height, std::vector(width, { 0, 0, 0 }));
}
GameMap(const GameMap &otherMap) {
width = otherMap.width;
height = otherMap.height;
contents = otherMap.contents;
}
GameMap(int w, int h) {
width = w;
height = h;
contents = std::vector< std::vector >(height, std::vector(width, { 0, 0, 0 }));
}
bool inBounds(Location l) {
return l.x < width && l.y < height;
}
float getDistance(Location l1, Location l2) {
short dx = abs(l1.x - l2.x), dy = abs(l1.y - l2.y);
if(dx > width / 2) dx = width - dx;
if(dy > height / 2) dy = height - dy;
return dx + dy;
}
float getAngle(Location l1, Location l2) {
short dx = l2.x - l1.x, dy = l2.y - l1.y;
if(dx > width - dx) dx -= width;
else if(-dx > width + dx) dx += width;
if(dy > height - dy) dy -= height;
else if(-dy > height + dy) dy += height;
return atan2(dy, dx);
}
Location getLocation(Location l, unsigned char direction) {
if(direction != STILL) {
if(direction == NORTH) {
if(l.y == 0) l.y = height - 1;
else l.y--;
}
else if(direction == EAST) {
if(l.x == width - 1) l.x = 0;
else l.x++;
}
else if(direction == SOUTH) {
if(l.y == height - 1) l.y = 0;
else l.y++;
}
else if(direction == WEST) {
if(l.x == 0) l.x = width - 1;
else l.x--;
}
}
return l;
}
Site& getSite(Location l, unsigned char direction = STILL) {
l = getLocation(l, direction);
return contents[l.y][l.x];
}
};
struct Move{
Location loc; unsigned char dir;
};
static bool operator<(const Move& m1, const Move& m2) {
unsigned int l1Prod = ((m1.loc.x + m1.loc.y)*((unsigned int)m1.loc.x + m1.loc.y + 1) / 2) + m1.loc.y, l2Prod = ((m2.loc.x + m2.loc.y)*((unsigned int)m2.loc.x + m2.loc.y + 1) / 2) + m2.loc.y;
return ((l1Prod + m1.dir)*(l1Prod + m1.dir + 1) / 2) + m1.dir < ((l2Prod + m2.dir)*(l2Prod + m2.dir + 1) / 2) + m2.dir;
}
}
#endif
================================================
FILE: airesources/C++/networking.hpp
================================================
#ifndef AI_NETWORKING_H
#define AI_NETWORKING_H
#include
#include
#include
#include
#include
#include
#include
#include
#include
#ifdef _WIN32
#include
#include
#include
#define WINSOCKVERSION MAKEWORD(2,2)
#else
#include
#include
#include
#include
#include
#endif
#include "hlt.hpp"
namespace detail{
static std::vector< std::vector > productions;
static int width, height;
static std::string serializeMoveSet(const std::set &moves) {
std::ostringstream oss;
for(auto a = moves.begin(); a != moves.end(); ++a) oss << a->loc.x << " " << a->loc.y << " " << (int)a->dir << " ";
return oss.str();
}
static void deserializeMapSize(const std::string & inputString) {
std::stringstream iss(inputString);
iss >> width >> height;
}
static void deserializeProductions(const std::string & inputString) {
std::stringstream iss(inputString);
productions.resize(height);
short temp;
for(auto a = productions.begin(); a != productions.end(); a++) {
a->resize(width);
for(auto b = a->begin(); b != a->end(); b++) {
iss >> temp;
*b = temp;
}
}
}
static hlt::GameMap deserializeMap(const std::string & inputString) {
std::stringstream iss(inputString);
hlt::GameMap map(width, height);
//Set productions
for(int a = 0; a < map.height; a++) {
for(int b = 0; b < map.width; b++) {
map.contents[a][b].production = productions[a][b];
}
}
//Run-length encode of owners
unsigned short y = 0, x = 0;
unsigned short counter = 0, owner = 0;
while(y != map.height) {
for(iss >> counter >> owner; counter; counter--) {
map.contents[y][x].owner = owner;
x++;
if(x == map.width) {
x = 0;
y++;
}
}
}
for (int a = 0; a < map.contents.size(); a++) {
for (int b = 0; b < map.contents[a].size(); b++) {
short strengthShort;
iss >> strengthShort;
map.contents[a][b].strength = strengthShort;
}
}
return map;
}
static void sendString(const std::string & sendString) {
if(sendString.length() < 1) std::cout << ' ' << std::endl; //Automatically flushes.
else std::cout << sendString << std::endl; //Automatically flushes.
}
static std::string getString() {
std::string newString;
std::getline(std::cin, newString);
return newString;
}
}
static void getInit(unsigned char& playerTag, hlt::GameMap& m) {
playerTag = (unsigned char)std::stoi(detail::getString());
detail::deserializeMapSize(detail::getString());
detail::deserializeProductions(detail::getString());
m = detail::deserializeMap(detail::getString());
}
static void sendInit(std::string name) {
detail::sendString(name);
}
static void getFrame(hlt::GameMap& m) {
m = detail::deserializeMap(detail::getString());
}
static void sendFrame(const std::set &moves) {
detail::sendString(detail::serializeMoveSet(moves));
}
#endif
================================================
FILE: airesources/C++/runGame.bat
================================================
g++ -std=c++11 MyBot.cpp -o MyBot.exe
g++ -std=c++11 RandomBot.cpp -o RandomBot.exe
.\halite.exe -d "30 30" "MyBot.exe" "RandomBot.exe"
================================================
FILE: airesources/C++/runGame.sh
================================================
#!/bin/bash
g++ -std=c++11 MyBot.cpp -o MyBot.o
g++ -std=c++11 RandomBot.cpp -o RandomBot.o
./halite -d "30 30" "./MyBot.o" "./RandomBot.o"
================================================
FILE: airesources/CSharp/Halite.csproj
================================================
Debug
AnyCPU
{1460A17A-7E8B-4643-B0A9-06A1B86F07E9}
Exe
Properties
Halite
Halite
v4.5.2
512
true
full
false
bin\Debug\
DEBUG;TRACE
prompt
4
pdbonly
true
bin\Release\
TRACE
prompt
4
Halite.MyBot
================================================
FILE: airesources/CSharp/HaliteHelper.cs
================================================
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Net;
using System.Net.Sockets;
///
/// Helpful for debugging.
///
public static class Log
{
private static string _logPath;
///
/// File must exist
///
public static void Setup(string logPath) {
_logPath = logPath;
}
public static void Information(string message) {
if (!string.IsNullOrEmpty(_logPath))
File.AppendAllLines(_logPath, new[] {string.Format("{0}: {1}", DateTime.Now.ToShortTimeString(), message)});
}
public static void Error(Exception exception) {
Log.Information(string.Format("ERROR: {0} {1}", exception.Message, exception.StackTrace));
}
}
public static class Networking
{
private static string ReadNextLine() {
var str = Console.ReadLine();
if (str == null) throw new ApplicationException("Could not read next line from stdin");
return str;
}
private static void SendString(string str) {
Console.WriteLine(str);
}
///
/// Call once at the start of a game to load the map and player tag from the first four stdin lines.
///
public static Map getInit(out ushort playerTag) {
// Line 1: Player tag
if (!ushort.TryParse(ReadNextLine(), out playerTag))
throw new ApplicationException("Could not get player tag from stdin during init");
// Lines 2-4: Map
var map = Map.ParseMap(ReadNextLine(), ReadNextLine(), ReadNextLine());
return map;
}
///
/// Call every frame to update the map to the next one provided by the environment.
///
public static void getFrame(ref Map map) {
map.Update(ReadNextLine());
}
///
/// Call to acknowledge the initail game map and start the game.
///
public static void SendInit(string botName) {
SendString(botName);
}
///
/// Call to send your move orders and complete your turn.
///
public static void SendMoves(IEnumerable moves) {
SendString(Move.MovesToString(moves));
}
}
public enum Direction
{
Still = 0,
North = 1,
East = 2,
South = 3,
West = 4
}
public struct Site
{
public ushort Owner { get; internal set; }
public ushort Strength { get; internal set; }
public ushort Production { get; internal set; }
}
public struct Location
{
public ushort X;
public ushort Y;
}
public struct Move
{
public Location Location;
public Direction Direction;
internal static string MovesToString(IEnumerable moves) {
return string.Join(" ", moves.Select(m => string.Format("{0} {1} {2}", m.Location.X, m.Location.Y, (int)m.Direction)));
}
}
///
/// State of the game at every turn. Use to get the map for a new game from
/// stdin, and use to update the map after orders for a turn have been executed.
///
public class Map
{
public void Update(string gameMapStr) {
var gameMapValues = new Queue(gameMapStr.Split(new[] {' '}, StringSplitOptions.RemoveEmptyEntries));
ushort x = 0, y = 0;
while (y < Height) {
ushort counter, owner;
if (!ushort.TryParse(gameMapValues.Dequeue(), out counter))
throw new ApplicationException("Could not get some counter from stdin");
if (!ushort.TryParse(gameMapValues.Dequeue(), out owner))
throw new ApplicationException("Could not get some owner from stdin");
while (counter > 0) {
_sites[x, y].Owner = owner;
x++;
if (x == Width) {
x = 0;
y++;
}
counter--;
}
}
var strengthValues = gameMapValues; // Referencing same queue, but using a name that is more clear
for (y = 0; y < Height; y++) {
for (x = 0; x < Width; x++) {
ushort strength;
if (!ushort.TryParse(strengthValues.Dequeue(), out strength))
throw new ApplicationException("Could not get some strength value from stdin");
_sites[x, y].Strength = strength;
}
}
}
///
/// Get a read-only structure representing the current state of the site at the supplied coordinates.
///
public Site this[ushort x, ushort y] {
get {
if (x >= Width)
throw new IndexOutOfRangeException(string.Format("Cannot get site at ({0},{1}) beacuse width is only {2}", x, y, Width));
if (y >= Height)
throw new IndexOutOfRangeException(string.Format("Cannot get site at ({0},{1}) beacuse height is only {2}", x, y, Height));
return _sites[x, y];
}
}
///
/// Get a read-only structure representing the current state of the site at the supplied location.
///
public Site this[Location location] => this[location.X, location.Y];
///
/// Returns the width of the map.
///
public ushort Width => (ushort)_sites.GetLength(0);
///
/// Returns the height of the map.
///
public ushort Height => (ushort)_sites.GetLength(1);
#region Implementation
private readonly Site[,] _sites;
private Map(ushort width, ushort height) {
_sites = new Site[width, height];
for (ushort x = 0; x < width; x++) {
for (ushort y = 0; y < height; y++) {
_sites[x, y] = new Site();
}
}
}
private static Tuple ParseMapSize(string mapSizeStr) {
ushort width, height;
var parts = mapSizeStr.Split(new[] {' '}, StringSplitOptions.RemoveEmptyEntries);
if (parts.Length != 2 || !ushort.TryParse(parts[0], out width) || !ushort.TryParse(parts[1], out height))
throw new ApplicationException("Could not get map size from stdin during init");
return Tuple.Create(width, height);
}
public static Map ParseMap(string mapSizeStr, string productionMapStr, string gameMapStr) {
var mapSize = ParseMapSize(mapSizeStr);
var map = new Map(mapSize.Item1, mapSize.Item2);
var productionValues = new Queue(productionMapStr.Split(new[] {' '}, StringSplitOptions.RemoveEmptyEntries));
ushort x, y;
for (y = 0; y < map.Height; y++) {
for (x = 0; x < map.Width; x++) {
ushort production;
if (!ushort.TryParse(productionValues.Dequeue(), out production))
throw new ApplicationException("Could not get some production value from stdin");
map._sites[x, y].Production = production;
}
}
map.Update(gameMapStr);
return map;
}
#endregion
}
================================================
FILE: airesources/CSharp/MyBot.cs
================================================
using System;
using System.Collections.Generic;
using System.Linq;
public class MyBot
{
public const string MyBotName = "MyC#Bot";
public static void Main(string[] args) {
Console.SetIn(Console.In);
Console.SetOut(Console.Out);
ushort myID;
var map = Networking.getInit(out myID);
/* ------
Do more prep work, see rules for time limit
------ */
Networking.SendInit(MyBotName); // Acknoweldge the init and begin the game
var random = new Random();
while (true) {
Networking.getFrame(ref map); // Update the map to reflect the moves before this turn
var moves = new List();
for (ushort x = 0; x < map.Width; x++) {
for (ushort y = 0; y < map.Height; y++) {
if (map[x, y].Owner == myID) {
moves.Add(new Move {
Location = new Location {X = x, Y = y},
Direction = (Direction)random.Next(5)
});
}
}
}
Networking.SendMoves(moves); // Send moves
}
}
}
================================================
FILE: airesources/CSharp/Properties/AssemblyInfo.cs
================================================
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
// General Information about an assembly is controlled through the following
// set of attributes. Change these attribute values to modify the information
// associated with an assembly.
[assembly: AssemblyTitle("Halite")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("")]
[assembly: AssemblyProduct("Halite")]
[assembly: AssemblyCopyright("Copyright © 2016")]
[assembly: AssemblyTrademark("")]
[assembly: AssemblyCulture("")]
// Setting ComVisible to false makes the types in this assembly not visible
// to COM components. If you need to access a type in this assembly from
// COM, set the ComVisible attribute to true on that type.
[assembly: ComVisible(false)]
// The following GUID is for the ID of the typelib if this project is exposed to COM
[assembly: Guid("1460a17a-7e8b-4643-b0a9-06a1b86f07e9")]
// Version information for an assembly consists of the following four values:
//
// Major Version
// Minor Version
// Build Number
// Revision
//
// You can specify all the values or you can default the Build and Revision Numbers
// by using the '*' as shown below:
// [assembly: AssemblyVersion("1.0.*")]
[assembly: AssemblyVersion("1.0.0.0")]
[assembly: AssemblyFileVersion("1.0.0.0")]
================================================
FILE: airesources/CSharp/RandomBot.cs
================================================
using System;
using System.Collections.Generic;
using System.Linq;
public class MyBot
{
public const string RandomBotName = "RandomC#Bot";
public static void Main(string[] args) {
Console.SetIn(Console.In);
Console.SetOut(Console.Out);
ushort myID;
var map = Networking.getInit(out myID);
Networking.SendInit(RandomBotName);
var random = new Random();
while (true) {
Networking.getFrame(ref map);
var moves = new List();
for (ushort x = 0; x < map.Width; x++) {
for (ushort y = 0; y < map.Height; y++) {
if (map[x, y].Owner == myID) {
moves.Add(new Move {
Location = new Location {X = x, Y = y},
Direction = (Direction)random.Next(5)
});
}
}
}
Networking.SendMoves(moves); // Send moves
}
}
}
================================================
FILE: airesources/CSharp/runGame.bat
================================================
csc /t:library /out:HaliteHelper.dll HaliteHelper.cs
csc /reference:HaliteHelper.dll -out:MyBot.exe MyBot.cs
csc /reference:HaliteHelper.dll -out:RandomBot.exe RandomBot.cs
halite -d "30 30" "MyBot.exe" "RandomBot.exe"
================================================
FILE: airesources/CSharp/runGame.sh
================================================
#!/bin/bash
mcs -t:library -out:HaliteHelper.dll HaliteHelper.cs
mcs -reference:HaliteHelper.dll -out:MyBot.o MyBot.cs
mcs -reference:HaliteHelper.dll -out:RandomBot.o RandomBot.cs
./halite -d "30 30" "./MyBot.o" "./RandomBot.o"
================================================
FILE: airesources/Clojure/.gitignore
================================================
/target
/classes
/checkouts
pom.xml
pom.xml.asc
*.jar
*.class
/.lein-*
/.nrepl-port
.hgignore
.hg/
================================================
FILE: airesources/Clojure/README.md
================================================
# halite-clj
A Clojure implementation of a random Halite bot.
## Usage
First, copy the "halite" executable to the root of your project. Build using "lein uberjar" and run:
./halite -d "30 30" "java -cp target/MyBot.jar MyBot" "java -cp target/MyBot.jar RandomBot"
================================================
FILE: airesources/Clojure/project.clj
================================================
(defproject halite-clj "0.1.0-SNAPSHOT"
:description "FIXME: write description"
:url "http://example.com/FIXME"
:license {:name "Eclipse Public License"
:url "http://www.eclipse.org/legal/epl-v10.html"}
:dependencies [[org.clojure/clojure "1.8.0"]]
:uberjar-name "MyBot.jar"
:main MyBot
:profiles {:uberjar {:aot :all}}
)
================================================
FILE: airesources/Clojure/runGame.bat
================================================
call lein uberjar
halite.exe -d "30 30" "java -cp target/MyBot.jar MyBot" "java -cp target/MyBot.jar RandomBot"
================================================
FILE: airesources/Clojure/runGame.sh
================================================
#!/bin/bash
lein uberjar
./halite -d "30 30" "java -cp target/MyBot.jar MyBot" "java -cp target/MyBot.jar RandomBot"
================================================
FILE: airesources/Clojure/src/MyBot.clj
================================================
(ns MyBot
(:require [game]
[io])
(:gen-class))
(def bot-name "MyFirstClojureBot")
(defn random-moves
"Takes a 2D vector of sites and returns a list of [site, direction] pairs"
[my-id game-map]
(let [my-sites (->> game-map
flatten
(filter #(= (:owner %) my-id)))]
(map vector my-sites (repeatedly #(rand-nth game/directions)))))
(defn -main []
(let [{:keys [my-id productions width height game-map]} (io/get-init!)]
;; Do any initialization you want with the starting game-map before submitting the bot-name
(println bot-name)
(doseq [turn (range)]
(let [game-map (io/create-game-map width height productions (io/read-ints!))]
(io/send-moves! (random-moves my-id game-map))))))
================================================
FILE: airesources/Clojure/src/RandomBot.clj
================================================
(ns RandomBot
(:require [game]
[io])
(:gen-class))
(def bot-name "RandomClojureBot")
(defn random-moves
"Takes a 2D vector of sites and returns a list of [site, direction] pairs"
[my-id game-map]
(let [my-sites (->> game-map
flatten
(filter #(= (:owner %) my-id)))]
(map vector my-sites (repeatedly #(rand-nth game/directions)))))
(defn -main []
(let [{:keys [my-id productions width height game-map]} (io/get-init!)]
;; Do any initialization you want with the starting game-map before submitting the bot-name
(println bot-name)
(doseq [turn (range)]
(let [game-map (io/create-game-map width height productions (io/read-ints!))]
(io/send-moves! (random-moves my-id game-map))))))
================================================
FILE: airesources/Clojure/src/game.clj
================================================
(ns game
(:gen-class))
;; The map is represented by a 2D vector of Sites
(defrecord Site [^int x ^int y ^int production ^int strength ^int owner])
(def directions [:still :north :east :south :west])
(def cardinal-directions (rest directions))
(defn adjacent-site [game-map site direction]
(let [width (count (first game-map))
height (count game-map)
new-x (condp = direction
:west (mod (dec (:x site)) width)
:east (mod (inc (:x site)) width)
(:x site))
new-y (condp = direction
:north (mod (dec (:y site)) height)
:south (mod (inc (:y site)) height)
(:y site))]
(get-in game-map [new-y new-x])))
(defn single-dimension-distance
"Computes the distance between two integers mod m"
[p1 p2 m]
(let [unwrapped-distance (Math/abs (- p1 p2))]
(min unwrapped-distance (- m unwrapped-distance))))
(defn distance [game-map site1 site2]
(+ (single-dimension-distance (:x site1) (:x site2) (count (first game-map)))
(single-dimension-distance (:y site1) (:y site2) (count game-map))))
================================================
FILE: airesources/Clojure/src/io.clj
================================================
(ns io
(:require clojure.string
game)
(:gen-class))
(defn create-game-map
"Parses the run-length encoded format of the map into a 2D vector of Sites"
[width height productions compressed-map]
(let [total-size (* width height)
potential-owner-run-pairs (partition 2 compressed-map)
owner-pair-count (->> potential-owner-run-pairs
(map first)
(reductions + 0)
(take-while #(not= total-size %))
(count))
owners (->> potential-owner-run-pairs
(take owner-pair-count)
(mapcat #(repeat (first %) (second %))))
strengths (->> compressed-map
(drop (* 2 owner-pair-count)))
flat-sites (map game/->Site
(cycle (range width))
(mapcat #(repeat width %) (range))
productions
strengths
owners)]
(mapv vec (partition width flat-sites))))
(defn read-ints!
"Reads a sequence of space-delimited integers from *in*"
[]
(map #(Integer/parseInt %)
(clojure.string/split (read-line) #" ")))
(defn get-init!
"Reads all the initialization data provided by the Halite environment process"
[]
(let [my-id (Integer/parseInt (read-line))
[width height] (read-ints!)
productions (read-ints!)
game-map (create-game-map width height productions (read-ints!))]
{:my-id my-id :width width :height height :productions productions :game-map game-map}))
(def direction->int (zipmap game/directions (range)))
(defn- format-moves-for-output [moves]
(clojure.string/join " "
(for [[site direction] moves]
(clojure.string/join " " [(:x site) (:y site) (direction->int direction)]))))
(defn send-moves!
"Submits a list of [site, direction] pairs to the Halite enviroment process"
[moves]
(println (format-moves-for-output moves)))
================================================
FILE: airesources/Go/MyBot.go
================================================
package main
import (
"hlt"
"math/rand"
)
func main() {
conn, gameMap := hlt.NewConnection()
conn.SendName("MyBot")
for {
var moves hlt.MoveSet
gameMap = conn.GetFrame()
for y := 0; y < gameMap.Height; y++ {
for x := 0; x < gameMap.Width; x++ {
loc := hlt.NewLocation(x, y)
if gameMap.GetSite(loc, hlt.STILL).Owner == conn.PlayerTag {
moves = append(moves, hlt.Move{
Location: loc,
Direction: hlt.Direction(rand.Int() % 5),
})
}
}
}
conn.SendFrame(moves)
}
}
================================================
FILE: airesources/Go/RandomBot.go
================================================
package main
import (
"hlt"
"math/rand"
)
func main() {
conn, gameMap := hlt.NewConnection()
conn.SendName("RandomBot")
for {
var moves hlt.MoveSet
gameMap = conn.GetFrame()
for y := 0; y < gameMap.Height; y++ {
for x := 0; x < gameMap.Width; x++ {
loc := hlt.NewLocation(x, y)
if gameMap.GetSite(loc, hlt.STILL).Owner == conn.PlayerTag {
moves = append(moves, hlt.Move{
Location: loc,
Direction: hlt.Direction(rand.Int() % 5),
})
}
}
}
conn.SendFrame(moves)
}
}
================================================
FILE: airesources/Go/runGame.bat
================================================
.\halite.exe -d "30 30" "go run MyBot.go" "go run RandomBot.go"
================================================
FILE: airesources/Go/runGame.sh
================================================
#!/bin/bash
export GOPATH="$(pwd)"
./halite -d "30 30" "go run MyBot.go" "go run RandomBot.go"
================================================
FILE: airesources/Go/src/hlt/gamemap.go
================================================
package hlt
import (
"log"
"math"
"strconv"
)
type GameMap struct {
Width, Height int
Contents [][]Site
}
func NewGameMap(width, height int) GameMap {
gameMap := GameMap{
Width: width,
Height: height,
}
gameMap.Contents = make([][]Site, height)
for y := 0; y < height; y++ {
gameMap.Contents[y] = make([]Site, width)
for x := 0; x < width; x++ {
gameMap.Contents[y][x] = Site{}
}
}
return gameMap
}
func int_str_array_pop(input []string) (int, []string) {
ret, err := strconv.Atoi(input[0])
input = input[1:]
if err != nil {
log.Printf("Whoopse", err)
}
return ret, input
}
func (m *GameMap) InBounds(loc Location) bool {
return loc.X >= 0 && loc.X < m.Width && loc.Y >= 0 && loc.Y < m.Height
}
func (m *GameMap) GetDistance(loc1, loc2 Location) int {
dx := int(math.Abs(float64(loc1.X) - float64(loc2.X)))
dy := int(math.Abs(float64(loc1.Y) - float64(loc2.Y)))
if dx > m.Width/2 {
dx = m.Width - dx
}
if dy > m.Width/2 {
dy = m.Height - dy
}
return dx + dy
}
func (m *GameMap) GetAngle(loc1, loc2 Location) float64 {
dx := loc2.X - loc1.X
dy := loc2.Y - loc1.Y
if dx > m.Width-dx {
dx -= m.Width
} else if -dx > m.Width+dx {
dx += m.Width
}
if dy > m.Height-dy {
dx -= m.Height
} else if -dy > m.Height+dy {
dy += m.Height
}
return math.Atan2(float64(dy), float64(dx))
}
func (m *GameMap) GetLocation(loc Location, direction Direction) Location {
switch direction {
case NORTH:
if loc.Y == 0 {
loc.Y = m.Height - 1
} else {
loc.Y -= 1
}
case EAST:
if loc.X == m.Width-1 {
loc.X = 0
} else {
loc.X += 1
}
case SOUTH:
if loc.Y == m.Height-1 {
loc.Y = 0
} else {
loc.Y += 1
}
case WEST:
if loc.X == 0 {
loc.X = m.Width - 1
} else {
loc.X -= 1
}
}
return loc
}
func (m *GameMap) GetSite(loc Location, direction Direction) Site {
loc = m.GetLocation(loc, direction)
return m.Contents[loc.Y][loc.X]
}
================================================
FILE: airesources/Go/src/hlt/networking.go
================================================
package hlt
import (
"bufio"
"fmt"
"io"
"log"
"os"
"strconv"
"strings"
)
type Direction int
const (
STILL Direction = iota
NORTH
EAST
SOUTH
WEST
)
var Directions = []Direction{STILL, NORTH, EAST, SOUTH, WEST}
var CARDINALS = []Direction{NORTH, EAST, SOUTH, WEST}
type Site struct {
Owner int
Strength int
Production int
}
type Location struct {
Y, X int
}
func NewLocation(x, y int) Location {
return Location{
X: x,
Y: y,
}
}
type Move struct {
Location Location
Direction Direction
}
type MoveSet []Move
func (ms MoveSet) serialize() string {
var retstr string
for _, move := range ms {
retstr = fmt.Sprintf("%s %d %d %d", retstr, move.Location.X, move.Location.Y, move.Direction)
}
return retstr
}
type Connection struct {
width, height int
PlayerTag int
productions [][]int
reader *bufio.Reader
writer io.Writer
}
func (c *Connection) deserializeMap() GameMap {
splitString := strings.Split(c.getString(), " ")
m := NewGameMap(c.width, c.height)
var x, y, owner, counter int
for y != m.Height {
counter, splitString = int_str_array_pop(splitString)
owner, splitString = int_str_array_pop(splitString)
for a := 0; a < counter; a++ {
m.Contents[y][x].Owner = owner
x += 1
if x == m.Width {
x = 0
y += 1
}
}
}
for y := 0; y < m.Height; y++ {
for x := 0; x < m.Width; x++ {
m.Contents[y][x].Strength, splitString = int_str_array_pop(splitString)
m.Contents[y][x].Production = c.productions[y][x]
}
}
return m
}
func (c *Connection) sendString(input string) {
fmt.Println(input)
}
func (c *Connection) getString() string {
retstr, _ := c.reader.ReadString('\n')
retstr = strings.TrimSpace(retstr)
return retstr
}
func (c *Connection) getInt() int {
i, err := strconv.Atoi(c.getString())
if err != nil {
log.Printf("Whoopse", err)
}
return i
}
func (c *Connection) deserializeMapSize() {
splitString := strings.Split(c.getString(), " ")
c.width, splitString = int_str_array_pop(splitString)
c.height, splitString = int_str_array_pop(splitString)
}
func (c *Connection) deserializeProductions() {
splitString := strings.Split(c.getString(), " ")
c.productions = make([][]int, c.height)
for y := 0; y < c.height; y++ {
c.productions[y] = make([]int, c.width)
for x := 0; x < c.width; x++ {
c.productions[y][x], splitString = int_str_array_pop(splitString)
}
}
}
func NewConnection() (Connection, GameMap) {
conn := Connection{
reader: bufio.NewReader(os.Stdin),
writer: os.Stdout,
}
conn.PlayerTag = conn.getInt()
conn.deserializeMapSize()
conn.deserializeProductions()
return conn, conn.deserializeMap()
}
func (c *Connection) SendName(name string) {
c.sendString(name)
}
func (c *Connection) GetFrame() GameMap {
return c.deserializeMap()
}
func (c *Connection) SendFrame(moves MoveSet) {
c.sendString(moves.serialize())
}
================================================
FILE: airesources/Java/Direction.java
================================================
import java.util.Random;
public enum Direction {
STILL, NORTH, EAST, SOUTH, WEST;
public static final Direction[] DIRECTIONS = new Direction[]{STILL, NORTH, EAST, SOUTH, WEST};
public static final Direction[] CARDINALS = new Direction[]{NORTH, EAST, SOUTH, WEST};
public static Direction randomDirection() {
Direction[] values = values();
return values[new Random().nextInt(values.length)];
}
}
================================================
FILE: airesources/Java/GameMap.java
================================================
import java.util.ArrayList;
public class GameMap{
private final Site[][] contents;
private final Location[][] locations;
public final int width, height;
public GameMap(int width, int height, int[][] productions) {
this.width = width;
this.height = height;
this.contents = new Site[width][height];
this.locations = new Location[width][height];
for (int y = 0; y < height; y++) {
for(int x = 0; x < width; x++) {
final Site site = new Site(productions[x][y]);
contents[x][y] = site;
locations[x][y] = new Location(x, y, site);
}
}
}
public boolean inBounds(Location loc) {
return loc.x < width && loc.x >= 0 && loc.y < height && loc.y >= 0;
}
public double getDistance(Location loc1, Location loc2) {
int dx = Math.abs(loc1.x - loc2.x);
int dy = Math.abs(loc1.y - loc2.y);
if(dx > width / 2.0) dx = width - dx;
if(dy > height / 2.0) dy = height - dy;
return dx + dy;
}
public double getAngle(Location loc1, Location loc2) {
int dx = loc1.x - loc2.x;
// Flip order because 0,0 is top left
// and want atan2 to look as it would on the unit circle
int dy = loc2.y - loc1.y;
if(dx > width - dx) dx -= width;
if(-dx > width + dx) dx += width;
if(dy > height - dy) dy -= height;
if(-dy > height + dy) dy += height;
return Math.atan2(dy, dx);
}
public Location getLocation(Location location, Direction direction) {
switch (direction) {
case STILL:
return location;
case NORTH:
return locations[location.getX()][(location.getY() == 0 ? height : location.getY()) -1];
case EAST:
return locations[location.getX() == width - 1 ? 0 : location.getX() + 1][location.getY()];
case SOUTH:
return locations[location.getX()][location.getY() == height - 1 ? 0 : location.getY() + 1];
case WEST:
return locations[(location.getX() == 0 ? width : location.getX()) - 1][location.getY()];
default:
throw new IllegalArgumentException(String.format("Unknown direction %s encountered", direction));
}
}
public Site getSite(Location loc, Direction dir) {
return getLocation(loc, dir).getSite();
}
public Site getSite(Location loc) {
return loc.getSite();
}
public Location getLocation(int x, int y) {
return locations[x][y];
}
void reset() {
for (int y = 0; y < height; y++) {
for (int x = 0; x < width; x++) {
final Site site = contents[x][y];
site.owner = 0;
site.strength = 0;
}
}
}
}
================================================
FILE: airesources/Java/InitPackage.java
================================================
public class InitPackage {
public int myID;
public GameMap map;
}
================================================
FILE: airesources/Java/Location.java
================================================
public class Location {
// Public for backward compability
public final int x, y;
private final Site site;
public Location(int x, int y, Site site) {
this.x = x;
this.y = y;
this.site = site;
}
public int getX() {
return x;
}
public int getY() {
return y;
}
public Site getSite() {
return site;
}
}
================================================
FILE: airesources/Java/Move.java
================================================
public class Move {
public Location loc;
public Direction dir;
public Move(Location loc_, Direction dir_) {
loc = loc_;
dir = dir_;
}
}
================================================
FILE: airesources/Java/MyBot.java
================================================
import java.util.ArrayList;
import java.util.List;
public class MyBot {
public static void main(String[] args) throws java.io.IOException {
final InitPackage iPackage = Networking.getInit();
final int myID = iPackage.myID;
final GameMap gameMap = iPackage.map;
Networking.sendInit("MyJavaBot");
while(true) {
List moves = new ArrayList();
Networking.updateFrame(gameMap);
for (int y = 0; y < gameMap.height; y++) {
for (int x = 0; x < gameMap.width; x++) {
final Location location = gameMap.getLocation(x, y);
final Site site = location.getSite();
if(site.owner == myID) {
moves.add(new Move(location, Direction.randomDirection()));
}
}
}
Networking.sendFrame(moves);
}
}
}
================================================
FILE: airesources/Java/Networking.java
================================================
import java.net.*;
import java.io.*;
import java.util.ArrayList;
import java.util.Scanner;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.util.List;
public class Networking {
static int[][] deserializeProductions(String inputString, int width, int height) {
String[] inputStringComponents = inputString.split(" ");
int index = 0;
int[][] productions = new int[width][height];
for (int y = 0; y < height; y++) {
for (int x = 0; x < width; x++) {
productions[x][y] = Integer.parseInt(inputStringComponents[index]);
index++;
}
}
return productions;
}
static String serializeMoveList(List moves) {
StringBuilder builder = new StringBuilder();
for (Move move : moves) {
builder.append(move.loc.x)
.append(" ")
.append(move.loc.y)
.append(" ")
.append(move.dir.ordinal())
.append(" ");
}
return builder.toString();
}
static GameMap deserializeGameMap(String inputString, GameMap map) {
String[] inputStringComponents = inputString.split(" ");
// Run-length encode of owners
int y = 0, x = 0;
int counter = 0, owner = 0;
int currentIndex = 0;
while (y != map.height) {
counter = Integer.parseInt(inputStringComponents[currentIndex]);
owner = Integer.parseInt(inputStringComponents[currentIndex + 1]);
currentIndex += 2;
for (int a = 0; a < counter; a++) {
map.getLocation(x,y).getSite().owner = owner;
++x;
if(x == map.width) {
x = 0;
++y;
}
}
}
for (int b = 0; b < map.height; b++) {
for (int a = 0; a < map.width; a++) {
int strengthInt = Integer.parseInt(inputStringComponents[currentIndex]);
currentIndex++;
map.getLocation(a,b).getSite().strength = strengthInt;
}
}
return map;
}
static void sendString(String sendString) {
System.out.print(sendString+'\n');
System.out.flush();
}
static String getString() {
try {
StringBuilder builder = new StringBuilder();
int buffer;
while ((buffer = System.in.read()) >= 0) {
if (buffer == '\n') {
break;
} else {
builder = builder.append((char)buffer);
}
}
if(builder.charAt(builder.length()-1) == '\r') builder.setLength(builder.length()-1); //Removes a carriage return if on windows for manual testing.
return builder.toString();
} catch(Exception e) {
System.exit(1);
return null; // the java compiler is stupid
}
}
static InitPackage getInit() {
InitPackage initPackage = new InitPackage();
initPackage.myID = (int)Integer.parseInt(getString());
// Deserialize width and height:
final String[] inputStringComponents = getString().split(" ");
int width = Integer.parseInt(inputStringComponents[0]);
int height = Integer.parseInt(inputStringComponents[1]);
int[][] productions = deserializeProductions(getString(), width, height);
GameMap map = new GameMap(width, height, productions);
deserializeGameMap(getString(), map);
initPackage.map = map;
return initPackage;
}
static void sendInit(String name) {
sendString(name);
}
static void updateFrame(GameMap map) {
map.reset();
deserializeGameMap(getString(), map);
}
static void sendFrame(List moves) {
sendString(serializeMoveList(moves));
}
}
================================================
FILE: airesources/Java/RandomBot.java
================================================
import java.util.ArrayList;
import java.util.List;
public class RandomBot {
public static void main(String[] args) throws java.io.IOException {
final InitPackage iPackage = Networking.getInit();
final int myID = iPackage.myID;
final GameMap gameMap = iPackage.map;
Networking.sendInit("RandomJavaBot");
while(true) {
List moves = new ArrayList();
Networking.updateFrame(gameMap);
for (int y = 0; y < gameMap.height; y++) {
for (int x = 0; x < gameMap.width; x++) {
final Location location = gameMap.getLocation(x, y);
final Site site = location.getSite();
if(site.owner == myID) {
moves.add(new Move(location, Direction.randomDirection()));
}
}
}
Networking.sendFrame(moves);
}
}
}
================================================
FILE: airesources/Java/Site.java
================================================
public class Site {
public final int production;
public int owner, strength;
public Site(int production) {
this.production = production;
}
}
================================================
FILE: airesources/Java/runGame.bat
================================================
javac MyBot.java
javac RandomBot.java
.\halite.exe -d "30 30" "java MyBot" "java RandomBot"
================================================
FILE: airesources/Java/runGame.sh
================================================
#!/bin/bash
javac MyBot.java
javac RandomBot.java
./halite -d "30 30" "java MyBot" "java RandomBot"
================================================
FILE: airesources/JavaScript/MyBot.js
================================================
const {
Move,
} = require('./hlt');
const Networking = require('./networking');
const network = new Networking('MyJavaScriptBot');
network.on('map', (gameMap, id) => {
const moves = [];
for (let y = 0; y < gameMap.height; y++) {
for (let x = 0; x < gameMap.width; x++) {
const loc = { x, y };
const { owner } = gameMap.getSite(loc);
if (owner === id) {
moves.push(new Move(loc, Math.floor(Math.random() * 5)));
}
}
}
network.sendMoves(moves);
});
================================================
FILE: airesources/JavaScript/RandomBot.js
================================================
const {
Move,
} = require('./hlt');
const Networking = require('./networking');
const network = new Networking('RandomJavaScriptBot');
network.on('map', (gameMap, id) => {
const moves = [];
for (let y = 0; y < gameMap.height; y++) {
for (let x = 0; x < gameMap.width; x++) {
const loc = { x, y };
const { owner } = gameMap.getSite(loc);
if (owner === id) {
moves.push(new Move(loc, Math.floor(Math.random() * 5)));
}
}
}
network.sendMoves(moves);
});
================================================
FILE: airesources/JavaScript/hlt.js
================================================
const STILL = 0;
const NORTH = 1;
const EAST = 2;
const SOUTH = 3;
const WEST = 4;
const DIRECTIONS = [STILL, NORTH, EAST, SOUTH, WEST];
const CARDINALS = [NORTH, EAST, SOUTH, WEST];
const ATTACK = 0;
const STOP_ATTACK = 1;
class Location {
constructor(x = 0, y = 0) {
this.x = x;
this.y = y;
}
}
class Site {
constructor(owner = 0, strength = 0, production = 0) {
this.owner = owner;
this.strength = strength;
this.production = production;
}
}
class Move {
constructor(loc = new Location(), direction = STILL) {
this.loc = loc;
this.direction = direction;
}
}
class GameMap {
constructor(width = 0, height = 0, numberOfPlayers = 0) {
this.width = width;
this.height = height;
this.numberOfPlayers = numberOfPlayers;
this.contents = [];
for (let y = 0; y < this.height; y++) {
const row = [];
for (let x = 0; x < this.width; x++) {
row.push(new Site(0, 0, 0));
}
this.contents.push(row);
}
}
inBounds(l) {
return l.x >= 0 && l.x < this.width && l.y >= 0 && l.y < this.height;
}
getDistance(l1, l2) {
let dx = Math.abs(l1.x - l2.x);
let dy = Math.abs(l1.y - l2.y);
if (dx > (this.width / 2)) {
dx = this.width - dx;
}
if (dy > (this.height / 2)) {
dy = this.height - dy;
}
return dx + dy;
}
getAngle(l1, l2) {
let dx = l2.x - l1.x;
let dy = l2.y - l1.y;
if (dx > (this.width - dx)) {
dx -= this.width;
} else if (-dx > (this.width + dx)) {
dx += this.width;
}
if (dy > (this.height - dy)) {
dy -= this.height;
} else if (-dy > (this.height + dy)) {
dy += this.height;
}
return Math.atan2(dy, dx);
}
getLocation(loc, direction) {
let { x, y } = loc;
if (direction === STILL) {
// nothing
} else if (direction === NORTH) {
y -= 1;
} else if (direction === EAST) {
x += 1;
} else if (direction === SOUTH) {
y += 1;
} else if (direction === WEST) {
x -= 1;
}
if (x < 0) {
x = this.width - 1;
} else {
x %= this.width;
}
if (y < 0) {
y = this.height - 1;
} else {
y %= this.height;
}
return { x, y };
}
getSite(l, direction = STILL) {
const { x, y } = this.getLocation(l, direction);
return this.contents[y][x];
}
}
module.exports = {
STILL,
NORTH,
EAST,
SOUTH,
WEST,
DIRECTIONS,
CARDINALS,
ATTACK,
STOP_ATTACK,
Location,
Site,
Move,
GameMap
};
================================================
FILE: airesources/JavaScript/networking.js
================================================
const EventEmitter = require('events');
const readline = require('readline');
const { GameMap } = require('./hlt.js');
class Networking extends EventEmitter {
constructor(botName) {
super();
this.messageCount = 0;
this.width = 0;
this.height = 0;
this.productions = [];
this.rl = readline.createInterface({
input: process.stdin
});
this.rl.on('line', (line) => {
switch (this.messageCount++) {
case 0:
// first line is the player ID
this.id = parseInt(line, 10);
break;
case 1:
// second line is the map dimensions
this.deserializeMapSize(line);
break;
case 2:
// third line is the productions
this.deserializeProductions(line);
break;
case 3:
// fourth line is the initial map
break;
default:
// everything after is map updates
return this.emit('map', this.deserializeMap(line), this.id);
}
});
Networking.sendString(botName);
}
sendMoves(moves) {
Networking.sendString(Networking.serializeMoveSet(moves));
}
deserializeMapSize(inputString) {
[this.width, this.height] = splitToInts(inputString);
}
deserializeProductions(inputString) {
const flatProductions = splitToInts(inputString);
for (let i = 0; i < this.height; i++) {
const start = i * this.width;
const end = (i + 1) * this.width;
this.productions.push(flatProductions.slice(start, end));
}
}
deserializeMap(inputString) {
const flatMap = splitToInts(inputString);
const m = new GameMap(this.width, this.height);
let x = 0;
let y = 0;
let counter = 0;
let owner = 0;
let rest = flatMap;
while (y !== m.height) {
[counter, owner, ...rest] = rest;
for (let i = 0; i < counter; i++) {
m.contents[y][x].owner = owner;
x += 1;
if (x === m.width) {
x = 0;
y += 1;
}
}
}
for (y = 0; y < m.height; y++) {
for (x = 0; x < m.width; x++) {
m.contents[y][x].strength = rest.shift();
m.contents[y][x].production = this.productions[y][x];
}
}
return m;
}
}
Networking.sendString = function sendString(toBeSent) {
process.stdout.write(`${toBeSent}\n`);
};
Networking.serializeMoveSet = function serializeMoveSet(moves) {
return moves
.map((move) => `${move.loc.x} ${move.loc.y} ${move.direction}`)
.join(' ');
};
function splitToInts(inputString) {
return inputString.split(' ').map((value) => parseInt(value, 10));
}
module.exports = Networking;
================================================
FILE: airesources/JavaScript/runGame.bat
================================================
.\halite.exe -d "30 30" "node MyBot.js" "node RandomBot.js"
================================================
FILE: airesources/JavaScript/runGame.sh
================================================
#!/bin/bash
./halite -d "30 30" "node MyBot.js" "node RandomBot.js"
================================================
FILE: airesources/Julia/MyBot.jl
================================================
include("hlt.jl")
include("networking.jl")
myID, gameMap = getInit()
sendInit("MyJuliaBot")
while true
moves = Vector{Move}()
gameMap = getFrame()
for y in 0:gameMap.height-1
for x in 0:gameMap.width-1
if getSite(gameMap, Location(x, y)).owner == myID
push!(moves, Move(Location(x, y), rand(0:4)))
end
end
end
sendFrame(moves)
end
================================================
FILE: airesources/Julia/RandomBot.jl
================================================
include("hlt.jl")
include("networking.jl")
myID, gameMap = getInit()
sendInit("RandomJuliaBot")
while true
moves = Vector{Move}()
gameMap = getFrame()
for y in 0:gameMap.height-1
for x in 0:gameMap.width-1
if getSite(gameMap, Location(x, y)).owner == myID
push!(moves, Move(Location(x, y), rand(0:4)))
end
end
end
sendFrame(moves)
end
================================================
FILE: airesources/Julia/hlt.jl
================================================
const STILL = 0
const NORTH = 1
const EAST = 2
const SOUTH = 3
const WEST = 4
const DIRECTIONS = [a for a in 0:4]
const CARDINALS = [a for a in 1:4]
const ATTACK = 0
const STOP_ATTACK = 1
type Location
x :: Int64
y :: Int64
Location(x::Int64, y::Int64) = new(x, y)
Location() = Location(0, 0)
end
type Site
owner :: Int64
strength :: Int64
production :: Int64
Site(owner::Int64, strength::Int64, production::Int64) = new(owner, strength, production)
Site() = Site(0, 0, 0)
end
type Move
loc :: Location
direction :: Int64
Move(loc::Location, direction::Int64) = new(loc, direction)
Move() = Move(Location(), 0)
end
type GameMap
width :: Int64
height :: Int64
contents :: Vector{Vector{Site}}
function GameMap(width::Int64, height::Int64)
contents = Vector{Vector{Site}}()
for y in 0:height-1
row = Vector{Site}()
for x in 0:width-1
push!(row, Site(0, 0, 0))
end
push!(contents, row)
end
new(width, height, contents)
end
GameMap() = GameMap(0, 0)
end
isBounds(gm::GameMap, l::Location) = l.x >= 0 && l.x < gm.width && l.y >= 0 && l.y < gm.height
function getDistance(gm::GameMap, l1::Location, l2::Location)
dx = abs(l1.x - l2.x)
dy = abs(l1.y - l2.y)
if dx > gm.width / 2
dx = gm.width - dx
end
if dy > gm.height / 2
dy = gm.height - dy
end
dx + dy
end
function getAngle(gm::GameMap, l1::Location, l2::Location)
dx = l2.x - l1.x
dy = l2.y - l1.y
if dx > gm.width - dx
dx -= gm.width
elseif -dx > gm.width + dx
dx += gm.width
end
if dy > gm.height - dy
dy -= gm.height
elseif -dy > gm.height + dy
dy += gm.height
end
atan2(dy, dx)
end
function getLocation(gm::GameMap, loc::Location, direction::Int64)
l = deepcopy(loc)
if direction != STILL
if direction == NORTH
if l.y == 0
l.y = gm.height - 1
else
l.y = l.y - 1
end
elseif direction == EAST
if l.x == gm.width - 1
l.x = 0
else
l.x = l.x + 1
end
elseif direction == SOUTH
if l.y == gm.height - 1
l.y = 0
else
l.y = l.y + 1
end
elseif direction == WEST
if l.x == 0
l.x = gm.width - 1
else
l.x = l.x - 1
end
end
end
l
end
function getSite(gm::GameMap, l::Location, direction::Int64=STILL)
l = getLocation(gm, l, direction)
gm.contents[l.y + 1][l.x + 1]
end
================================================
FILE: airesources/Julia/networking.jl
================================================
_productions = Vector{Vector{Int64}}()
_width = nothing
_height = nothing
function serializeMoveSet(moves::Vector{Move})
returnString = ""
for move in moves
returnString *= string(move.loc.x) * " " * string(move.loc.y) * " " * string(move.direction) * " "
end
returnString
end
function deserializeMapSize(inputString::String)
splitString = reverse(split(inputString, " "))
global _width, _height
_width = parse(pop!(splitString))
_height = parse(pop!(splitString))
end
function deserializeProductions(inputString::String)
splitString = reverse(split(inputString, " "))
for a in 1:_height
row = Vector{Int64}()
for b in 1:_width
push!(row, parse(pop!(splitString)))
end
push!(_productions, row)
end
end
function deserializeMap(inputString::String)
splitString = reverse(split(inputString, " "))
m = GameMap(_width, _height)
y = 1
x = 1
counter = 0
owner = 0
while ~(y > m.height)
counter = parse(pop!(splitString))
owner = parse(pop!(splitString))
for a in 0:counter-1
m.contents[y][x].owner = owner
x += 1
if x > m.width
x = 1
y += 1
end
end
end
for a in 1:_height
for b in 1:_width
m.contents[a][b].strength = parse(pop!(splitString))
m.contents[a][b].production = _productions[a][b]
end
end
m
end
function sendString(toBeSent::String)
toBeSent *= "\n"
write(STDOUT, toBeSent)
flush(STDOUT)
end
function getString()
rstrip(readline(), '\n')
end
function getInit()
playerTag = parse(getString())
deserializeMapSize(getString())
deserializeProductions(getString())
m = deserializeMap(getString())
(playerTag, m)
end
function sendInit(name::String)
sendString(name)
end
function getFrame()
return deserializeMap(getString())
end
function sendFrame(moves::Vector{Move})
sendString(serializeMoveSet(moves))
end
================================================
FILE: airesources/Julia/runGame.bat
================================================
.\halite.exe -d "30 30" "julia MyBot.jl" "julia RandomBot.jl"
================================================
FILE: airesources/Julia/runGame.sh
================================================
#!/bin/bash
./halite -d "30 30" "julia MyBot.jl" "julia RandomBot.jl"
================================================
FILE: airesources/OCaml/MyBot.ml
================================================
(* OCaml Starter for Halite on Halite.io
This code is public domain. There is no warranty.
*)
open Td;;
let random_move state row col =
let dir = Halite.direction_of_int (Random.int 5) in
let loc = {
row = row;
col = col;
} in
{
loc = loc;
direction = dir;
}
;;
let random_moves state =
let moves = ref [] in
Array.iteri (fun ir row -> Array.iteri (fun ic site ->
if site.owner = state.my_id then
moves := (random_move state ir ic) :: !moves
) row) state.game_map.contents;
!moves
;;
let mybot_function state =
begin try
(
Halite.get_init state;
Halite.send_init "MyOCamlBot";
while true do
Halite.get_frame state;
let moves = random_moves state in
Halite.send_frame moves
done
)
with exc ->
(
Debug.debug (Printf.sprintf
"Exception in turn %d :\n" state.round);
Debug.debug (Printexc.to_string exc);
raise exc
)
end;
;;
let run_bot bot =
let game_state = Halite.init () in
bot game_state
;;
run_bot mybot_function
================================================
FILE: airesources/OCaml/README.md
================================================
Halite OCaml Starter Package
----------------------------
This is an OCaml starter package for Halite on halite.io
It uses lowercase letters and underscores for variable and function names (following the OCaml convention), but otherwise matches the API seen in other starter packages.
================================================
FILE: airesources/OCaml/RandomBot.ml
================================================
(* OCaml Starter for Halite on Halite.io
This code is public domain. There is no warranty.
*)
open Td;;
let random_move state row col =
let dir = Halite.direction_of_int (Random.int 5) in
let loc = {
row = row;
col = col;
} in
{
loc = loc;
direction = dir;
}
;;
let random_moves state =
let moves = ref [] in
Array.iteri (fun ir row -> Array.iteri (fun ic site ->
if site.owner = state.my_id then
moves := (random_move state ir ic) :: !moves
) row) state.game_map.contents;
!moves
;;
let mybot_function state =
begin try
(
Halite.get_init state;
Halite.send_init "RandomOCamlBot";
while true do
Halite.get_frame state;
let moves = random_moves state in
Halite.send_frame moves
done
)
with exc ->
(
Debug.debug (Printf.sprintf
"Exception in turn %d :\n" state.round);
Debug.debug (Printexc.to_string exc);
raise exc
)
end;
;;
let run_bot bot =
let game_state = Halite.init () in
bot game_state
;;
run_bot mybot_function
================================================
FILE: airesources/OCaml/debug.ml
================================================
(* OCaml Starter for Halite on Halite.io
This code is public domain. There is no warranty.
*)
let out_chan = open_out "mybot_err.log" ;;
let debug s =
output_string out_chan s;
flush out_chan
;;
let error s =
output_string out_chan ("ERROR: " ^ s ^ "\n");
flush out_chan
;;
(* Replace the functions above with these to silence all logging
let out_chan = stdout;;
let debug s = () ;;
let error s = () ;;
*)
================================================
FILE: airesources/OCaml/halite.ml
================================================
(* OCaml Starter for Halite on Halite.io
This code is public domain. There is no warranty.
*)
open Td;;
open Debug;;
(* Some useful things *)
let time_first_turn = 15000.0;;
let time_per_turn = 1000.0;;
let list_directions = [`Still; `North; `East; `South; `West];;
let list_cardinals = [`North; `East; `South; `West];;
let (array_directions:t_direction array) =
[| `Still; `North; `East; `South; `West |]
;;
let (array_cardinals:t_direction array) = [| `North; `East; `South; `West |];;
(* Some boolean reference cells to track init status *)
let first_turn = ref false;;
let init_my_id_done = ref false;;
let init_size_done = ref false;;
let init_production_done = ref false;;
let init_map_done = ref false;;
let all_init_done = ref false;;
let sent_init = ref false;;
let get_time () = Unix.gettimeofday ();;
(* input processing *)
let new_site () =
{
owner = -1;
strength = -1;
production = -1;
}
;;
let new_blank_game_map width height =
let v = Array.make_matrix height width 0 in
Array.map (Array.map (fun _ -> new_site())) v
;;
let clear_state state =
state.game_map.contents <-
new_blank_game_map state.game_map.width state.game_map.height;
state.round <- 0;
;;
(* tokenizer from rosetta code *)
let split_char sep str =
let string_index_from i =
try Some (String.index_from str i sep)
with Not_found -> None
in
let rec aux i acc = match string_index_from i with
| Some i' ->
let w = String.sub str i (i' - i) in
aux (succ i') (w::acc)
| None ->
let w = String.sub str i (String.length str - i) in
List.rev (w::acc)
in
aux 0 []
;;
let get_2d_coords state coord =
let row = coord / state.game_map.width in
let col = coord mod state.game_map.width in
row, col
;;
let set_owner state coord owner =
let row, col = get_2d_coords state coord in
state.game_map.contents.(row).(col).owner <- owner
;;
let set_strength state coord v =
let row, col = get_2d_coords state coord in
state.game_map.contents.(row).(col).strength <- v
;;
let set_production state coord v =
let row, col = get_2d_coords state coord in
state.game_map.contents.(row).(col).production <- v
;;
let set_owners state start repeat owner =
for coord = start to (start + repeat - 1) do
set_owner state coord owner
done
;;
let total_size state = state.game_map.width * state.game_map.height;;
let deserialize_map state tokens =
let count = ref 0 in
let repeat = ref 0 in
let ready = ref false in
let num_sites = total_size state in
List.iter (fun token ->
if !count < num_sites then (
if !ready then (
set_owners state !count !repeat (int_of_string token);
count := !count + !repeat;
ready := false;
) else (
repeat := int_of_string token;
ready := true;
)
)
else (
set_strength state (!count mod num_sites) (int_of_string token);
count := !count + 1;
)
) tokens
;;
let init_production state tokens =
List.iteri (fun i s ->
set_production state i (int_of_string s)
) tokens
;;
let init_size state tokens =
match tokens with
| w :: h :: [] ->
let width = int_of_string w in
let height = int_of_string h in
state.game_map.width <- width;
state.game_map.height <- height;
state.max_rounds <- (int_of_float (sqrt (float_of_int(width * height)))) * 10;
clear_state state;
| _ ->
let s =
List.fold_left (fun acc t -> acc ^ " " ^ t) " " tokens
in
Debug.error ("incorrect input for init_size " ^ s ^ "\n")
;;
let init_my_id state tokens =
match tokens with
| id :: [] ->
state.my_id <- int_of_string id
| _ -> Debug.error ("incorrect input for init_my_id\n")
;;
let process_line state line =
let tokens = split_char ' ' (String.trim line) in
if !all_init_done then (
deserialize_map state tokens;
) else if not !init_my_id_done then (
init_my_id state tokens;
init_my_id_done := true;
) else if not !init_size_done then (
init_size state tokens;
init_size_done := true;
) else if not !init_production_done then (
init_production state tokens;
init_production_done := true;
) else if not !init_map_done then (
deserialize_map state tokens;
init_map_done := true;
all_init_done := true;
)
else Debug.error "Impossible condition: all_init_done not set when all init done"
;;
let get_frame state =
state.round <- state.round + 1;
state.last_update <- get_time();
let line = read_line () in
process_line state line
;;
let read_lines bot state =
while true do
let line = read_line () in
process_line state line;
done
;;
let get_init state =
let finished = ref false in
while not !finished do
let line = read_line () in
process_line state line;
if !all_init_done then
finished := true
done
;;
(* End input section *)
(* output section *)
let char_of_dir = function
| `Still -> '0'
| `North -> '1'
| `East -> '2'
| `South -> '3'
| `West -> '4'
;;
let serialize_move move =
Printf.sprintf "%i %i %c" move.loc.col move.loc.row (char_of_dir move.direction)
;;
let send_frame moves =
List.iter (fun move ->
Printf.printf "%s " (serialize_move move)
) moves;
Printf.printf "\n";
flush stdout;
;;
let send_init name =
print_string (name ^ "\n");
flush stdout;
sent_init := true;
;;
(* End output section *)
(* Utility functions *)
let random_from_list lst =
let len = List.length lst in
List.nth lst (Random.int len)
;;
let in_bounds state row col =
(row >= 0) && (col >= 0)
&&
(row < state.game_map.height) && (col < state.game_map.width)
;;
let get_distance state l1 l2 =
let pd_col = abs (l1.col - l2.col) in
let pd_row = abs (l1.row - l2.row) in
let d_col =
if pd_col > state.game_map.width / 2 then state.game_map.width - pd_col else pd_col
in
let d_row =
if pd_row > state.game_map.height / 2 then state.game_map.height - pd_row else pd_row
in
d_row + d_col
;;
let get_angle state l1 l2 =
let pd_col = l2.col - l1.col in
let pd_row = l2.row - l1.row in
let d_col =
if pd_col > state.game_map.width - pd_col then pd_col - state.game_map.width
else if (-pd_col) > state.game_map.width + pd_col then
pd_col + state.game_map.width
else pd_col
in
let d_row =
if pd_row > state.game_map.height - pd_row then
pd_row - state.game_map.height
else if (-pd_row) > state.game_map.height + pd_row then
pd_row + state.game_map.height
else pd_row
in
atan2 (float_of_int d_row) (float_of_int d_col)
;;
let wrap_loc state loc =
let wrap v bound =
if v < 0 then bound + v
else if v >= bound then v - bound
else v
in
let w_row = wrap loc.row state.game_map.height in
let w_col = wrap loc.col state.game_map.width in
{row = w_row; col = w_col}
;;
let get_location state loc direction =
let (o_row, o_col) =
match direction with
| `Still -> (0, 0)
| `North -> (-1, 0)
| `East -> (0, 1)
| `South -> (1, 0)
| `West -> (0, -1)
in
let row = loc.row + o_row in
let col = loc.col + o_col in
wrap_loc state {row = row; col = col}
;;
let get_site state loc direction =
let l = get_location state loc direction in
state.game_map.contents.(l.row).(l.col)
;;
let time_elapsed_this_turn state =
(get_time() -. state.last_update) *. 1000.
;;
let time_remaining state =
let turntime = if !first_turn then time_first_turn else time_per_turn in
(turntime -. time_elapsed_this_turn state)
;;
let direction_of_int = function
| 0 -> `Still
| 1 -> `North
| 2 -> `East
| 3 -> `South
| 4 -> `West
| n -> failwith ("Invalid direction_of_int: " ^ (string_of_int n) ^ "\n")
;;
let debug_block state f =
Array.iter (fun row ->
Debug.debug "\n";
Array.iter (fun site ->
Debug.debug (f site)
) row
) state.game_map.contents;
Debug.debug "\n"
;;
let debug_productions state =
debug_block state (fun site ->
Printf.sprintf "%2d" site.production
)
;;
let debug_owners state =
debug_block state (fun site ->
(string_of_int site.owner) ^ " "
)
;;
let debug_strength state =
debug_block state (fun site ->
Printf.sprintf "%3d " site.strength
)
;;
let debug_game_map state =
debug_owners state;
debug_strength state;
debug_productions state;
;;
(* End utility *)
let init () =
Random.self_init ();
let gmap =
{
width = (-1);
height = (-1);
contents = [|[| |]|];
}
in
let state =
{
my_id = (-1);
round = 0;
max_rounds = 0;
last_update = (-1.0);
game_map = gmap;
}
in
state
;;
================================================
FILE: airesources/OCaml/runGame.bat
================================================
ocamlbuild -lib unix MyBot.native
ocamlbuild -lib unix RandomBot.native
.\halite.exe -d "30 30" ".\MyBot.exe" ".\RandomBot.exe"
================================================
FILE: airesources/OCaml/runGame.sh
================================================
#!/bin/bash
ocamlbuild -lib unix MyBot.native
ocamlbuild -lib unix RandomBot.native
./halite -d "30 30" "./MyBot.native" "./RandomBot.native"
================================================
FILE: airesources/OCaml/td.ml
================================================
(* OCaml Starter for Halite on Halite.io
This code is public domain. There is no warranty.
*)
type t_direction = [ `Still | `North | `East | `South | `West ] ;;
type location =
{
mutable row : int;
mutable col : int;
}
;;
type site =
{
mutable owner : int;
mutable strength : int;
mutable production : int;
}
;;
type move =
{
mutable loc : location;
mutable direction : t_direction;
}
;;
type game_map =
{
mutable width : int;
mutable height : int;
mutable contents : site array array;
}
;;
type game_state =
{
mutable my_id : int;
mutable round : int;
mutable max_rounds : int;
mutable last_update : float;
mutable game_map : game_map;
}
;;
================================================
FILE: airesources/PHP/MyBot.php
================================================
height; ++$y) {
for ($x = 0; $x < $gameMap->width; ++$x) {
if ($gameMap->getSite(new Location($x, $y))->owner === $myID) {
$moves[] = new Move(new Location($x, $y), rand(0, 4));
}
}
}
sendFrame($moves);
}
================================================
FILE: airesources/PHP/RandomBot.php
================================================
height; ++$y) {
for ($x = 0; $x < $gameMap->width; ++$x) {
if ($gameMap->getSite(new Location($x, $y))->owner === $myID) {
$moves[] = new Move(new Location($x, $y), rand(0, 4));
}
}
}
sendFrame($moves);
}
================================================
FILE: airesources/PHP/hlt.php
================================================
x = $x;
$this->y = $y;
}
}
class Site
{
public $owner;
public $strength;
public $production;
public function __construct($owner = 0, $strength = 0, $production = 0)
{
$this->owner = $owner;
$this->strength = $strength;
$this->production = $production;
}
}
class Move
{
public $loc;
public $direction;
public function __construct(Location $loc, $direction = STILL)
{
$this->loc = $loc;
$this->direction = $direction;
}
}
class GameMap
{
public $width;
public $height;
public $contents;
public function __construct($width = 0, $height = 0, $numberOfPlayers = 0)
{
$this->width = $width;
$this->height = $height;
$this->contents = [];
for ($y = 0; $y < $this->height; ++$y) {
$row = [];
for ($x = 0; $x < $this->width; ++$x) {
$row[] = new Site(0, 0, 0);
}
$this->contents[] = $row;
}
}
public function inBounds(Location $l)
{
return $l->x >= 0 && $l->x < $this->width && $l->y >= 0 && $l->y < $this->height;
}
public function getDistance(Location $l1, Location $l2)
{
$dx = abs($l1->x - $l2->x);
$dy = abs($l1->y - $l2->y);
if ($dx > $this->width / 2) {
$dx = $this->width - $dx;
}
if ($dy > $this->height / 2) {
$dy = $this->height - $dy;
}
return $dx + $dy;
}
public function getAngle(Location $l1, Location $l2)
{
$dx = $l2->x - $l1->x;
$dy = $l2->y - $l1->y;
if ($dx > $this->width - $dx) {
$dx -= $this->width;
} elseif (-$dx > $this->width + $dx) {
$dx += $this->width;
}
if ($dy > $this->height - $dy) {
$dy -= $this->height;
} elseif (-$dy > $this->height + $dy) {
$dy += $this->height;
}
return atan2($dy, $dx);
}
public function getLocation(Location $loc, $direction)
{
$l = clone $loc;
if ($direction !== STILL) {
if ($direction === NORTH) {
if ($l->y === 0) {
$l->y = $this->height - 1;
} else {
$l->y -= 1;
}
} elseif ($direction === EAST) {
if ($l->x === $this->width - 1) {
$l->x = 0;
} else {
$l->x += 1;
}
} elseif ($direction === SOUTH) {
if ($l->y === $this->height - 1) {
$l->y = 0;
} else {
$l->y += 1;
}
} elseif ($direction === WEST) {
if ($l->x === 0) {
$l->x = $this->width - 1;
} else {
$l->x -= 1;
}
}
}
return $l;
}
public function getSite(Location $l, $direction = STILL)
{
$l = $this->getLocation($l, $direction);
return $this->contents[$l->y][$l->x];
}
}
================================================
FILE: airesources/PHP/networking.php
================================================
loc->x . ' ' . $move->loc->y . ' ' . $move->direction . ' ';
}
return $returnString;
}
function deserializeMapSize($inputString)
{
global $_width, $_height;
$splitString = explode(' ', $inputString);
$_width = (int)array_shift($splitString);
$_height = (int)array_shift($splitString);
}
function deserializeProductions($inputString)
{
global $_width, $_height, $_productions;
$splitString = explode(' ', $inputString);
for ($a = 0; $a < $_height; ++$a) {
$row = [];
for ($b = 0; $b < $_width; ++$b) {
$row[] = (int)array_shift($splitString);
}
$_productions[] = $row;
}
}
function deserializeMap($inputString)
{
global $_width, $_height, $_productions;
$splitString = explode(' ', $inputString);
$m = new GameMap($_width, $_height);
$y = 0;
$x = 0;
while ($y !== $m->height) {
$counter = (int)array_shift($splitString);
$owner = (int)array_shift($splitString);
for ($a = 0; $a < $counter; ++$a) {
$m->contents[$y][$x]->owner = $owner;
$x += 1;
if ($x === $m->width) {
$x = 0;
$y += 1;
}
}
}
for ($a = 0; $a < $_height; ++$a) {
for ($b = 0; $b < $_width; ++$b) {
$m->contents[$a][$b]->strength = (int)array_shift($splitString);
$m->contents[$a][$b]->production = $_productions[$a][$b];
}
}
return $m;
}
function sendString($toBeSent)
{
$toBeSent .= "\n";
fwrite(STDOUT, $toBeSent);
}
function getString()
{
$input = fgets(STDIN);
if ($input === false) {
exit;
}
return rtrim($input, "\n");
}
function getInit()
{
$playerTag = (int)getString();
deserializeMapSize(getString());
deserializeProductions(getString());
$m = deserializeMap(getString());
return [$playerTag, $m];
}
function sendInit($name)
{
sendString($name);
}
function getFrame()
{
return deserializeMap(getString());
}
function sendFrame(array $moves)
{
sendString(serializeMoveSet($moves));
}
================================================
FILE: airesources/PHP/runGame.bat
================================================
.\halite.exe -d "30 30" "php MyBot.php" "php RandomBot.php"
================================================
FILE: airesources/PHP/runGame.sh
================================================
#!/bin/bash
./halite -d "30 30" "php MyBot.php" "php RandomBot.php"
================================================
FILE: airesources/Python/MyBot.py
================================================
import hlt
from hlt import NORTH, EAST, SOUTH, WEST, STILL, Move, Square
import random
myID, game_map = hlt.get_init()
hlt.send_init("MyPythonBot")
while True:
game_map.get_frame()
moves = [Move(square, random.choice((NORTH, EAST, SOUTH, WEST, STILL))) for square in game_map if square.owner == myID]
hlt.send_frame(moves)
================================================
FILE: airesources/Python/RandomBot.py
================================================
import hlt
from hlt import NORTH, EAST, SOUTH, WEST, STILL, Move, Square
import random
myID, game_map = hlt.get_init()
hlt.send_init("RandomPythonBot")
while True:
game_map.get_frame()
moves = [Move(square, random.choice((NORTH, EAST, SOUTH, WEST, STILL))) for square in game_map if square.owner == myID]
hlt.send_frame(moves)
================================================
FILE: airesources/Python/hlt.py
================================================
import sys
from collections import namedtuple
from itertools import chain, zip_longest
def grouper(iterable, n, fillvalue=None):
"Collect data into fixed-length chunks or blocks"
# grouper('ABCDEFG', 3, 'x') --> ABC DEF Gxx"
args = [iter(iterable)] * n
return zip_longest(*args, fillvalue=fillvalue)
NORTH, EAST, SOUTH, WEST, STILL = range(5)
def opposite_cardinal(direction):
"Returns the opposing cardinal direction."
return (direction + 2) % 4 if direction != STILL else STILL
Square = namedtuple('Square', 'x y owner strength production')
Move = namedtuple('Move', 'square direction')
class GameMap:
def __init__(self, size_string, production_string, map_string=None):
self.width, self.height = tuple(map(int, size_string.split()))
self.production = tuple(tuple(map(int, substring)) for substring in grouper(production_string.split(), self.width))
self.contents = None
self.get_frame(map_string)
self.starting_player_count = len(set(square.owner for square in self)) - 1
def get_frame(self, map_string=None):
"Updates the map information from the latest frame provided by the Halite game environment."
if map_string is None:
map_string = get_string()
split_string = map_string.split()
owners = list()
while len(owners) < self.width * self.height:
counter = int(split_string.pop(0))
owner = int(split_string.pop(0))
owners.extend([owner] * counter)
assert len(owners) == self.width * self.height
assert len(split_string) == self.width * self.height
self.contents = [[Square(x, y, owner, strength, production)
for x, (owner, strength, production)
in enumerate(zip(owner_row, strength_row, production_row))]
for y, (owner_row, strength_row, production_row)
in enumerate(zip(grouper(owners, self.width),
grouper(map(int, split_string), self.width),
self.production))]
def __iter__(self):
"Allows direct iteration over all squares in the GameMap instance."
return chain.from_iterable(self.contents)
def neighbors(self, square, n=1, include_self=False):
"Iterable over the n-distance neighbors of a given square. For single-step neighbors, the enumeration index provides the direction associated with the neighbor."
assert isinstance(include_self, bool)
assert isinstance(n, int) and n > 0
if n == 1:
combos = ((0, -1), (1, 0), (0, 1), (-1, 0), (0, 0)) # NORTH, EAST, SOUTH, WEST, STILL ... matches indices provided by enumerate(game_map.neighbors(square))
else:
combos = ((dx, dy) for dy in range(-n, n+1) for dx in range(-n, n+1) if abs(dx) + abs(dy) <= n)
return (self.contents[(square.y + dy) % self.height][(square.x + dx) % self.width] for dx, dy in combos if include_self or dx or dy)
def get_target(self, square, direction):
"Returns a single, one-step neighbor in a given direction."
dx, dy = ((0, -1), (1, 0), (0, 1), (-1, 0), (0, 0))[direction]
return self.contents[(square.y + dy) % self.height][(square.x + dx) % self.width]
def get_distance(self, sq1, sq2):
"Returns Manhattan distance between two squares."
dx = min(abs(sq1.x - sq2.x), sq1.x + self.width - sq2.x, sq2.x + self.width - sq1.x)
dy = min(abs(sq1.y - sq2.y), sq1.y + self.height - sq2.y, sq2.y + self.height - sq1.y)
return dx + dy
#################################################################
# Functions for communicating with the Halite game environment #
#################################################################
def send_string(s):
sys.stdout.write(s)
sys.stdout.write('\n')
sys.stdout.flush()
def get_string():
return sys.stdin.readline().rstrip('\n')
def get_init():
playerID = int(get_string())
m = GameMap(get_string(), get_string())
return playerID, m
def send_init(name):
send_string(name)
def translate_cardinal(direction):
"Translate direction constants used by this Python-based bot framework to that used by the official Halite game environment."
return (direction + 1) % 5
def send_frame(moves):
send_string(' '.join(str(move.square.x) + ' ' + str(move.square.y) + ' ' + str(translate_cardinal(move.direction)) for move in moves))
================================================
FILE: airesources/Python/runGame.bat
================================================
.\halite.exe -d "30 30" "python MyBot.py" "python RandomBot.py"
================================================
FILE: airesources/Python/runGame.sh
================================================
#!/bin/bash
if hash python3 2>/dev/null; then
./halite -d "30 30" "python3 MyBot.py" "python3 RandomBot.py"
else
./halite -d "30 30" "python MyBot.py" "python RandomBot.py"
fi
================================================
FILE: airesources/Ruby/MyBot.rb
================================================
$:.unshift(File.dirname(__FILE__))
require 'networking'
network = Networking.new("RubyBot")
tag, map = network.configure
while true
moves = []
map = network.frame
(0...map.height).each do |y|
(0...map.width).each do |x|
loc = Location.new(x, y)
site = map.site(loc)
if site.owner == tag
moves << Move.new(loc, GameMap::DIRECTIONS.shuffle.first)
end
end
end
network.send_moves(moves)
end
================================================
FILE: airesources/Ruby/RandomBot.rb
================================================
$:.unshift(File.dirname(__FILE__))
require 'networking'
network = Networking.new("RandomRubyBot")
tag, map = network.configure
while true
moves = []
map = network.frame
(0...map.height).each do |y|
(0...map.width).each do |x|
loc = Location.new(x, y)
site = map.site(loc)
if site.owner == tag
moves << Move.new(loc, GameMap::DIRECTIONS.shuffle.first)
end
end
end
network.send_moves(moves)
end
================================================
FILE: airesources/Ruby/game_map.rb
================================================
class GameMap
CARDINALS = [:north, :east, :south, :west]
DIRECTIONS = [:still] + CARDINALS
attr_reader :width, :height
attr_reader :content
def initialize(options = {})
@width = options[:width]
@height = options[:height]
@content = []
options[:owners].each_with_index do |owner, idx|
site = Site.new(owner, options[:strengths][idx], options[:production][idx])
y, x = idx.divmod(@width)
@content[y] ||= []
@content[y][x] = site
end
end
def site(location, direction = :still)
new_location = find_location(location, direction)
content[new_location.y][new_location.x]
end
def find_location(location, direction)
x, y = location.x, location.y
case direction
when :north
y = y == 0 ? height - 1 : y - 1
when :east
x = x == width - 1 ? 0 : x + 1
when :south
y = y == height - 1 ? 0 : y + 1
when :west
x = x == 0 ? width - 1 : x - 1
end
Location.new(x, y)
end
def distance_between(from, to)
dx = (from.x - to.x).abs
dy = (from.y - to.y).abs
dx = width - dx if dx > width / 2
dy = height - dy if dy > height / 2
dx + dy
end
def angle_between(from, to)
dx = to.x - from.x
dy = to.y - from.y
if dx > width - dx
dx -= width
elsif -dx > width + dx
dx += width
end
if dy > height - dy
dy -= height
elsif -dy > height + dy
dy += height
end
Math.atan2(dy, dx)
end
def in_bounds(loc)
loc.x.between?(0, width - 1) && loc.y.between?(0, height - 1)
end
end
================================================
FILE: airesources/Ruby/location.rb
================================================
class Location
attr_reader :x, :y
def initialize(x, y)
@x, @y = x, y
end
end
================================================
FILE: airesources/Ruby/move.rb
================================================
class Move
attr_reader :location, :direction
def initialize(location, direction)
@location = location
@direction = GameMap::DIRECTIONS.index(direction)
end
def to_s
[location.x, location.y, direction].join(' ')
end
end
================================================
FILE: airesources/Ruby/networking.rb
================================================
require 'logger'
require 'location'
require 'move'
require 'site'
require 'game_map'
class Networking
attr_reader :player_tag
attr_reader :width, :height, :size
attr_reader :production
attr_reader :name
def initialize(name)
# implicit IO flush
$stdout.sync = true
@name = name
init_player_tag
init_map_size
init_map_production
init_map
end
# getInit/sendInit
def configure
write_to_output(name)
[player_tag, @map]
end
# getFrame
def frame
init_map
end
# sendMoves
def send_moves(moves = [])
write_to_output(moves.join(' '))
end
def logger
@logger ||= Logger.new("bot-#{name}.log").tap do |l|
l.formatter = proc do |severity, datetime, progname, msg|
"#{datetime.strftime("%Y-%m-%d %H:%M:%S.%6N")} - #{severity} - #{msg}\n"
end
end
end
def log(msg, severity = :info)
logger.send(severity, msg)
end
private
def init_player_tag
@player_tag = Integer(read_from_input)
log("player tag: #{@player_tag}")
end
def init_map_size
@width, @height = read_ints_from_input
@size = @width * @height
log("width: #{@width} - height: #{@height} - size: #{@size}")
end
def init_map_production
@production = read_ints_from_input
end
def init_map
data = read_ints_from_input
owners_map = []
until owners_map.size == size
counter = data.shift
owner = data.shift
owners_map += [owner] * counter
end
@map = GameMap.new( width: width,
height: height,
owners: owners_map,
strengths: data,
production: production)
end
def read_from_input
$stdin.gets.strip
end
def read_ints_from_input
read_from_input.split(' ').map { |v| Integer(v) }
end
def write_to_output(data)
data = "#{data.strip}\n"
log("Sending: #{data.inspect}")
$stdout.puts(data)
end
end
================================================
FILE: airesources/Ruby/runGame.bat
================================================
.\halite.exe -d "30 30" "ruby MyBot.rb" "ruby RandomBot.rb"
================================================
FILE: airesources/Ruby/runGame.sh
================================================
#!/bin/bash
./halite -d "30 30" "ruby MyBot.rb" "ruby RandomBot.rb"
================================================
FILE: airesources/Ruby/site.rb
================================================
class Site
attr_reader :owner, :strength, :production
def initialize(owner = 0, strength = 0, production = 0)
@owner, @strength, @production = owner, strength, production
end
end
================================================
FILE: airesources/Rust/Cargo.toml
================================================
[package]
name = "Rust"
version = "0.1.0"
authors = ["Benjamin Spector "]
publish = false
vcs = "None"
[dependencies]
rand = "*"
text_io = "*"
[[bin]]
path = "src/MyBot.rs"
name = "MyBot"
[[bin]]
path = "src/RandomBot.rs"
name = "RandomBot"
================================================
FILE: airesources/Rust/runGame.bat
================================================
cargo build
.\halite.exe -d "30 30" "target/debug/MyBot" "target/debug/RandomBot"
================================================
FILE: airesources/Rust/runGame.sh
================================================
#!/bin/bash
cargo build
./halite -d "30 30" "target/debug/MyBot" "target/debug/RandomBot"
================================================
FILE: airesources/Rust/src/MyBot.rs
================================================
#![allow(non_snake_case)]
#![allow(warnings)]
extern crate rand;
#[macro_use] extern crate text_io;
//Notice: due to Rust's extreme dislike of (even private!) global mutables, we do not reset the production values of each tile during get_frame.
//If you change them, you may not be able to recover the actual production values of the map, so we recommend not editing them.
//However, if your code calls for it, you're welcome to edit the production values of the sites of the map - just do so at your own risk.
mod hlt;
use hlt::{ networking, types };
use std::collections::HashMap;
use rand::Rng;
fn main() {
let (my_id, mut game_map) = networking::get_init();
let mut rng = rand::thread_rng();
networking::send_init(format!("{}{}", "RustBot".to_string(), my_id.to_string()));
loop {
networking::get_frame(&mut game_map);
let mut moves = HashMap::new();
for a in 0..game_map.height {
for b in 0..game_map.width {
let l = hlt::types::Location { x: b, y: a };
if game_map.get_site(l, types::STILL).owner == my_id {
moves.insert(l, (rng.gen::() % 5) as u8);
}
}
}
networking::send_frame(moves);
}
}
================================================
FILE: airesources/Rust/src/RandomBot.rs
================================================
#![allow(non_snake_case)]
#![allow(warnings)]
extern crate rand;
#[macro_use] extern crate text_io;
//Notice: due to Rust's extreme dislike of (even private!) global mutables, we do not reset the production values of each tile during get_frame.
//If you change them, you may not be able to recover the actual production values of the map, so we recommend not editing them.
//However, if your code calls for it, you're welcome to edit the production values of the sites of the map - just do so at your own risk.
mod hlt;
use hlt::{ networking, types };
use std::collections::HashMap;
use rand::Rng;
fn main() {
let (my_id, mut game_map) = networking::get_init();
let mut rng = rand::thread_rng();
networking::send_init(format!("{}{}", "RustBot".to_string(), my_id.to_string()));
loop {
networking::get_frame(&mut game_map);
let mut moves = HashMap::new();
for a in 0..game_map.height {
for b in 0..game_map.width {
let l = hlt::types::Location { x: b, y: a };
if game_map.get_site(l, types::STILL).owner == my_id {
moves.insert(l, (rng.gen::() % 5) as u8);
}
}
}
networking::send_frame(moves);
}
}
================================================
FILE: airesources/Rust/src/hlt/mod.rs
================================================
#![allow(warnings)]
pub mod networking;
pub mod types;
================================================
FILE: airesources/Rust/src/hlt/networking.rs
================================================
#![allow(warnings)]
use hlt::types;
use std::io;
use std::collections::HashMap;
use std::io::Write;
use std::str::FromStr;
//Persistant between moves, that way if the user screws up the map it won't persist.
static mut _width: u16 = 0;
static mut _height: u16 = 0;
fn serialize_move_set(moves: HashMap) -> String {
let mut s: String = String::new();
for (l, d) in moves {
s = format!("{}{} {} {} ", s, l.x, l.y, d);
}
s
}
fn deserialize_map_size(s: String) -> () {
let splt: Vec<&str> = s.split(" ").collect();
unsafe {
_width = u16::from_str(splt[0]).unwrap();
_height = u16::from_str(splt[1]).unwrap();
}
}
fn deserialize_productions(s: String) -> types::GameMap {
let splt: Vec<&str> = s.split(" ").collect();
let mut gmp = types::GameMap { width: 0, height: 0, contents: Vec::new() };
unsafe {
gmp.width = _width;
gmp.height= _height;
}
gmp.contents.resize(gmp.height as usize, Vec::new());
let mut loc = 0;
for v in &mut gmp.contents {
for x in 0..gmp.width {
v.push(types::Site { owner: 0, strength: 0, production: u8::from_str(splt[loc]).unwrap() });
loc += 1;
}
}
gmp
}
fn deserialize_map(s: String, gmp: &mut types::GameMap) -> () {
let splt: Vec<&str> = s.split(" ").collect();
unsafe {
let mut counter = 0;
let mut owner = 0;
let mut loc: usize = 0;
for a in 0.._height {
for b in 0.._width {
if counter == 0 {
counter = u16::from_str(splt[loc]).unwrap();
loc += 1;
owner = u8::from_str(splt[loc]).unwrap();
loc += 1;
}
gmp.get_site(types::Location { x: b, y: a }, types::STILL).owner = owner;
counter -= 1;
}
}
for a in 0.._height {
for b in 0.._width {
gmp.get_site(types::Location { x: b, y: a }, types::STILL).strength = u8::from_str(splt[loc]).unwrap();
loc += 1;
}
}
}
}
fn send_string(s: String) -> () {
println!("{}", s);
io::stdout().flush();
}
fn get_string() -> String {
read!("{}\n")
}
pub fn get_init() -> (u8, types::GameMap) {
let playerTag: u8 = u8::from_str(&get_string()).unwrap();
deserialize_map_size(get_string());
let mut gmp = deserialize_productions(get_string());
deserialize_map(get_string(), &mut gmp);
(playerTag, gmp)
}
pub fn send_init(name: String) -> () {
send_string(name);
}
pub fn get_frame(gmp: &mut types::GameMap) -> () {
deserialize_map(get_string(), gmp);
}
pub fn send_frame(moves: HashMap) -> () {
send_string(serialize_move_set(moves));
}
================================================
FILE: airesources/Rust/src/hlt/types.rs
================================================
#![allow(warnings)]
pub const STILL: u8 = 0;
pub const NORTH: u8 = 1;
pub const EAST: u8 = 2;
pub const SOUTH: u8 = 3;
pub const WEST: u8 = 4;
pub const DIRECTIONS: [u8; 5] = [STILL, NORTH, EAST, SOUTH, WEST];
pub const CARDINALS: [u8; 4] = [NORTH, EAST, SOUTH, WEST];
#[derive(Copy, Clone, Hash, Eq, PartialEq, PartialOrd, Ord, Debug)]
pub struct Location {
pub x: u16,
pub y: u16,
}
#[derive(Copy, Clone, Eq, Debug, PartialEq)]
pub struct Site {
pub owner: u8,
pub strength: u8,
pub production: u8,
}
#[derive(Clone, Debug)]
pub struct GameMap {
pub width: u16, //Number of columns.
pub height: u16, //Number of rows.
pub contents: Vec< Vec >,
}
impl GameMap {
pub fn in_bounds(&self, l: Location) -> bool {
l.x < self.width && l.y < self.height
}
pub fn get_distance(&self, l1: Location, l2: Location) -> u16 {
let mut dx = (l1.x as i16 - l2.x as i16).abs();
let mut dy = (l1.y as i16 - l2.y as i16).abs();
if dx > self.width as i16 / 2 { dx = self.width as i16 - dx; }
if dy > self.height as i16 / 2 { dy = self.height as i16 - dy; }
(dx + dy) as u16
}
pub fn get_angle(&self, l1: Location, l2: Location) -> f64 {
let mut dx = l2.x as i16- l1.x as i16;
let mut dy = l2.y as i16 - l1.y as i16;
if dx > self.width as i16 - dx { dx -= self.width as i16; }
else if-dx > self.width as i16 + dx { dx += self.width as i16; }
if dy > self.height as i16 - dy { dy -= self.height as i16; }
else if -dy > self.height as i16 + dy { dy += self.height as i16; }
(dy as f64).atan2(dx as f64)
}
pub fn get_location(&self, l: Location, d: u8) -> Location {
let mut loc = Location { x: l.x, y: l.y };
if d == NORTH {
if loc.y == 0 { loc.y = self.height - 1; }
else { loc.y -= 1; }
} else if d == EAST {
if loc.x == self.width - 1 { loc.x = 0; }
else { loc.x += 1; }
} else if d == SOUTH {
if loc.y == self.height - 1 { loc.y = 0; }
else { loc.y += 1; }
} else if d == WEST {
if loc.x == 0 { loc.x = self.width - 1; }
else { loc.x -= 1; }
}
loc
}
pub fn get_site(&mut self, l: Location, d: u8) -> &mut Site {
let loc = self.get_location(l, d);
&mut self.contents[loc.y as usize][loc.x as usize]
}
pub fn get_site_ref(&self, l: Location, d: u8) -> &Site {
let loc = self.get_location(l, d);
&self.contents[loc.y as usize][loc.x as usize]
}
}
================================================
FILE: airesources/Scala/Bot.scala
================================================
trait Bot {
def getMoves(grid: Grid): Iterable[Move]
}
trait BotFactory {
def make(id: Int): Bot
}
================================================
FILE: airesources/Scala/Direction.scala
================================================
import scala.util.Random
object Direction {
private val random = new Random()
val CARDINALS = Seq(North, East, South, West)
val ALL = Seq(Still, North, East, South, West)
def getRandomDir: Direction = ALL(random.nextInt(5))
def getRandomCard: Direction = CARDINALS(random.nextInt(4))
}
class Direction(value: Int) {
def getValue = value
}
case object Still extends Direction(0)
case object North extends Direction(1)
case object East extends Direction(2)
case object South extends Direction(3)
case object West extends Direction(4)
================================================
FILE: airesources/Scala/Env.scala
================================================
object Env {
def readId(): Int = {
read().toInt
}
def readInit(): Grid = {
val dims = read().split(" ")
val width = dims(0).toInt
val height = dims(1).toInt
val locations = Array.ofDim[Location](height, width)
val productions = read().split(" ")
for (y <- 0 until height) {
for (x <- 0 until width) {
locations(y)(x) = Location(x, y, productions(y * width + x).toInt)
}
}
val occupants = readFrame(width, height)
new Grid(width, height, locations, occupants)
}
def readFrame(width: Int, height: Int): Array[Array[Occupant]] = {
val ownersStrengths = read().split(" ")
val strengthsIndex = ownersStrengths.length - width * height
var y, x, count = 0
var owner, cur, i = 0
val occupants = Array.ofDim[Occupant](height, width)
while (y < height) {
if (cur < count) {
occupants(y)(x) = Occupant(owner, ownersStrengths(strengthsIndex + y * width + x).toInt)
if (x == width - 1) {
x = 0
y += 1
} else {
x += 1
}
cur += 1
} else {
count = ownersStrengths(i).toInt
owner = ownersStrengths(i + 1).toInt
cur = 0
i += 2
}
}
occupants
}
def writeFrame(moves: Iterable[Move]): Unit = {
val builder = new StringBuilder()
moves foreach { m =>
builder.append(m.location.x)
builder.append(" ")
builder.append(m.location.y)
builder.append(" ")
builder.append(m.direction.getValue)
builder.append(" ")
}
writeString(builder.toString())
}
def writeInit(name: String): Unit = {
writeString(name)
}
private def writeString(s: String): Unit = {
System.out.print(s + '\n')
System.out.flush()
}
private def read(): String = {
val buffer = new StringBuilder()
var next = System.in.read()
while (next != '\n' && next != 0) {
buffer.append(next.asInstanceOf[Char])
next = System.in.read()
}
buffer.toString
}
}
================================================
FILE: airesources/Scala/Grid.scala
================================================
object Grid {
val NEUTRAL = 0
}
class Grid(width: Int, height: Int, locations: Array[Array[Location]], var occupants: Array[Array[Occupant]]) {
def update(occupants: Array[Array[Occupant]]) = this.occupants = occupants
def getWidth = width
def getHeight = height
def getOccupant(x: Int, y: Int): Occupant = occupants(y)(x)
def getLocation(x: Int, y: Int): Location = locations(y)(x)
def getSite(x: Int, y: Int): Site = Site(getLocation(x, y), getOccupant(x, y))
def getSites: Seq[Site] = {
for {
x <- 0 until width
y <- 0 until height
} yield getSite(x, y)
}
def getMine(id: Int): Seq[Site] = {
for {
x <- 0 until width
y <- 0 until height
if getOccupant(x, y).id == id
} yield getSite(x, y)
}
def getDistance(first: Location, second: Location): Int = {
var dx = Math.abs(first.x - second.x)
var dy = Math.abs(first.y - second.y)
if (dx > width / 2.0) {
dx = width - dx
}
if (dy > height / 2.0) {
dy = height - dy
}
dx + dy
}
def getAngle(first: Location, second: Location): Double = {
var dx = first.x - second.x
// Flip order because 0,0 is top left
// and want atan2 to look as it would on the unit circle
var dy = second.y - first.y
if (dx > width - dx) {
dx -= width
}
if (-dx > width + dx) {
dx += width
}
if (dy > height - dy) {
dy -= height
}
if (-dy > height + dy) {
dy += height
}
Math.atan2(dy, dx)
}
def getNeighbor(location: Location, direction: Direction): Neighbor = {
val x = location.x
val y = location.y
direction match {
case North => Neighbor(getSite(x, if (y == 0) height - 1 else y - 1), North)
case East => Neighbor(getSite(if (x == width - 1) 0 else x + 1, y), East)
case South => Neighbor(getSite(x, if (y == height - 1) 0 else y + 1), South)
case West => Neighbor(getSite(if (x == 0) width - 1 else x - 1, y), West)
case Still => Neighbor(getSite(x, y), Still)
}
}
def getNeighbors(location: Location): Seq[Neighbor] = {
Direction.CARDINALS map (d => getNeighbor(location, d))
}
def getMyNeighbors(id: Int, location: Location): Seq[Neighbor] = {
getNeighbors(location).filter(_.site.occupant.id == id)
}
}
case class Location(x: Int, y: Int, production: Int)
case class Occupant(id: Int, strength: Int)
case class Site(location: Location, occupant: Occupant)
case class Neighbor(site: Site, direction: Direction)
================================================
FILE: airesources/Scala/Move.scala
================================================
case class Move(location: Location, direction: Direction)
================================================
FILE: airesources/Scala/MyBot.scala
================================================
object MyBot extends BotFactory {
def main(args: Array[String]): Unit = {
Runner.run("scalaMyBot", this)
}
override def make(id: Int): Bot = new MyBot(id)
}
class MyBot(myId: Int) extends Bot {
override def getMoves(grid: Grid): Iterable[Move] = {
for {
site <- grid.getMine(myId)
} yield Move(site.location, Direction.getRandomDir)
}
}
================================================
FILE: airesources/Scala/RandomBot.scala
================================================
object RandomBot extends BotFactory {
def main(args: Array[String]): Unit = {
Runner.run("scalaRandom", this)
}
override def make(id: Int): Bot = new RandomBot(id)
}
class RandomBot(myId: Int) extends Bot {
override def getMoves(grid: Grid): Iterable[Move] = {
for {
site <- grid.getMine(myId)
} yield Move(site.location, Direction.getRandomDir)
}
}
================================================
FILE: airesources/Scala/Runner.scala
================================================
object Runner {
def run(name: String, botFactory: BotFactory): Unit = {
val id = Env.readId()
val grid = Env.readInit()
val bot = botFactory.make(id)
Env.writeInit(name)
while (true) {
val occupants = Env.readFrame(grid.getWidth, grid.getHeight)
grid.update(occupants)
val moves = bot.getMoves(grid)
Env.writeFrame(moves)
}
}
}
================================================
FILE: airesources/Scala/runGame.bat
================================================
javac *.java
scalac HaliteBot.scala
scalac MyBot.scala
scalac RandomBot.scala
\halite.exe -d "30 30" "scala MyBot" "scala RandomBot"
================================================
FILE: airesources/Scala/runGame.sh
================================================
#!/bin/bash
scalac *.scala
./halite -d "30 30" "scala MyBot" "scala RandomBot"
================================================
FILE: airesources/Sockets/HaliteSocketHelper.cs
================================================
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Net;
using System.Net.Sockets;
/*
* Note: For reasons presently unclear this networking package
* does not appear to be working with the pipe_socket_translator.py
* also provided. Please see the forums for a temporary workaround
* while we fix this issue. Thank you.
*/
///
/// Helpful for debugging.
///
public static class Log
{
private static string _logPath;
///
/// File must exist
///
public static void Setup(string logPath) {
_logPath = logPath;
}
public static void Information(string message) {
if (!string.IsNullOrEmpty(_logPath))
File.AppendAllLines(_logPath, new[] {string.Format("{0}: {1}", DateTime.Now.ToShortTimeString(), message)});
}
public static void Error(Exception exception) {
Log.Information(string.Format("ERROR: {0} {1}", exception.Message, exception.StackTrace));
}
}
public static class Networking
{
/// Socket input stream.
private static StreamReader _streamReader;
private static StreamWriter _streamWriter;
private static string ReadNextLine() {
var str = _streamReader.ReadLine();
if (str == null) throw new ApplicationException("Could not read next line from socket");
return str;
}
private static void SendString(string str) {
_streamWriter.WriteLine(str);
}
///
/// Call once at the start of a game to load the map and player tag from the first four stdin lines.
///
public static Map getInit(out ushort playerTag) {
Console.WriteLine("Enter the port on which to connect: ");
var client = new TcpClient("127.0.0.1", int.Parse(Console.ReadLine()));
var networkStream = client.GetStream();
_streamReader = new StreamReader(new BufferedStream(networkStream));
_streamWriter = new StreamWriter(networkStream) {AutoFlush = true};
// Line 1: Player tag
if (!ushort.TryParse(ReadNextLine(), out playerTag))
throw new ApplicationException("Could not get player tag from socket during init");
// Lines 2-4: Map
var map = Map.ParseMap(ReadNextLine(), ReadNextLine(), ReadNextLine());
return map;
}
///
/// Call every frame to update the map to the next one provided by the environment.
///
public static void getFrame(ref Map map) {
map.Update(ReadNextLine());
}
///
/// Call to acknowledge the initail game map and start the game.
///
public static void SendInit(string botName) {
SendString(botName);
}
///
/// Call to send your move orders and complete your turn.
///
public static void SendMoves(IEnumerable moves) {
SendString(Move.MovesToString(moves));
}
}
public enum Direction
{
Still = 0,
North = 1,
East = 2,
South = 3,
West = 4
}
public struct Site
{
public ushort Owner { get; internal set; }
public ushort Strength { get; internal set; }
public ushort Production { get; internal set; }
}
public struct Location
{
public ushort X;
public ushort Y;
}
public struct Move
{
public Location Location;
public Direction Direction;
internal static string MovesToString(IEnumerable moves) {
return string.Join(" ", moves.Select(m => string.Format("{0} {1} {2}", m.Location.X, m.Location.Y, (int)m.Direction)));
}
}
///
/// State of the game at every turn. Use to get the map for a new game from
/// stdin, and use to update the map after orders for a turn have been executed.
///
public class Map
{
public void Update(string gameMapStr) {
var gameMapValues = new Queue(gameMapStr.Split(new[] {' '}, StringSplitOptions.RemoveEmptyEntries));
ushort x = 0, y = 0;
while (y < Height) {
ushort counter, owner;
if (!ushort.TryParse(gameMapValues.Dequeue(), out counter))
throw new ApplicationException("Could not get some counter from stdin");
if (!ushort.TryParse(gameMapValues.Dequeue(), out owner))
throw new ApplicationException("Could not get some owner from stdin");
while (counter > 0) {
_sites[x, y] = new Site {Owner = owner};
x++;
if (x == Width) {
x = 0;
y++;
}
counter--;
}
}
var strengthValues = gameMapValues; // Referencing same queue, but using a name that is more clear
for (x = 0; x < Width; x++) {
for (y = 0; y < Height; y++) {
ushort strength;
if (!ushort.TryParse(strengthValues.Dequeue(), out strength))
throw new ApplicationException("Could not get some strength value from stdin");
_sites[x, y].Strength = strength;
}
}
}
///
/// Get a read-only structure representing the current state of the site at the supplied coordinates.
///
public Site this[ushort x, ushort y] {
get {
if (x >= Width)
throw new IndexOutOfRangeException(string.Format("Cannot get site at ({0},{1}) beacuse width is only {2}", x, y, Width));
if (y >= Height)
throw new IndexOutOfRangeException(string.Format("Cannot get site at ({0},{1}) beacuse height is only {2}", x, y, Height));
return _sites[x, y];
}
}
///
/// Get a read-only structure representing the current state of the site at the supplied location.
///
public Site this[Location location] => this[location.X, location.Y];
///
/// Returns the width of the map.
///
public ushort Width => (ushort)_sites.GetLength(0);
///
/// Returns the height of the map.
///
public ushort Height => (ushort)_sites.GetLength(1);
#region Implementation
private readonly Site[,] _sites;
private Map(ushort width, ushort height) {
_sites = new Site[width, height];
for (ushort x = 0; x < width; x++) {
for (ushort y = 0; y < height; y++) {
_sites[x, y] = new Site();
}
}
}
private static Tuple ParseMapSize(string mapSizeStr) {
ushort width, height;
var parts = mapSizeStr.Split(new[] {' '}, StringSplitOptions.RemoveEmptyEntries);
if (parts.Length != 2 || !ushort.TryParse(parts[0], out width) || !ushort.TryParse(parts[1], out height))
throw new ApplicationException("Could not get map size from stdin during init");
return Tuple.Create(width, height);
}
public static Map ParseMap(string mapSizeStr, string productionMapStr, string gameMapStr) {
var mapSize = ParseMapSize(mapSizeStr);
var map = new Map(mapSize.Item1, mapSize.Item2);
var productionValues = new Queue(productionMapStr.Split(new[] {' '}, StringSplitOptions.RemoveEmptyEntries));
ushort x, y;
for (x = 0; x < map.Width; x++) {
for (y = 0; y < map.Height; y++) {
ushort production;
if (!ushort.TryParse(productionValues.Dequeue(), out production))
throw new ApplicationException("Could not get some production value from stdin");
map._sites[x, y].Production = production;
}
}
map.Update(gameMapStr);
return map;
}
#endregion
}
================================================
FILE: airesources/Sockets/SocketNetworking.java
================================================
import java.net.*;
import java.io.*;
import java.util.ArrayList;
import java.util.Scanner;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
public class SocketNetworking {
public static final int SIZE_OF_INTEGER_PREFIX = 4;
public static final int CHAR_SIZE = 1;
private static BufferedReader _in;
private static PrintWriter _out;
private static int _width, _height;
private static ArrayList< ArrayList > _productions;
private static void deserializeGameMapSize(String inputString) {
String[] inputStringComponents = inputString.split(" ");
_width = Integer.parseInt(inputStringComponents[0]);
_height = Integer.parseInt(inputStringComponents[1]);
}
private static void deserializeProductions(String inputString) {
String[] inputStringComponents = inputString.split(" ");
int index = 0;
_productions = new ArrayList< ArrayList >();
for(int a = 0; a < _height; a++) {
ArrayList row = new ArrayList();
for(int b = 0; b < _width; b++) {
row.add(Integer.parseInt(inputStringComponents[index]));
index++;
}
_productions.add(row);
}
}
private static String serializeMoveList(ArrayList moves) {
StringBuilder builder = new StringBuilder();
for(Move move : moves) builder.append(move.loc.x + " " + move.loc.y + " " + move.dir.ordinal() + " ");
return builder.toString();
}
private static GameMap deserializeGameMap(String inputString) {
String[] inputStringComponents = inputString.split(" ");
GameMap map = new GameMap(_width, _height);
// Run-length encode of owners
int y = 0, x = 0;
int counter = 0, owner = 0;
int currentIndex = 0;
while(y != map.height) {
counter = Integer.parseInt(inputStringComponents[currentIndex]);
owner = Integer.parseInt(inputStringComponents[currentIndex + 1]);
currentIndex += 2;
for(int a = 0; a < counter; ++a) {
map.contents.get(y).get(x).owner = owner;
++x;
if(x == map.width) {
x = 0;
++y;
}
}
}
for (int a = 0; a < map.contents.size(); ++a) {
for (int b = 0; b < map.contents.get(a).size(); ++b) {
int strengthInt = Integer.parseInt(inputStringComponents[currentIndex]);
currentIndex++;
map.contents.get(a).get(b).strength = strengthInt;
map.contents.get(a).get(b).production = _productions.get(a).get(b);
}
}
return map;
}
private static void sendString(String sendString) throws java.io.IOException {
_out.println(sendString);
_out.flush();
}
private static String getString() throws java.io.IOException {
return _in.readLine();
}
public static InitPackage getInit() throws java.io.IOException {
//Set up connection
System.out.print("Enter the port on which to connect: ");
Scanner in = new Scanner(System.in);
int port = in.nextInt();
Socket connection = new Socket("127.0.0.1", port);
System.out.println("Connected to intermediary on port #" + port);
_in = new BufferedReader(new InputStreamReader(connection.getInputStream()));
_out = new PrintWriter(connection.getOutputStream(), false);
InitPackage initPackage = new InitPackage();
initPackage.myID = (int)Long.parseLong(getString());
deserializeGameMapSize(getString());
deserializeProductions(getString());
initPackage.map = deserializeGameMap(getString());
return initPackage;
}
public static void sendInit(String name) throws java.io.IOException {
sendString(name);
}
public static GameMap getFrame() throws java.io.IOException {
return deserializeGameMap(getString());
}
public static void sendFrame(ArrayList moves) throws java.io.IOException {
sendString(serializeMoveList(moves));
}
}
================================================
FILE: airesources/Sockets/pipe_socket_translator.py
================================================
import socket
import sys
# Connect
socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
socket.bind(('localhost', int(sys.argv[1])))
socket.listen(1)
connection, _ = socket.accept()
# IO Functions
def sendStringPipe(toBeSent):
sys.stdout.write(toBeSent+'\n')
sys.stdout.flush()
def getStringPipe():
str = sys.stdin.readline().rstrip('\n')
return(str)
def sendStringSocket(toBeSent):
global connection
toBeSent += '\n'
connection.sendall(bytes(toBeSent, 'ascii'))
def getStringSocket():
global connection
newString = ""
buffer = '\0'
while True:
buffer = connection.recv(1).decode('ascii')
if buffer != '\n':
newString += str(buffer)
else:
return newString
# Handle Init IO
sendStringSocket(getStringPipe()) # Player ID
sendStringSocket(getStringPipe()) # Map Dimensions
sendStringSocket(getStringPipe()) # Productions
sendStringSocket(getStringPipe()) # Starting Map
sendStringPipe(getStringSocket()) # Player Name / Ready Response
# Run Frame Loop
while True:
sendStringSocket(getStringPipe()) # Frame Map
sendStringPipe(getStringSocket()) # Move List
================================================
FILE: airesources/Sockets/socket_networking.hpp
================================================
#ifndef AI_NETWORKING_H
#define AI_NETWORKING_H
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#ifdef _WIN32
#include
#include
#include
#else
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#endif
#include "hlt.hpp"
namespace detail {
static std::vector< std::vector > productions;
static int width, height;
#ifdef _WIN32
static SOCKET connection = INVALID_SOCKET;
#else
static int connection;
#endif
static std::string serializeMoveSet(const std::set &moves) {
std::ostringstream oss;
for(auto a = moves.begin(); a != moves.end(); ++a) oss << a->loc.x << " " << a->loc.y << " " << (int)a->dir << " ";
return oss.str();
}
static void deserializeMapSize(const std::string & inputString) {
std::stringstream iss(inputString);
iss >> width >> height;
}
static void deserializeProductions(const std::string & inputString) {
std::stringstream iss(inputString);
productions.resize(height);
short temp;
for(auto a = productions.begin(); a != productions.end(); a++) {
a->resize(width);
for(auto b = a->begin(); b != a->end(); b++) {
iss >> temp;
*b = temp;
}
}
}
static hlt::GameMap deserializeMap(const std::string & inputString) {
std::stringstream iss(inputString);
hlt::GameMap map(width, height);
//Set productions
for(int a = 0; a < map.height; a++) {
for(int b = 0; b < map.width; b++) {
map.contents[a][b].production = productions[a][b];
}
}
//Run-length encode of owners
unsigned short y = 0, x = 0;
unsigned short counter = 0, owner = 0;
while(y != map.height) {
for(iss >> counter >> owner; counter; counter--) {
map.contents[y][x].owner = owner;
x++;
if(x == map.width) {
x = 0;
y++;
}
}
}
for (int a = 0; a < map.contents.size(); a++) {
for (int b = 0; b < map.contents[a].size(); b++) {
short strengthShort;
iss >> strengthShort;
map.contents[a][b].strength = strengthShort;
}
}
return map;
}
static void sendString(std::string & sendString) {
sendString.push_back('\n');
#ifdef _WIN32
int result = send(connection, sendString.c_str(), sendString.size(), 0);
assert(result != SOCKET_ERROR);
#else
int result = write(connection, sendString.c_str(), sendString.size());
assert(result >= 1); //Should be at least 1, as at least a newline should get written.
#endif
sendString.pop_back(); //Remove newline.
}
static std::string getString() {
std::string newString;
char buffer = 0;
while(buffer != '\n') {
#ifdef _WIN32
int result = recv(connection, &buffer, 1, 0);
assert(result != SOCKET_ERROR);
#else
int result = read(connection, &buffer, 1);
assert(result >= 0);
#endif
newString.push_back(buffer);
}
return newString;
}
}
static void getInit(unsigned char& playerTag, hlt::GameMap& m) {
int port;
std::cout << "Enter the port on which to connect: ";
std::cin >> port;
#ifdef _WIN32
WSADATA wsaData;
int iResult = WSAStartup(MAKEWORD(2,2), &wsaData);
assert(iResult == 0); //Confirms that Winsock started up correctly.
struct addrinfo hints, * result;
ZeroMemory(&hints, sizeof(hints));
hints.ai_family = AF_UNSPEC;
hints.ai_socktype = SOCK_STREAM;
hints.ai_protocol = IPPROTO_TCP;
iResult = getaddrinfo("127.0.0.1", std::to_string(port).c_str(), &hints, &result);
assert(iResult == 0); //Confirms that getaddrinfo did not fail.
detail::connection = socket(result->ai_family, result->ai_socktype, result->ai_protocol); //Creates socket.
assert(detail::connection != INVALID_SOCKET); //Confirms connection is a valid socket.
iResult = connect(detail::connection, result->ai_addr, int(result->ai_addrlen));
assert(iResult != SOCKET_ERROR); //Confirms that there was a successful connection.
freeaddrinfo(result);
#else
//Connect to port
connection = socket(AF_INET, SOCK_STREAM, 0);
assert(detail::connection >= 0);
struct hostent *server;
server = gethostbyname("127.0.0.1");
assert(server != NULL);
struct sockaddr_in serverAddr;
bzero((char *) &serverAddr, sizeof(serverAddr));
serverAddr.sin_family = AF_INET;
bcopy((char *)server->h_addr, (char *)&serverAddr.sin_addr.s_addr, server->h_length);
serverAddr.sin_port = htons(port);
assert(connect(detail::connection, (struct sockaddr *)&serverAddr, sizeof(serverAddr)) >= 0);
#endif
std::cout << "Connected to intermediary on port #" << port << std::endl;
playerTag = (unsigned char)std::stoi(detail::getString());
detail::deserializeMapSize(detail::getString());
detail::deserializeProductions(detail::getString());
m = detail::deserializeMap(detail::getString());
}
static void sendInit(std::string name) {
detail::sendString(name);
}
static void getFrame(hlt::GameMap& m) {
m = detail::deserializeMap(detail::getString());
}
static void sendFrame(const std::set &moves) {
std::string serializedMoves = detail::serializeMoveSet(moves);
detail::sendString(serializedMoves);
}
#endif
================================================
FILE: airesources/Sockets/socket_networking.py
================================================
from hlt import *
import socket
import traceback
import struct
from ctypes import *
import sys
_productions = []
_width = -1
_height = -1
_connection = None
def serializeMoveSet(moves):
returnString = ""
for move in moves:
returnString += str(move.loc.x) + " " + str(move.loc.y) + " " + str(move.direction) + " "
return returnString
def deserializeMapSize(inputString):
splitString = inputString.split(" ")
global _width, _height
_width = int(splitString.pop(0))
_height = int(splitString.pop(0))
def deserializeProductions(inputString):
splitString = inputString.split(" ")
for a in range(0, _height):
row = []
for b in range(0, _width):
row.append(int(splitString.pop(0)))
_productions.append(row)
def deserializeMap(inputString):
splitString = inputString.split(" ")
m = GameMap(_width, _height)
y = 0
x = 0
counter = 0
owner = 0
while y != m.height:
counter = int(splitString.pop(0))
owner = int(splitString.pop(0))
for a in range(0, counter):
m.contents[y][x].owner = owner
x += 1
if x == m.width:
x = 0
y += 1
for a in range(0, _height):
for b in range(0, _width):
m.contents[a][b].strength = int(splitString.pop(0))
m.contents[a][b].production = _productions[a][b]
return m
def sendString(toBeSent):
global _connection
toBeSent += '\n'
_connection.sendall(bytes(toBeSent, 'ascii'))
def getString():
global _connection
newString = ""
buffer = '\0'
while True:
buffer = _connection.recv(1).decode('ascii')
if buffer != '\n':
newString += str(buffer)
else:
return newString
def getInit():
# Connect to environment.
global _connection
_connection = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
port = int(input('Enter the port on which to connect: '))
_connection.connect(('localhost', port))
print('Connected to intermediary on port #' + str(port))
playerTag = int(getString())
deserializeMapSize(getString())
deserializeProductions(getString())
m = deserializeMap(getString())
return (playerTag, m)
def sendInit(name):
sendString(name)
def getFrame():
return deserializeMap(getString())
def sendFrame(moves):
sendString(serializeMoveSet(moves))
================================================
FILE: appveyor.yml
================================================
# Specify version format
version: "{build}"
only_commits:
message: /build/
# Build worker image (VM template)
image: Windows Server 2012 R2
# clone directory
clone_folder: C:\Halite
# branches to build
branches:
only:
- master
#before_build:
# - dir \s
# scripts that run after cloning repository
build_script:
- cd C:\Halite\environment
- .\make.bat
artifacts:
- path: environment\halite.exe
name: halite.exe
================================================
FILE: environment/Makefile
================================================
CXXFLAGS += -std=c++11 -pthread -I ./
INSTALL_PATH?=/usr/local
SOURCES=$(shell find . -name "*.cpp")
OBJECTS=$(SOURCES:%.cpp=%.o)
TARGET=halite
.PHONY: all
all: $(TARGET)
$(TARGET): $(OBJECTS)
$(LINK.cpp) $^ $(LOADLIBES) $(LDLIBS) -o $@
.PHONY: clean
clean:
rm -f $(TARGET) $(OBJECTS)
.PHONY: install
install:
install -m 0755 halite $(INSTALL_PATH)/bin
================================================
FILE: environment/core/Halite.cpp
================================================
#include "Halite.hpp"
#include "limits.h"
#define F_NEWLINE '\n'
//Private Functions ------------------
std::vector Halite::processNextFrame(std::vector alive) {
//Update alive frame counts
for(unsigned char a = 0; a < number_of_players; a++) if(alive[a]) alive_frame_count[a]++;
//Create threads to send/receive data to/from players. The threads should return a float of how much time passed between the end of their message being sent and the end of the AI's message being received.
std::vector< std::future > frameThreads(std::count(alive.begin(), alive.end(), true));
unsigned char threadLocation = 0; //Represents place in frameThreads.
//Get the messages sent by bots this frame
for(unsigned char a = 0; a < number_of_players; a++) {
if(alive[a]) {
frameThreads[threadLocation] = std::async(&Networking::handleFrameNetworking, &networking, a + 1, turn_number, game_map, ignore_timeout, &player_moves[a]);
threadLocation++;
}
}
full_player_moves.push_back(std::vector< std::vector >(game_map.map_height, std::vector(game_map.map_width, 0)));
//Join threads. Figure out if the player responded in an allowable amount of time or if the player has timed out.
threadLocation = 0; //Represents place in frameThreads.
for(unsigned char a = 0; a < number_of_players; a++) {
if(alive[a]) {
int time = frameThreads[threadLocation].get();
if(time == -1) {
networking.killPlayer(a + 1);
timeout_tags.insert(a + 1);
//Give their pieces to the neutral player.
for(unsigned short b = 0; b < game_map.map_height; b++) for(unsigned short c = 0; c < game_map.map_width; c++) if(game_map.contents[b][c].owner == a + 1) game_map.contents[b][c].owner = 0;
}
else total_frame_response_times[a] += time;
threadLocation++;
}
}
std::vector< std::map > pieces(number_of_players);
//For each player, use their moves to create the pieces map.
for(unsigned char a = 0; a < number_of_players; a++) if(alive[a]) {
//Add in pieces according to their moves. Also add in a second piece corresponding to the piece left behind.
for(auto b = player_moves[a].begin(); b != player_moves[a].end(); b++) if(game_map.inBounds(b->first) && game_map.getSite(b->first).owner == a + 1) {
if(b->second == STILL) {
if(game_map.getSite(b->first).strength + game_map.getSite(b->first).production <= 255) game_map.getSite(b->first).strength += game_map.getSite(b->first).production;
else game_map.getSite(b->first).strength = 255;
//Update full still count
full_still_count[a]++;
//Add to full production
full_production_count[a] += game_map.getSite(b->first).production;
}
//Update full caridnal count.
else full_cardinal_count[a]++;
//Update moves
full_player_moves.back()[b->first.y][b->first.x] = b->second;
hlt::Location newLoc = game_map.getLocation(b->first, b->second);
if(pieces[a].count(newLoc)) {
if(short(pieces[a][newLoc]) + game_map.getSite(b->first).strength <= 255) pieces[a][newLoc] += game_map.getSite(b->first).strength;
else pieces[a][newLoc] = 255;
}
else {
pieces[a].insert(std::pair(newLoc, game_map.getSite(b->first).strength));
}
//Add in a new piece with a strength of 0 if necessary.
if(!pieces[a].count(b->first)) {
pieces[a].insert(std::pair(b->first, 0));
}
//Erase from the game map so that the player can't make another move with the same piece.
game_map.getSite(b->first).owner = 0;
game_map.getSite(b->first).strength = 0;
}
}
//Add in all of the remaining pieces whose moves weren't specified.
for(unsigned short a = 0; a < game_map.map_height; a++) for(unsigned short b = 0; b < game_map.map_width; b++) {
hlt::Site & s = game_map.contents[a][b];
if(s.owner != 0) {
hlt::Location l = { b, a };
if(short(s.strength) + s.production <= 255) {
s.strength += s.production;
}
else s.strength = 255;
if(pieces[s.owner - 1].count(l)) {
if(short(pieces[s.owner - 1][l]) + s.strength <= 255) pieces[s.owner - 1][l] += s.strength;
else pieces[s.owner - 1][l] = 255;
}
else {
pieces[s.owner - 1].insert(std::pair(l, s.strength));
}
//Add to full production
full_production_count[s.owner - 1] += s.production;
//Update full still count
full_still_count[s.owner - 1]++;
//Erase from game map.
s.owner = 0;
s.strength = 0;
}
}
std::vector< std::map > toInjure(number_of_players);
std::vector< std::vector > injureMap(game_map.map_height, std::vector(game_map.map_width, 0));
//Sweep through locations and find the correct damage for each piece. Start by applying damage within only the active strengths.
for(unsigned char a = 0; a != game_map.map_height; a++) for(unsigned short b = 0; b < game_map.map_width; b++) {
hlt::Location l = { b, a };
for(unsigned short c = 0; c < number_of_players; c++) if(alive[c] && pieces[c].count(l)) {
for(unsigned short d = 0; d < number_of_players; d++) if(d != c && alive[d]) {
hlt::Location tempLoc = l;
//Check 'STILL' square. We also need to deal with the threshold here:
if(pieces[d].count(tempLoc)) {
//Apply damage, but not more than they have strength:
if(toInjure[d].count(tempLoc)) toInjure[d][tempLoc] += pieces[c][l];
else toInjure[d].insert(std::pair(tempLoc, pieces[c][l]));
}
//Check 'NORTH' square:
tempLoc = game_map.getLocation(l, NORTH);
if(pieces[d].count(tempLoc)) {
//Apply damage, but not more than they have strength:
if(toInjure[d].count(tempLoc)) toInjure[d][tempLoc] += pieces[c][l];
else toInjure[d].insert(std::pair(tempLoc, pieces[c][l]));
}
//Check 'EAST' square:
tempLoc = game_map.getLocation(l, EAST);
if(pieces[d].count(tempLoc)) {
//Apply damage, but not more than they have strength:
if(toInjure[d].count(tempLoc)) toInjure[d][tempLoc] += pieces[c][l];
else toInjure[d].insert(std::pair(tempLoc, pieces[c][l]));
}
//Check 'SOUTH' square:
tempLoc = game_map.getLocation(l, SOUTH);
if(pieces[d].count(tempLoc)) {
//Apply damage, but not more than they have strength:
if(toInjure[d].count(tempLoc)) toInjure[d][tempLoc] += pieces[c][l];
else toInjure[d].insert(std::pair(tempLoc, pieces[c][l]));
}
//Check 'WEST' square:
tempLoc = game_map.getLocation(l, WEST);
if(pieces[d].count(tempLoc)) {
//Apply damage, but not more than they have strength:
if(toInjure[d].count(tempLoc)) toInjure[d][tempLoc] += pieces[c][l];
else toInjure[d].insert(std::pair(tempLoc, pieces[c][l]));
}
}
if(game_map.getSite(l).strength > 0) {
if(toInjure[c].count(l)) toInjure[c][l] += game_map.getSite(l).strength;
else toInjure[c].insert(std::pair(l, game_map.getSite(l).strength));
injureMap[l.y][l.x] += pieces[c][l];
}
}
}
//Injure and/or delete pieces. Note >= rather than > indicates that pieces with a strength of 0 are killed.
for(unsigned char a = 0; a < number_of_players; a++) if(alive[a]) {
for(auto b = toInjure[a].begin(); b != toInjure[a].end(); b++) {
//Apply damage.
if(b->second >= pieces[a][b->first]) pieces[a].erase(b->first);
else pieces[a][b->first] -= b->second;
}
}
//Apply damage to map pieces.
for(int a = 0; a < game_map.map_height; a++) for(int b = 0; b < game_map.map_width; b++) {
if(game_map.contents[a][b].strength < injureMap[a][b]) game_map.contents[a][b].strength = 0;
else game_map.contents[a][b].strength -= injureMap[a][b];
game_map.contents[a][b].owner = 0;
}
//Add pieces back into the map.
for(unsigned char a = 0; a < number_of_players; a++) {
for(auto b = pieces[a].begin(); b != pieces[a].end(); b++) {
game_map.getSite(b->first).owner = a + 1;
game_map.getSite(b->first).strength = b->second;
}
}
//Add to full game:
full_frames.push_back(hlt::Map(game_map));
//Check if the game is over:
std::vector stillAlive(number_of_players, false);
for(auto a = last_territory_count.begin(); a != last_territory_count.end(); a++) *a = 0;
for(unsigned short a = 0; a < game_map.map_height; a++) for(unsigned short b = 0; b < game_map.map_width; b++) if(game_map.contents[a][b].owner != 0) {
last_territory_count[game_map.contents[a][b].owner - 1]++;
full_territory_count[game_map.contents[a][b].owner - 1]++;
full_strength_count[game_map.contents[a][b].owner - 1] += game_map.contents[a][b].strength;
full_production_count[game_map.contents[a][b].owner - 1] += game_map.contents[a][b].strength;
stillAlive[game_map.contents[a][b].owner - 1] = true;
}
return stillAlive;
}
//Public Functions -------------------
Halite::Halite(unsigned short width_, unsigned short height_, unsigned int seed_, unsigned short n_players_for_map_creation, Networking networking_, bool shouldIgnoreTimeout) {
networking = networking_;
// number_of_players is the number of active bots to start the match; it is constant throughout game
number_of_players = networking.numberOfPlayers();
//Initialize map
game_map = hlt::Map(width_, height_, n_players_for_map_creation, seed_);
//If this is single-player mode, remove all the extra players (they were automatically inserted in map, just 0 them out)
if (number_of_players == 1){
for(unsigned short b = 0; b < game_map.map_height; b++) for(unsigned short c = 0; c < game_map.map_width; c++) if(game_map.contents[b][c].owner > 1) game_map.contents[b][c].owner = 0;
}
//Default initialize
player_moves = std::vector< std::map >();
turn_number = 0;
player_names = std::vector< std::string >(number_of_players);
//Add to full game:
full_frames.push_back(hlt::Map(game_map));
//Initialize player moves vector
player_moves.resize(number_of_players);
//Check if timeout should be ignored.
ignore_timeout = shouldIgnoreTimeout;
//Init statistics
productive_squares_remaining = 1; // just more than zero to get through the game_loop the first time
alive_frame_count = std::vector(number_of_players, 1);
last_territory_count = std::vector(number_of_players, 1);
full_territory_count = std::vector(number_of_players, 1);
full_strength_count = std::vector(number_of_players, 255);
full_production_count = std::vector(number_of_players);
full_still_count = std::vector(number_of_players);
full_cardinal_count = std::vector(number_of_players);
init_response_times = std::vector(number_of_players);
total_frame_response_times = std::vector(number_of_players);
timeout_tags = std::set();
}
void Halite::output(std::string filename) {
std::ofstream gameFile;
gameFile.open(filename, std::ios_base::binary);
if(!gameFile.is_open()) throw std::runtime_error("Could not open file for replay");
nlohmann::json j;
//This is version 11.
j["version"] = 11;
//Encode some details about the game that will make it convenient to parse.
j["width"] = game_map.map_width;
j["height"] = game_map.map_height;
j["num_players"] = player_names.size();
j["num_frames"] = full_frames.size();
//Encode player names.
j["player_names"] = nlohmann::json(player_names);
//Encode the production map.
std::vector< std::vector > productions(game_map.map_height, std::vector(game_map.map_width));
for(int a = 0; a < game_map.map_height; a++) {
for(int b = 0; b < game_map.map_width; b++) {
productions[a][b] = (game_map.contents[a][b].production);
}
}
j["productions"] = nlohmann::json(productions);
//Encode the frames. Note that there is no moves field for the last frame.
std::vector< std::vector< std::vector< std::vector > > > frames;
std::vector< std::vector< std::vector > > moves;
frames.reserve(full_frames.size());
moves.reserve(full_frames.size() - 1);
for(int a = 0; a < full_frames.size(); a++) {
std::vector< std::vector< std::vector > > frame(game_map.map_height, std::vector< std::vector >(game_map.map_width));
for(int b = 0; b < game_map.map_height; b++) {
for(int c = 0; c < game_map.map_width; c++) {
frame[b][c].push_back(full_frames[a].contents[b][c].owner);
frame[b][c].push_back(full_frames[a].contents[b][c].strength);
}
}
frames.push_back(frame);
}
for(int a = 0; a < full_frames.size() - 1; a++) {
std::vector< std::vector > move_frame(game_map.map_height, std::vector(game_map.map_width));
for(int b = 0; b < game_map.map_height; b++) {
for(int c = 0; c < game_map.map_width; c++) {
move_frame[b][c] = full_player_moves[a][b][c];
}
}
moves.push_back(move_frame);
}
j["frames"] = nlohmann::json(frames);
j["moves"] = nlohmann::json(moves);
gameFile << j;
gameFile.flush();
gameFile.close();
}
GameStatistics Halite::runGame(std::vector * names_, unsigned int seed, unsigned int id, bool enabledReplay, std::string replayDirectory) {
//For rankings
std::vector result(number_of_players, true);
std::vector rankings;
//Send initial package
std::vector< std::future > initThreads(number_of_players);
for(unsigned char a = 0; a < number_of_players; a++) {
initThreads[a] = std::async(&Networking::handleInitNetworking, &networking, static_cast(a + 1), game_map, ignore_timeout, &player_names[a]);
}
for(unsigned char a = 0; a < number_of_players; a++) {
int time = initThreads[a].get();
if(time == -1) {
networking.killPlayer(a + 1);
timeout_tags.insert(a + 1);
result[a] = false;
rankings.push_back(a);
for(unsigned short b = 0; b < game_map.map_height; b++) for(unsigned short c = 0; c < game_map.map_width; c++) if(game_map.contents[b][c].owner == a + 1) game_map.contents[b][c].owner = 0;
}
else init_response_times[a] = time;
}
//Override player names with the provided ones if appropriate.
if(names_ != NULL) {
player_names.clear();
for(auto a = names_->begin(); a != names_->end(); a++) player_names.push_back(a->substr(0, 30));
}
const int maxTurnNumber = sqrt(game_map.map_width * game_map.map_height) * 10;
while(turn_number < maxTurnNumber && (std::count(result.begin(), result.end(), true) > 1 || (number_of_players == 1 && productive_squares_remaining > 0))) {
//Increment turn number:
turn_number++;
if(!quiet_output) std::cout << "Turn " << turn_number << "\n";
//Frame logic.
std::vector newResult = processNextFrame(result);
//Add to vector of players that should be dead.
std::vector newRankings;
for(unsigned char a = 0; a < number_of_players; a++) if(result[a] && !newResult[a]) {
newRankings.push_back(a);
}
//Sort newRankings by last territory count. If it's the same, use the territory integral instead to break that tie.
std::stable_sort(newRankings.begin(), newRankings.end(), [&](const unsigned int & u1, const unsigned int & u2) -> bool {
if(last_territory_count[u1] == last_territory_count[u2]) return full_territory_count[u1] < full_territory_count[u2];
return last_territory_count[u1] < last_territory_count[u2];
});
for(auto a = newRankings.begin(); a != newRankings.end(); a++) rankings.push_back(*a);
//Count productive squares remaining for Halite single-player game
productive_squares_remaining = 0;
for(unsigned short b = 0; b < game_map.map_height; b++) for(unsigned short c = 0; c < game_map.map_width; c++) if(game_map.contents[b][c].owner == 0 && game_map.contents[b][c].production > 0) productive_squares_remaining++;
result = newResult;
}
std::vector newRankings;
for(int a = 0; a < number_of_players; a++) if(result[a]) newRankings.push_back(a);
//Sort newRankings by last territory count. If it's the same, use the territory integral instead to break that tie.
std::stable_sort(newRankings.begin(), newRankings.end(), [&](const unsigned int & u1, const unsigned int & u2) -> bool {
if(last_territory_count[u1] == last_territory_count[u2]) return full_territory_count[u1] < full_territory_count[u2];
return last_territory_count[u1] < last_territory_count[u2];
});
for(auto a = newRankings.begin(); a != newRankings.end(); a++) rankings.push_back(*a);
std::reverse(rankings.begin(), rankings.end()); //Best player first rather than last.
GameStatistics stats;
int chunkSize = game_map.map_width * game_map.map_height / number_of_players;
for(unsigned char a = 0; a < number_of_players; a++) {
PlayerStatistics p;
p.tag = a + 1;
p.rank = std::distance(rankings.begin(), std::find(rankings.begin(), rankings.end(), a)) + 1;
// alive_frame_count counts frames, but the frames are 0-base indexed (at least in the visualizer), so everyone needs -1 to find the frame # where last_alive
// however, the first place player and 2nd place player always have the same reported alive_frame_count (not sure why)
// it turns out to make "last_frame_alive" match what is seen in replayer, we have to -2 from all but finishers who are alive in last frame of game who only need -1
p.last_frame_alive = alive_frame_count[a] - 2 + result[a];
p.average_territory_count = full_territory_count[a] / double(chunkSize * alive_frame_count[a]);
p.average_strength_count = full_strength_count[a] / double(chunkSize * alive_frame_count[a]);
p.average_production_count = alive_frame_count[a] > 1 ? full_production_count[a] / double(chunkSize * (alive_frame_count[a] - 1)) : 0; //For this, we want turns rather than frames.
p.still_percentage = full_cardinal_count[a] + full_still_count[a] > 0 ? full_still_count[a] / double(full_cardinal_count[a] + full_still_count[a]) : 0;
p.init_response_time = init_response_times[a];
p.average_frame_response_time = total_frame_response_times[a] / double(alive_frame_count[a]); //In milliseconds.
stats.player_statistics.push_back(p);
}
stats.timeout_tags = timeout_tags;
stats.timeout_log_filenames = std::vector(timeout_tags.size());
//Output gamefile. First try the replays folder; if that fails, just use the straight filename.
if (enabledReplay) {
stats.output_filename = replayDirectory + "Replays/" + std::to_string(id) + '-' + std::to_string(seed) + ".hlt";
try {
output(stats.output_filename);
}
catch(std::runtime_error & e) {
stats.output_filename = replayDirectory + std::to_string(id) + '-' + std::to_string(seed) + ".hlt";
output(stats.output_filename);
}
if(!quiet_output) std::cout << "Map seed was " << seed << std::endl << "Opening a file at " << stats.output_filename << std::endl;
else std::cout << stats.output_filename << ' ' << seed << std::endl;
}
//Output logs for players that timed out or errored.
int timeoutIndex = 0;
for(auto a = timeout_tags.begin(); a != timeout_tags.end(); a++) {
stats.timeout_log_filenames[timeoutIndex] = std::to_string(*a) + '-' + std::to_string(id) + ".log";
std::ofstream file(stats.timeout_log_filenames[timeoutIndex], std::ios_base::binary);
file << networking.player_logs[*a - 1];
file.flush();
file.close();
timeoutIndex++;
}
return stats;
}
std::string Halite::getName(unsigned char playerTag) {
return player_names[playerTag - 1];
}
Halite::~Halite() {
//Get rid of dynamically allocated memory:
for(int a = 0; a < number_of_players; a++) networking.killPlayer(a+1);
}
================================================
FILE: environment/core/Halite.hpp
================================================
#ifndef HALITE_H
#define HALITE_H
#include
#include
#include