Acrobot Acronym Game!

By Ratmatix on Jun 13, 2010

A few years ago, I played this acronym game with friends, but it was using an eggdrop bot. I really wanted to play it again, so I thought i'd write it from scratch as a mIRC script. :3 After much testing, seems to be running well! :)

Basic game flow is described in the "Game Timeline" comment block.

Instructions for playing are fairly clear, and !help describes all the commands implemented so far.

Custom settings (for timings, botname, channel name, etc) go into the acro.loadSettings alias.

It's still a work in progress, although the later things i'm wanting to do can't really be added here. I'm currently working on the bot creating and submitting its own acronym each round, pulling words out a dictionary according to some sentence structure, but it would be far too large to add as a snippet.

Enjoy!

If you've got any improvements (code or functionality) leave a comment!

~Ratmatix
PS: It's not entirely commented, but it will be within a few days. :3

; Acronym Game
; Author: ratmatix
; Email: ratmatix+hawkee [at] gmail (dot) com

; =============================================================================================
; Settings
; =============================================================================================

on *:load: {
  acro.loadSettings
}

on *:start: {
  acro.removeSettings
  acro.loadSettings
}

alias acro.loadSettings {
  ; Sets if the bot is active; if a game can be started
  set %ACROSETTING.active 1
  ; Bot name
  set %ACROSETTING.botname acrobot
  ; Name of channel in which the game can be played
  set %ACROSETTING.chan #acro
  ; Number of rounds
  set %ACROSETTING.rounds 5
  ; Time to wait for players to !join
  set %ACROSETTING.joinTime 30
  ; Time to wait for players to !submit acros
  set %ACROSETTING.submitTime 90
  ; Time to wait for players to !vote acros
  set %ACROSETTING.voteTime 30
  ; Weighted string for acronym
  set %ACROSETTING.weighted AAABBBCCCDDDEEEFFFGGGHHHIIIJJKKLLLMMMNNNOOOPPPQRRRSSSTTTUUUVVVWWXYYZ
}

alias -l acro.removeSettings {
  .timeracro.* off
  unset %ACRO.*
}

; =============================================================================================
; Game Timeline (with default timings)
; =============================================================================================
; !start
;  -> 30 seconds for players to join with !join
; startGame
; playRound x | x <- 1..10
;  -> maximum of 120 seconds per round (All phases are ended prematurely if all players submit or vote)
;      -> Bot generates and displays a string of random letters
;      -> 90 seconds for players to submit acros with !submit <acro>
;      -> Bot displays the submitted acronyms, anonymously 
;      -> 30 seconds for players to vote for acros with !vote <acroNum>
;      -> Bot displays round results
; endGame
;  -> Bot displays game results
; cake

; =============================================================================================
; Game aliases/identifiers (in order of game flow)
; =============================================================================================

on *:TEXT:!start*:%ACROSETTING.chan: {
  if ($me == %ACROSETTING.botname) {
    if (%ACROSETTING.active) {
      if ((!%ACRO.starting) && (!%ACRO.started)) {
        acro.loadSettings
        msg %ACROSETTING.chan Game of acro starting! 
        msg %ACROSETTING.chan Type 4!join to join within the next %ACROSETTING.joinTime seconds.
        unset %ACRO.*
        set -u $+ [ %ACROSETTING.joinTime ] %ACRO.starting 1
        .timerACRO.start 1 %ACROSETTING.joinTime acro.startGame
      }
      else {
        notice $nick A game has already started!
      }
    }
    else {
      msg %ACROSETTING.chan acrobot has been disabled. Probably for upgrades... Like laz0rs! Try again later :)
    }
  }
}

on *:TEXT:!join*:%ACROSETTING.chan: {
  if ($me == %ACROSETTING.botname) {
    if (%ACRO.starting) || (%ACRO.started) {
      if (!$acro.isPlayer($nick)) {
        acro.addPlayer $nick
        msg %ACROSETTING.chan 4 $+ $nick $+  has joined the game
      } 
      else {
        notice $nick You're already in the game!
      }
    }
    else {
      notice $nick No game to join. Type 4!start to start one.
    }
  }
}

; addPlayer <nick> adds that player to the current game
alias -l acro.addPlayer {
  set %ACRO.playerNames $addtok(%ACRO.playerNames, $1, 32)
  set %ACRO.playerPoints $instok(%ACRO.playerPoints, 0, $acro.numPlayers, 32)
  set %ACRO.playerVotes $instok(%ACRO.playerVotes, 0, $acro.numPlayers, 32)
  set %ACRO.playerVoted $instok(%ACRO.playerVoted, 0, $acro.numPlayers, 32)
}

alias -l acro.startGame {
  if ($acro.numPlayers > 0) {
    unset %ACRO.starting
    set %ACRO.started 1
    msg %ACROSETTING.chan Game starting with players:4 %ACRO.playerNames

    set %ACRO.roundNum 0
    acro.playRound
  }
  else {
    acro.stop Nobody joined 4:(
  }
}

alias -l acro.playRound {
  inc %ACRO.roundNum
  set %ACRO.acro $acro.generateAcro
  set %ACRO.submitting 1
  msg %ACROSETTING.chan Acronym for round %ACRO.roundNum of %ACROSETTING.rounds $+ :4 %ACRO.acro
  msg %ACROSETTING.chan Submit acronyms to the bot with: 4/notice %ACROSETTING.botname submit <acronym> within the next %ACROSETTING.submitTime seconds

  acro.resetRound
  .timerACRO.beginVoting 1 %ACROSETTING.submitTime acro.beginVoting
}

; $generateAcro returns a random acronym of length 3 to 7
alias -l acro.generateAcro {
  var %ACRO.c = 0

  var %ACRO.length = $rand(3,7)
  while (%ACRO.c < %ACRO.length) {
    var %ACRO.d =  %ACRO.d $mid(%ACROSETTING.weighted, $rand(1,$len(%ACROSETTING.weighted)), 1)
    inc %ACRO.c
  }
  return %ACRO.d
}

alias -l acro.resetRound {
  var %ACRO.b 1
  unset %ACRO.playerVotes
  unset %ACRO.playerVoted
  unset %ACRO.playerAcros
  unset %ACRO.playerAcrod
  while (%ACRO.b <= $acro.numPlayers) {
    set %ACRO.playerVotes $instok(%ACRO.playerVotes, 0, %ACRO.b, 32)
    set %ACRO.playerVoted $instok(%ACRO.playerVoted, 0, %ACRO.b, 32)
    inc %ACRO.b
  }
}

on *:NOTICE:submit*:*: {
  if ($me == %ACROSETTING.botname) {
    if ($acro.isPlayer($nick)) {
      if (!$acro.hasAcrod($nick)) {
        if ($acro.checkAcro($strip($2-))) {
          acro.addAcro $acro.playerNum($nick) $strip($2-)
          notice $nick Acro submitted successfully.
          if ($acro.allSubmitted) {
            .timerACRO.beginVoting off
            ;msg %ACROSETTING.chan All players have submitted an acronym!
            acro.beginVoting
          }
        }
        else {
          notice $nick Not a valid acro!
        }
      } 
      else {
        notice $nick You've already submitted an acro!
      }
    }
    else {
      notice $nick You're not playing this game!
    }
  }
}

alias -l acro.hasAcrod {
  return $istok(%ACRO.playerAcrod, $acro.playerNum($1), 32)
}

; $checkAcro(<player submitted acro>) returns true if it is a valid acro for that round
alias -l acro.checkAcro {
  var %ACRO.e $numtok(%ACRO.acro, 32)
  var %ACRO.f $numtok($1, 32)
  if (%ACRO.e != %ACRO.f) {
    return $false
  }
  while (%ACRO.e >= 1) {
    if ($left($gettok($1-, %ACRO.e, 32), 1) != $left($gettok(%ACRO.acro, %ACRO.e, 32), 1)) {
      return $false
    }
    dec %ACRO.e
  }
  return $true
}

; addAcro <player num> <acro>
alias -l acro.addAcro {
  set %ACRO.playerAcrod $instok(%ACRO.playerAcrod, $1, $calc($numtok(%ACRO.playerAcrod, 32) + 1), 32)
  set %ACRO.playerAcros $instok(%ACRO.playerAcros, $2-, $calc($numtok(%ACRO.playerAcros, 96) + 1), 96)
}

alias -l acro.allSubmitted {
  if ($numtok(%ACRO.playerAcrod, 32) == $ACRO.numPlayers) {
    return $true
  }
  else {
    return $false
  }
}

alias -l acro.beginVoting {
  unset %ACRO.submitting
  set %ACRO.voting 1
  msg %ACROSETTING.chan Time to 4start voting!
  msg %ACROSETTING.chan Vote for the best acro with 4/notice %ACROSETTING.botname vote <acro number> within the next %ACROSETTING.voteTime seconds
  msg %ACROSETTING.chan Acronyms in order of submission:
  var %ACRO.g 1

  while (%ACRO.g <= $numtok(%acro.playerAcrod, 32)) {
    msg %ACROSETTING.chan [4 $+ %ACRO.g $+ ] $gettok(%ACRO.playerAcros, %ACRO.g, 96)
    inc %ACRO.g
  }

  .timerACRO.endRound 1 %ACROSETTING.voteTime acro.endRound
}

; players vote by sending a notice to the bot. The voting notice should be formed like this: !vote <acroNum>
on *:NOTICE:vote*:*: {
  if ($me == %ACROSETTING.botname) {
    if (%ACRO.voting) {
      if ($acro.isPlayer($nick)) {
        if (!$acro.hasVoted($nick)) {
          if ($acro.checkAcroNum($2)) {
            $acro.incVote($nick, $2)
            notice $nick Vote submitted successfully.
            if ($acro.allVoted) {
              .timerACRO.endRound off
              ;msg %ACROSETTING.chan All players have voted!
              acro.endRound
            }
          }
          else {
            notice $nick That's not a valid acro number!
          }
        }
        else {
          notice $nick You've already voted this round!
        }
      } 
      else {
        notice $nick You're not playing this game!
      }
    }
    else {
      notice $nick It's not time to vote yet!
    }
  }
}

alias -l acro.hasVoted {
  return $gettok(%ACRO.playerVoted, $acro.playerNum($1), 32)
}

; $checkAcroNum(<acroNum>) returns true if that acro number is valid. i.e. Was submitted.
alias -l acro.checkAcroNum {
  var %ACRO.g $numtok(%ACRO.playerAcros, 96)
  return $iif(($1 > 0) && ($1 <= $numtok(%ACRO.playerAcros, 32)), $true, $false)
}

; $incVote(<voting player name>, <acroNum>) increments the player's vote score
alias -l acro.incVote {
  var %ACRO.acroOwner $gettok(%ACRO.playerAcrod, $2, 32)
  set %ACRO.playerVoted $puttok(%ACRO.playerVoted, 1, $acro.playerNum($1), 32)
  set %ACRO.playerVotes $puttok(%ACRO.playerVotes, $calc($gettok(%ACRO.playerVotes, %ACRO.acroOwner, 32) + 1), %ACRO.acroOwner, 32)
}

alias -l acro.allVoted {
  var %ACRO.m 1
  while (%ACRO.m <= $acro.numPlayers) {
    if (!$acro.hasVoted($acro.playerName(%ACRO.m))) {
      return $false
    }
    inc %ACRO.m
  }
  return $true
}

alias -l acro.endRound {
  unset %ACRO.voting
  var %ACRO.h 1
  var %ACRO.mostVotes 0
  msg %ACROSETTING.chan 4Results for round %ACRO.roundNum $+:

  while (%ACRO.h <= $numtok(%ACRO.playerAcros, 96)) {
    var %ACRO.acroOwner $gettok(%ACRO.playerAcrod, %ACRO.h, 32)
    msg %ACROSETTING.chan [4 $+ %ACRO.h $+ ] $gettok(%ACRO.playerAcros, %ACRO.h, 96) - $iif($acro.numVotes(%ACRO.acroOwner) == 1, 1 vote, $ifmatch votes)
    if ($acro.numVotes(%ACRO.acroOwner) > %ACRO.mostVotes) {
      var %ACRO.mostVotes $ifmatch
    }
    inc %ACRO.h
  }

  if (%ACRO.mostVotes != 0) {
    acro.incPoint %ACRO.mostVotes
  }
  else {
    msg %ACROSETTING.chan 4Nobody voted. :'(
  }

  if (%ACRO.roundNum < %ACROSETTING.rounds) {
    acro.playRound
  }
  else {
    acro.endgame
  }
}

; $numVotes(<player Num>) returns the number of votes that acro received
alias -l acro.numVotes {
  return $gettok(%ACRO.playerVotes, $1, 32)
}

; incPoint <points> - finds the acros with that many votes and awards their owners with 1 point
alias -l acro.incPoint {
  var %ACRO.j 1

  msg %ACROSETTING.chan Round Winner(s):

  while (%ACRO.j <= $acro.numPlayers) {
    if ($gettok(%ACRO.playerVotes, %ACRO.j, 32) == $1) {
      msg %ACROSETTING.chan [4 $+ %ACRO.j $+ ] belonged to4 $acro.playerName(%ACRO.j)
      set %ACRO.playerPoints $puttok(%ACRO.playerPoints, $calc($gettok(%ACRO.playerPoints, %ACRO.j, 32) + 1), %ACRO.j, 32)
    }
    inc %ACRO.j
  }
}

alias -l acro.endgame {
  msg %ACROSETTING.chan Game finished!
  msg %ACROSETTING.chan Final Scores:
  var %ACRO.i 1
  var %ACRO.mostPoints 0

  while (%ACRO.i <= $acro.numPlayers) {
    msg %ACROSETTING.chan $acro.playerName(%ACRO.i) - $iif($acro.numPoints(%ACRO.i) == 1, 1 point, $ifmatch points)
    if ($acro.numPoints(%ACRO.i) > %ACRO.mostPoints) {
      var %ACRO.mostPoints $ifmatch
    }
    inc %ACRO.i
  }

  acro.winners %ACRO.mostPoints

  acro.removeSettings
}

alias -l acro.numPoints {
  return $gettok(%ACRO.playerPoints, $1, 32)
}

; winners <points> - finds the players with that many points and call them the winner(s)! :D
alias -l acro.winners {
  var %ACRO.k 1

  while (%ACRO.k <= $acro.numPlayers) {
    if ($gettok(%ACRO.playerPoints, %ACRO.k, 32) == $1) {
      var %ACRO.winners %ACRO.winners $acro.playerName(%ACRO.k)
    }
    inc %ACRO.k
  }
  msg %ACROSETTING.chan The $iif($numtok(%ACRO.winners, 32) == 1, winner is4 %ACRO.winners , winners are:4 %ACRO.winners )
}

; =============================================================================================
; Utility identifiers or events
; =============================================================================================

; $isPlayer(<name>) returns $true if <name> is a player in the current game, else $false.
alias -l acro.isPlayer {
  return $istok(%ACRO.playerNames, $1, 32)
}

; $playerNum(<name>) returns the player's player number. This means they are the nth token in playerNames, playerPoints
alias -l acro.playerNum {
  return $findtok(%ACRO.playerNames, $1, 32)
}

; $playerName(<player number>) returns the player name who is the nth player number
alias -l acro.playerName {
  return $gettok(%ACRO.playerNames, $1, 32)
}

; $numPlayers returns the number of players who joined this game
alias -l acro.numPlayers {
  return $numtok(%ACRO.playerNames, 32)
}

on *:TEXT:!stop:%ACROSETTING.chan: {
  if ($me == %ACROSETTING.botname) {
    if ((%ACRO.starting) || (%ACRO.started)) {
      if ($acro.isPlayer($nick)) {
        acro.stop Game 4stopped! :(
      }
      else {
        notice $nick Only players can stop the game!
      }
    }
    else {
      notice $nick There isn't a game to stop!
    }
  }
}

on *:TEXT:!leave:%ACROSETTING.chan: {
  if ($me == %ACROSETTING.botname) {
    msg %ACROSETTING.chan 4 $+ $nick has left the game.
    acro.removePlayer $nick
  }
}

on *:TEXT:!forcestart:%ACROSETTING.chan: {
  if ($me == %ACROSETTING.botname) {
    if (%ACRO.starting) {
      if ($acro.isPlayer($nick)) {
        .timerACRO.start off
        acro.startGame
      }
      else {
        notice $nick Only players can !forcestart a game
      }
    } 
    else {
      notice $nick !forcestart can only be used when waiting for players to join
    }
  }
}

on *:TEXT:!kick*:%ACROSETTING.chan: {
  if ($me == %ACROSETTING.botname) {
    if (%ACRO.starting) || (%ACRO.started) {
      if ($isPlayer($2)) {
        if ($nick isop $chan) {
          msg %ACROSETTING.chan 4 $+ $2 has been kicked from the game.
          acro.removePlayer $2
        } 
        else {
          notice $nick !kick can only be used by OPs. OPs have been notified.
          notice %ACROSETTING.botname $nick wants to kick $2
        }
      }
      else {
        notice $nick You can only kick players from the current game!
      }
    }
    else {
      notice $nick You can only kick people if there is a game in play!
    }
  }
}

; removePlayer <nick> removes the player from the game.
alias -l acro.removePlayer {
  var %ACRO.m $acro.playerNum($1)

  set %ACRO.playerNames $deltok(%ACRO.playerNames, %ACRO.m, 32)
  set %ACRO.playerPoints $deltok(%ACRO.playerPoints, %ACRO.m, 32)
  set %ACRO.playerVotes $deltok(%ACRO.playerVotes, %ACRO.m, 32)
  set %ACRO.playerVoted $deltok(%ACRO.playerVoted, %ACRO.m, 32)
  set %ACRO.playerAcros $deltok(%ACRO.playerAcros, %ACRO.m, $asc(`))
  set %ACRO.playerAcrod $deltok(%ACRO.playerAcrod, %ACRO.m, 32)

  if ($acro.numPlayers == 0) && (%acro.started) {
    acro.stop 4Game stopped due to lack of players :(
  }
}

; stop <text to be displayed>
alias -l acro.stop {
  msg %ACROSETTING.chan $1-
  acro.removeSettings
}

on *:JOIN:%ACROSETTING.chan: {
  if ($me == %ACROSETTING.botname) {
    if (%ACRO.starting) {
      msg %ACROSETTING.chan Hey $nick $+ ! A game is starting now; type 4!join to join!
    }
    else if (%ACRO.started) {
      msg %ACROSETTING.chan Hey $nick $+ ! A game has started, but you can still join with 4!join
    }
  }
}

on *:TEXT:!help:%ACROSETTING.chan: {
  if ($me == %ACROSETTING.botname) {
    notice $nick !start to begin a game
    notice $nick !join to join a started game
    notice $nick !forcestart to force a game to start if it is still in the joining phase
    notice $nick !leave to leave a game you are currently playing
    notice $nick !kick to kick a player from the current game. Can only be used by OPs.
    notice $nick To submit an acronym, send a notice to the bot: /notice %ACROSETTING.botname submit <acronym>
    notice $nick To vote for an acronym, send a notice to the bot: /notice %ACROSETTING.botname vote <nubmer>
  }
}

Comments

Sign in to comment.
Maghion   -  Oct 05, 2010

not working for me..

 Respond  
Ratmatix   -  Jun 17, 2010

Oh right, yeah. Thanks!

 Respond  
Bielie   -  Jun 17, 2010

Looks good but the !help function should be with timers. And in 2-3 notices....

Like this:

on *:TEXT:!help:%ACROSETTING.chan: {
  if ($me == %ACROSETTING.botname) {
    notice $nick !start to begin a game. || !join to join a started game. || !forcestart to force a game to start if it is still in the joining phase. || !leave to leave a game you are currently playing. ||
    .timer 1 2 notice $nick !kick to kick a player from the current game. (Can only be used by OPs.) | To submit an acronym, send a notice to the bot: /notice %ACROSETTING.botname submit <acronym> || To vote for an acronym, send a notice to the bot: /notice %ACROSETTING.botname vote <nubmer> ||
  }
}

Its clearer if you use 2 colors aswell.

 Respond  
Are you sure you want to unfollow this person?
Are you sure you want to delete this?
Click "Unsubscribe" to stop receiving notices pertaining to this post.
Click "Subscribe" to resume notices pertaining to this post.