# Design Question / Challenge - From SmartPy Contract to Yes, It's Just Ruby - Let's Play Nim (The Ancient Math Subtraction Game)

(Gerald Bauer) #1

Hello,

Here's another design question / challenge:

Turn the SmartPy contract that lets you play Nim (the ancient math
subtraction game) into a "Yes, It's Just Ruby" version. Example:

import smartpy as sp

class NimGame(sp.Contract):
def __init__(self, size, bound = None, winnerIsLast = False):
self.bound = bound
self.winnerIsLast = winnerIsLast
self.init(deck = sp.range(1, size + 1),
size = size,
nextPlayer = 1,
claimed = False,
winner = 0)

@sp.message
def remove(self, data, params):
cell = params.cell
k = params.k
sp.check(0 <= cell)
sp.check(cell < data.size)
sp.check(1 <= k)
if self.bound is not None:
sp.check(k <= self.bound)
sp.check(k <= data.deck[cell])
sp.set(data.deck[cell], data.deck[cell] - k)
sp.set(data.nextPlayer, 3 - data.nextPlayer)

@sp.message
def claim(self, data, params):
sp.check(sp.sum(data.deck) == 0)
sp.set(data.claimed, True)
if self.winnerIsLast:
sp.set(data.winner, 3 - data.nextPlayer)
else:
sp.set(data.winner, data.nextPlayer)

What's SmartPy?

The SmartPy library for programming contracts with Python
(see Introducing SmartPy [1]) compiles to SmartML and onto Michelson bytecode.

What's Nim?

Nim is a mathematical game of strategy in which two players take turns
removing objects from distinct heaps. On each turn, a player must remove
at least one object, and may remove any number of objects provided
they all come from the same heap. The goal of the game is to avoid
taking the last object.

(Source: Nim @ Wikipedia [2])

And here's my (second) take [3] with an alternate
"meta" parameterized contract template / factory
and yes, it's ruby:

···

####################################
# Nim Game Contract Template
#
# Parameter Options:
# - bound (default: nil)
# - winner_is_last (default: false)

sig [Integer],
def setup( size )
@deck = Array( 1...size+1 ) ## e.g. [1,2,3,4,...]
@size = size
@next_player = 1
@claimed = false
@winner = 0
end

# cell - representing a cell from an array
# k - a quantity to remove from this cell
sig [Integer, Integer],
def remove( cell, k )
assert 0 <= cell
assert cell < @size
assert 1 <= k
if \$DEFINED[:bound]
assert k <= \$PARA[:bound]
end
assert k <= @deck[cell]

@deck[cell] -= k
@nextPlayer = 3 - @nextPlayer ## toggles between 1|2
end

def claim
assert @deck.sum == 0

@claimed = true
if \$TRUE[:winner_is_last]
@winner = 3 - @nextPlayer
else
@winner = @nextPlayer
end
end

Can you do better? Yes, you can. Post your code snippets, ideas,