DEV Community staff staff

Posted on

Daily Challenge #125 - 23 Matches or More

There is a game called 23 Matches. In this game, there are 23 matches on the table. Each turn a player takes 1, 2 or 3 matches away. Player who takes the last match - loses. This will be a generalized version of the game. Here we have X matches and we can take up to Y matches away each turn.

Example: X = 13, Y = 4

There are X = 13 matches on table
Player 1 takes 1 match -> 12 left on table
Player 2 takes 4 matches -> 8 left on table
Player 1 takes 2 matches -> 6 left on table
Player 2 takes 3 matches -> 3 left on table
Player 1 takes 2 matches -> 1 left on table
Player 2 takes last match

Player 2 loses.

You're about to write a BOT to compete with my bot.

To do this - implement function createBot which accepts two arguments:

X - initial number of matches on table (20 <= X <= 1000)
Y - max number of matches to be taken away each turn (2 <= Y <= 19)
Your function must return an object of following structure:

//example bot

let myBot = {
   name: "Optional name as string",
   makeMove: matchesStillOnTable => matchesToTake

Challenger Bot

const randomBot = {
      name: "Random",
      makeMove: onTable => Math.floor(Math.random() * 3) + 1

Your bot will always start the game. The game is always winnable for your bot - there won't be any cheap tricks or edgy corner cases.

Good luck!

This challenge comes from tiriana on CodeWars. Thank you to CodeWars, who has licensed redistribution of this challenge under the 2-Clause BSD License!

Want to propose a challenge idea for a future post? Email with your suggestions!

Top comments (1)

craigmc08 profile image
Craig McIlwrath

This is my solution in Haskell. The "object" containing the function is pretty awkward in Haskell. It would probably be better to just use the makeMove function directly or partially applied.

Quick note: In my exploration of this game, it seems like if the matches remaining at the beginning of your turn is in a specific arithmetic sequence, then you have to rely on the opponent making a mistake. With my bot, this can only happen if the starting number of matches is in this sequence. If this happen, it just picks up as many matches as possible to lose as fast as possible (hence, "Pessimist Bot").

data Bot = Bot { getName :: String, getMakeMove :: Integer -> Integer }

makeMove :: Integer -> Integer -> Integer
makeMove l m
  | m == 1    = 1
  | m < l + 2 = m - 1
  | otherwise = let d = minimum [m - z | t <- [1..m], let z = (l + 1) * t + 1, z <= m]
                in  if d > l || d == 0
                      then l -- Give up, the only way to win is the opponent messes up
                      else d

createBot :: Integer -> Integer -> Bot
createBot n l = Bot "Pessimist Bot" $ makeMove l