123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274 |
- #!/usr/bin/ruby
- #`(if running under some shell) {
- eval 'exec /usr/bin/sidef $0 ${1+"$@"}'
- }
- # Author: Daniel "Trizen" Șuteu
- # License: GPLv3
- # Created on: 21 August 2012
- # Latest edit on: 10 November 2013
- # Translated to Sidef in 21 September 2014
- # Latest edit on: 16 November 2022
- # Website: https://github.com/trizen/asciiplanes
- # Find the planes' positions on a grid. (text-based game)
- var asciitable =
- try { require('Text::ASCIITable') }
- catch { STDERR.print("Can't load the 'Text::ASCIITable' Perl module...\n"); Sys.exit(2) }
- var ANSI =
- try { frequire('Term::ANSIColor') }
- catch { nil }
- ## Package variables
- var pkgname = 'asciiplanes'
- var version = 0.06
- ## Game variables
- var BOARD_SIZE = 8
- var PLANES_NUM = 3
- var parts = (['head'] + ['hit']*7)
- var plane_chars = ['$', '#', '@']
- var use_colors = defined(ANSI)
- var wrap_plane = false
- var hit_char = %q{O}
- var miss_char = %q{`}
- func print_usage {
- print <<"EOT"
- usage: #{__MAIN__} [options]
- main:
- --size=i : length side of the board (default: #{BOARD_SIZE})
- --planes=i : the total number of planes (default: #{PLANES_NUM})
- --wrap! : wrap the plane around the play board (default: #{wrap_plane})
- --hit=s : character used when a plane is hit (default: "#{hit_char}")
- --miss=s : character used when a plane is missed (default: "#{miss_char}")
- --colors! : use ANSI colors (requires Term::ANSIColor) (default: #{use_colors})
- help:
- --help : print this message and exit
- --version : print the version number and exit
- example:
- #{__MAIN__} --size=12 --planes=6 --hit='*'
- EOT
- Sys.exit
- }
- func print_version {
- print "#{pkgname} #{version}\n"
- Sys.exit
- }
- if (ARGV) {
- ARGV.getopt!(
- 'board-size|size=i' => \BOARD_SIZE,
- 'planes-num=i' => \PLANES_NUM,
- 'hit-char=s' => \hit_char,
- 'miss-char=s' => \miss_char,
- 'wrap!' => \wrap_plane,
- 'colors!' => \use_colors,
- 'help|h|?' => print_usage,
- 'version|v|V' => print_version,
- )
- }
- ## The play-board of the game, and some other arrays
- #---------------------------------------------------------------
- var play_board = BOARD_SIZE.of { [nil] * BOARD_SIZE }
- var info_board = BOARD_SIZE.of { [' '] * BOARD_SIZE }
- var letters = Hash()
- play_board.range.each { |i|
- static char = 'a'
- letters{char++} = i
- }
- #---------------------------------------------------------------
- func pointers(board, x, y, indices) {
- gather {
- [[0,0]] + indices -> each { |pair|
- pair.kind_of(Array) || next
- var (row, col) = (x + pair[0], y + pair[1])
- if (wrap_plane) {
- row %= BOARD_SIZE #=
- col %= BOARD_SIZE #=
- }
- row.is_between(0, BOARD_SIZE-1) || return []
- col.is_between(0, BOARD_SIZE-1) || return []
- take(\board[row][col])
- }
- }
- }
- func up(board, x, y) {
- pointers(board, x, y, [
- '[+0, +0]',
- [+1, -1], [+1, +0], [+1, +1],
- [+2, +0],
- [+3, -1], [+3, +0], [+3, +1],
- ])
- }
- func down(board, x, y) {
- pointers(board, x, y, [
- [-3, -1], [-3, +0], [-3, +1],
- [-2, +0],
- [-1, -1], [-1, +0], [-1, +1],
- '[+0, +0]',
- ])
- }
- func left(board, x, y) {
- pointers(board, x, y, [
- [-1, +1], [-1, +3],
- '[+0, +0]', [+0, +1], [+0, +2], [+0, +3],
- [+1, +1], [+1, +3],
- ])
- }
- func right(board, x, y) {
- pointers(board, x, y, [
- [-1, -3], [-1, -1],
- [+0, -3], [+0, -2], [+0, -1], '[+0, +0]',
- [+1, -3], [+1, -1],
- ])
- }
- func assign(change=false, plane=[], data=[]) {
- plane.len || return false
- change || (
- plane.each { |c|
- *c == nil || return false
- }
- )
- plane.range.each { |i|
- *plane[i] = data[i]
- }
- return true
- }
- func print_ascii_table {
- var table = asciitable.new(Hash(headingText => "#{pkgname} #{version}"))
- table.setCols(' ', (1..BOARD_SIZE)...)
- var char = 'a';
- info_board.each { |row|
- table.addRow([char++, row...])
- table.addRowLine()
- }
- var t = table.drawit
- if (defined(ANSI) && use_colors) {
- t.gsub!(hit_char, ANSI.colored(hit_char, 'bold red'))
- t.gsub!(miss_char, ANSI.colored(miss_char, 'yellow'))
- plane_chars.each {|c|
- t.gsub!(c, ANSI.colored(c, "bold green"))
- }
- }
- say t
- }
- var count = 0
- var max_tries = 1_000
- var directions = [up, down, left, right]
- while (count != PLANES_NUM) {
- var x = play_board.end.irand
- var y = play_board[0].end.irand
- var rand = directions.end.irand
- var code = directions[rand]
- if (--max_tries <= 0) {
- die "FATAL ERROR: try to increase the size of the grid (--size=x).\n"
- }
- assign(
- change: false,
- plane: code.call(play_board, x, y),
- data: parts.map {|c| "#{c}_#{rand}" },
- ) || next
- count++
- }
- ## MAIN
- var tries = 0
- var start_time = Time.new.sec
- print_ascii_table()
- while (count > 0) {
- var letter = letters.keys.rand
- var number = irand(1, BOARD_SIZE)
- say "=>> Your guess (e.g.: #{letter}#{number})"
- var input = (Sys.scanln("> ") \\ break -> lc)
- input ~~ ['q', 'quit'] && break
- var m = input.match(/^\h*([a-z]+)\D*([0-9]+)/) || next
- letters.has_key(m[0]) || next
- var x = letters{m[0]}
- var y = Num(m[1]).dec
- (y >= 0) && (y < BOARD_SIZE) || next
- var point = play_board[x][y]
- if (point == nil) {
- info_board[x][y] = miss_char
- }
- elsif (point.match(/^head_(\d)$/i)) { |m|
- var dir = Num(m[0])
- var item = plane_chars[(PLANES_NUM - count) % plane_chars.len]
- var code = directions[dir]
- [play_board, info_board].each { |board|
- assign(
- change: true,
- data: [item]*8,
- plane: code.call(board, x, y),
- ) || die "#{__MAIN__}: unexpected error!"
- }
- count--;
- }
- elsif (point ~~ /^hit_\d$/i) {
- info_board[x][y] = hit_char
- }
- tries++
- print_ascii_table()
- }
- printf("** Info: %d tries in %d seconds\n", tries, Time.new.sec - start_time)
- if (count == 0) {
- say "** Congratulations! All the planes are destroyed!"
- }
|