diff --git a/CMakeLists.txt b/CMakeLists.txt
new file mode 100644
index 0000000000000000000000000000000000000000..8cb3c6082d8004c30a687f1214c70ec21b730bb5
--- /dev/null
+++ b/CMakeLists.txt
@@ -0,0 +1,201 @@
+cmake_minimum_required(VERSION 2.8.3)
+project(socrates_workshop)
+
+## Compile as C++11, supported in ROS Kinetic and newer
+# add_compile_options(-std=c++11)
+
+## Find catkin macros and libraries
+## if COMPONENTS list like find_package(catkin REQUIRED COMPONENTS xyz)
+## is used, also find other catkin packages
+find_package(catkin REQUIRED COMPONENTS
+  roscpp
+  rospy
+  std_msgs
+  message_generation
+)
+
+## System dependencies are found with CMake's conventions
+# find_package(Boost REQUIRED COMPONENTS system)
+
+
+## Uncomment this if the package has a setup.py. This macro ensures
+## modules and global scripts declared therein get installed
+## See http://ros.org/doc/api/catkin/html/user_guide/setup_dot_py.html
+# catkin_python_setup()
+
+################################################
+## Declare ROS messages, services and actions ##
+################################################
+
+## To declare and build messages, services or actions from within this
+## package, follow these steps:
+## * Let MSG_DEP_SET be the set of packages whose message types you use in
+##   your messages/services/actions (e.g. std_msgs, actionlib_msgs, ...).
+## * In the file package.xml:
+##   * add a build_depend tag for "message_generation"
+##   * add a build_depend and a run_depend tag for each package in MSG_DEP_SET
+##   * If MSG_DEP_SET isn't empty the following dependency has been pulled in
+##     but can be declared for certainty nonetheless:
+##     * add a run_depend tag for "message_runtime"
+## * In this file (CMakeLists.txt):
+##   * add "message_generation" and every package in MSG_DEP_SET to
+##     find_package(catkin REQUIRED COMPONENTS ...)
+##   * add "message_runtime" and every package in MSG_DEP_SET to
+##     catkin_package(CATKIN_DEPENDS ...)
+##   * uncomment the add_*_files sections below as needed
+##     and list every .msg/.srv/.action file to be processed
+##   * uncomment the generate_messages entry below
+##   * add every package in MSG_DEP_SET to generate_messages(DEPENDENCIES ...)
+
+## Generate messages in the 'msg' folder
+add_message_files(
+#   FILES
+#   Message1.msg
+#   Message2.msg
+)
+
+## Generate services in the 'srv' folder
+add_service_files(
+  FILES
+  MiniMax.srv
+  IntInt.srv
+  Board.srv
+)
+
+## Generate actions in the 'action' folder
+# add_action_files(
+#   FILES
+#   Action1.action
+#   Action2.action
+# )
+
+## Generate added messages and services with any dependencies listed here
+generate_messages(
+  DEPENDENCIES
+  std_msgs
+)
+
+################################################
+## Declare ROS dynamic reconfigure parameters ##
+################################################
+
+## To declare and build dynamic reconfigure parameters within this
+## package, follow these steps:
+## * In the file package.xml:
+##   * add a build_depend and a run_depend tag for "dynamic_reconfigure"
+## * In this file (CMakeLists.txt):
+##   * add "dynamic_reconfigure" to
+##     find_package(catkin REQUIRED COMPONENTS ...)
+##   * uncomment the "generate_dynamic_reconfigure_options" section below
+##     and list every .cfg file to be processed
+
+## Generate dynamic reconfigure parameters in the 'cfg' folder
+# generate_dynamic_reconfigure_options(
+#   cfg/DynReconf1.cfg
+#   cfg/DynReconf2.cfg
+# )
+
+###################################
+## catkin specific configuration ##
+###################################
+## The catkin_package macro generates cmake config files for your package
+## Declare things to be passed to dependent projects
+## INCLUDE_DIRS: uncomment this if you package contains header files
+## LIBRARIES: libraries you create in this project that dependent projects also need
+## CATKIN_DEPENDS: catkin_packages dependent projects also need
+## DEPENDS: system dependencies of this project that dependent projects also need
+catkin_package(
+#  INCLUDE_DIRS include
+#  LIBRARIES socrates_workshop
+ CATKIN_DEPENDS roscpp rospy std_msgs message_runtime
+#  DEPENDS system_lib
+)
+
+###########
+## Build ##
+###########
+
+## Specify additional locations of header files
+## Your package locations should be listed before other locations
+include_directories(
+# include
+  ${catkin_INCLUDE_DIRS}
+)
+
+## Declare a C++ library
+# add_library(${PROJECT_NAME}
+#   src/${PROJECT_NAME}/socrates_workshop.cpp
+# )
+
+## Add cmake target dependencies of the library
+## as an example, code may need to be generated before libraries
+## either from message generation or dynamic reconfigure
+# add_dependencies(${PROJECT_NAME} ${${PROJECT_NAME}_EXPORTED_TARGETS} ${catkin_EXPORTED_TARGETS})
+
+## Declare a C++ executable
+## With catkin_make all packages are built within a single CMake context
+## The recommended prefix ensures that target names across packages don't collide
+# add_executable(${PROJECT_NAME}_node src/socrates_workshop_node.cpp)
+
+## Rename C++ executable without prefix
+## The above recommended prefix causes long target names, the following renames the
+## target back to the shorter version for ease of user use
+## e.g. "rosrun someones_pkg node" instead of "rosrun someones_pkg someones_pkg_node"
+# set_target_properties(${PROJECT_NAME}_node PROPERTIES OUTPUT_NAME node PREFIX "")
+
+## Add cmake target dependencies of the executable
+## same as for the library above
+# add_dependencies(${PROJECT_NAME}_node ${${PROJECT_NAME}_EXPORTED_TARGETS} ${catkin_EXPORTED_TARGETS})
+
+## Specify libraries to link a library or executable target against
+# target_link_libraries(${PROJECT_NAME}_node
+#   ${catkin_LIBRARIES}
+# )
+
+#############
+## Install ##
+#############
+
+# all install targets should use catkin DESTINATION variables
+# See http://ros.org/doc/api/catkin/html/adv_user_guide/variables.html
+
+## Mark executable scripts (Python etc.) for installation
+## in contrast to setup.py, you can choose the destination
+# install(PROGRAMS
+#   scripts/my_python_script
+#   DESTINATION ${CATKIN_PACKAGE_BIN_DESTINATION}
+# )
+
+## Mark executables and/or libraries for installation
+# install(TARGETS ${PROJECT_NAME} ${PROJECT_NAME}_node
+#   ARCHIVE DESTINATION ${CATKIN_PACKAGE_LIB_DESTINATION}
+#   LIBRARY DESTINATION ${CATKIN_PACKAGE_LIB_DESTINATION}
+#   RUNTIME DESTINATION ${CATKIN_PACKAGE_BIN_DESTINATION}
+# )
+
+## Mark cpp header files for installation
+# install(DIRECTORY include/${PROJECT_NAME}/
+#   DESTINATION ${CATKIN_PACKAGE_INCLUDE_DESTINATION}
+#   FILES_MATCHING PATTERN "*.h"
+#   PATTERN ".svn" EXCLUDE
+# )
+
+## Mark other files for installation (e.g. launch and bag files, etc.)
+# install(FILES
+#   # myfile1
+#   # myfile2
+#   DESTINATION ${CATKIN_PACKAGE_SHARE_DESTINATION}
+# )
+
+#############
+## Testing ##
+#############
+
+## Add gtest based cpp test target and link libraries
+# catkin_add_gtest(${PROJECT_NAME}-test test/test_socrates_workshop.cpp)
+# if(TARGET ${PROJECT_NAME}-test)
+#   target_link_libraries(${PROJECT_NAME}-test ${PROJECT_NAME})
+# endif()
+
+## Add folders to be run by python nosetests
+# catkin_add_nosetests(test)
diff --git a/launch/tic_tac_toe.launch b/launch/tic_tac_toe.launch
new file mode 100644
index 0000000000000000000000000000000000000000..a80850177a54289be7dcb53b5cd7c7ac5e2ad39d
--- /dev/null
+++ b/launch/tic_tac_toe.launch
@@ -0,0 +1,27 @@
+<launch>
+	<param name="application_name"			value="tic_tac_toe" 			type="string" />
+	<param name="topic_minimax_service" 		value="call_minimax" 			type="string" />	
+	<param name="topic_perform_robot_action" 	value="perform_action" 			type="string" />
+	<param name="topic_difficulty" 			value="set_difficulty" 				type="string" />
+	<param name="topic_ask_help" 				value="help_user" 				type="string" />
+	<param name="topic_board_state" 			value="board_state" 			type="string" />
+	<param name="topic_gripper_callback" 		value="gripper_action_callback" 	type="string" />
+	<param name="topic_gripper_action" 		value="gripper_action" 			type="string" />
+
+	<param name="param_difficulty" 			value="1" 					type="int" />
+	<param name="param_difficulty_min" 		value="1" 					type="int" />
+	<param name="param_difficulty_max" 		value="4" 					type="int" />
+
+	<param name="param_human_player_id" 		value="1" 					type="int" />
+	<param name="param_ai_player_id" 			value="-1" 					type="int" />
+
+	<node name="node_minimax_server" 			pkg="socrates_workshop" 			type="node_minimax.py" />
+	<node name="node_main" 					pkg="socrates_workshop" 			type="node_main.py" />
+	<node name="node_difficulty" 				pkg="socrates_workshop" 			type="node_difficulty.py" />
+	<node name="node_human_helper" 			pkg="socrates_workshop" 			type="node_human_helper.py" />
+</launch>
+
+
+<!--
+	<param name="" value="" type="" />
+-->
diff --git a/package.xml b/package.xml
new file mode 100644
index 0000000000000000000000000000000000000000..980d2d6049df28dfd1917856dbb911099601064f
--- /dev/null
+++ b/package.xml
@@ -0,0 +1,66 @@
+<?xml version="1.0"?>
+<package>
+  <name>socrates_workshop</name>
+  <version>0.0.2</version>
+  <description>The socrates_workshop package</description>
+
+  <!-- One maintainer tag required, multiple allowed, one person per tag -->
+  <!-- Example:  -->
+  <!-- <maintainer email="jane.doe@example.com">Jane Doe</maintainer> -->
+  <maintainer email="michelep@cs.umu.se">michele</maintainer>
+
+
+  <!-- One license tag required, multiple allowed, one license per tag -->
+  <!-- Commonly used license strings: -->
+  <!--   BSD, MIT, Boost Software License, GPLv2, GPLv3, LGPLv2.1, LGPLv3 -->
+  <license>TODO</license>
+
+
+  <!-- Url tags are optional, but multiple are allowed, one per tag -->
+  <!-- Optional attribute type can be: website, bugtracker, or repository -->
+  <!-- Example: -->
+  <!-- <url type="website">http://wiki.ros.org/socrates_workshop</url> -->
+
+
+  <!-- Author tags are optional, multiple are allowed, one per tag -->
+  <!-- Authors do not have to be maintainers, but could be -->
+  <!-- Example: -->
+  <!-- <author email="jane.doe@example.com">Jane Doe</author> -->
+
+
+  <!-- The *_depend tags are used to specify dependencies -->
+  <!-- Dependencies can be catkin packages or system dependencies -->
+  <!-- Examples: -->
+  <!-- Use build_depend for packages you need at compile time: -->
+  <!--   <build_depend>message_generation</build_depend> -->
+  <!-- Use buildtool_depend for build tool packages: -->
+  <!--   <buildtool_depend>catkin</buildtool_depend> -->
+  <!-- Use run_depend for packages you need at runtime: -->
+  <!--   <run_depend>message_runtime</run_depend> -->
+  <!-- Use test_depend for packages you need only for testing: -->
+  <!--   <test_depend>gtest</test_depend> -->
+  <buildtool_depend>catkin</buildtool_depend>
+  <build_depend>roscpp</build_depend>
+  <build_depend>rospy</build_depend>
+  <build_depend>std_msgs</build_depend>
+  <build_depend>message_generation</build_depend>
+
+  <build_depend>sensor_msgs</build_depend>
+  <build_depend>opencv2</build_depend>
+  <build_depend>cv_bridge</build_depend>
+
+  <run_depend>roscpp</run_depend>
+  <run_depend>rospy</run_depend>
+  <run_depend>std_msgs</run_depend>
+  <run_depend>message_runtime</run_depend>
+
+  <run_depend>sensor_msgs</run_depend>
+  <run_depend>opencv2</run_depend>
+  <run_depend>cv_bridge</run_depend>
+
+  <!-- The export tag contains other, unspecified, tags -->
+  <export>
+    <!-- Other tools can request additional information be placed here -->
+
+  </export>
+</package>
diff --git a/scripts/node_difficulty.py b/scripts/node_difficulty.py
new file mode 100755
index 0000000000000000000000000000000000000000..a59f7eb23e0500166b733a1f75993ec4d5eacbe7
--- /dev/null
+++ b/scripts/node_difficulty.py
@@ -0,0 +1,46 @@
+#!/usr/bin/env python
+import rospy
+import tic_tac_toe_common as ttt
+
+from std_msgs.msg import Int16
+from socrates_workshop.srv import *
+
+NODE_NAME = "node_difficulty"
+
+
+PARAM_DIFFICULTY = "param_difficulty"
+PARAM_DIFFICULTY_MIN = "param_difficulty_min"
+PARAM_DIFFICULTY_MAX = "param_difficulty_max"
+
+TOPIC_DIFFICULTY = "topic_difficulty"
+
+
+def setCurrentDifficulty(value):
+
+	min_diff = rospy.get_param(PARAM_DIFFICULTY_MIN)
+	max_diff = rospy.get_param(PARAM_DIFFICULTY_MAX)
+	
+	value = max(min_diff, min(value, max_diff))	
+
+	rospy.set_param(PARAM_DIFFICULTY, value)
+	return value
+
+def difficultyCallback(msg):
+	value = msg.data
+
+	value = setCurrentDifficulty(value)
+
+	return IntIntResponse(value)
+    
+def init_this_node():
+
+	rospy.init_node(NODE_NAME, anonymous=True)
+	
+
+	s = rospy.Service(ttt.concatTopicName(TOPIC_DIFFICULTY), IntInt, difficultyCallback)
+	
+
+	rospy.spin()
+
+if __name__ == '__main__':
+    init_this_node()
diff --git a/scripts/node_human_helper.py b/scripts/node_human_helper.py
new file mode 100755
index 0000000000000000000000000000000000000000..81e612ce3d954fc1039c8c2926f9668d32a63dcd
--- /dev/null
+++ b/scripts/node_human_helper.py
@@ -0,0 +1,89 @@
+#!/usr/bin/env python
+import rospy
+import tic_tac_toe_common as ttt
+from std_msgs.msg import *
+
+from socrates_workshop.srv import MiniMax, Board, IntInt
+
+NODE_NAME = "node_main"
+
+
+TOPIC_ASK_HELP		 	= "topic_ask_help"
+TOPIC_BOARD_STATE	 	= "topic_board_state"
+TOPIC_MINIMAX		 	= "topic_minimax_service"
+TOPIC_DIFFICULTY 		= "topic_difficulty"
+
+TOPIC_ACTION_CALLBACK	 = "topic_gripper_callback"
+
+
+this = sys.modules[__name__]
+
+this.board_service_proxy 	= None
+this.minimax_service_proxy 	= None
+this.gripper_subscriber		= None
+this.difficulty_service_proxy = None
+
+
+
+def helpUser(nextAction, board):
+	rospy.loginfo("I suggest action %s for board %s", nextAction, board)
+
+def helpCallback(msg):
+	id_human = ttt.getUserId()
+	id_ai = ttt.getAiId()
+
+	msg_board = this.board_service_proxy(id_human, id_ai)
+
+	depth = 10
+	msg_action = this.minimax_service_proxy(msg_board.board, depth, id_human, id_ai)
+
+	helpUser(msg_action.action, msg_board.board)
+
+
+"""
+Callback function for the gripper movement
+Depending of current difficulty we execute different routines
+"""
+def callbackGripperActionExecuted(msg):
+	success = msg.data
+
+	# We query the current difficulty level
+	msg_difficulty = this.difficulty_service_proxy(0)
+	difficulty = msg_difficulty.data
+
+	if difficulty == 1:
+		helpCallback(None)
+
+	if difficulty == 4:
+		# countdown
+		pass
+	
+    
+def init_this_node():
+
+	rospy.init_node(NODE_NAME, anonymous=True)
+
+	topic = ttt.concatTopicName(TOPIC_ASK_HELP)
+	s = rospy.Subscriber(topic, Empty, helpCallback)
+
+	topic = ttt.concatTopicName(TOPIC_BOARD_STATE)
+	this.board_service_proxy = rospy.ServiceProxy(topic, Board)
+
+	topic = ttt.concatTopicName(TOPIC_MINIMAX)
+	this.minimax_service_proxy = rospy.ServiceProxy(topic, MiniMax)
+
+
+
+	# Difficulty service to query the current level of difficulty
+	topic = ttt.concatTopicName(TOPIC_DIFFICULTY)
+	this.difficulty_service_proxy = rospy.ServiceProxy(topic, IntInt)
+
+	# Subscriber on the gripper callback invoked each time the gipper concludes an action
+	topic = ttt.concatTopicName(TOPIC_ACTION_CALLBACK)
+	this.gripper_subscriber = rospy.Subscriber(topic, Bool, callbackGripperActionExecuted)
+
+
+	rospy.spin()
+
+if __name__ == '__main__':
+	init_this_node()
diff --git a/scripts/node_main.py b/scripts/node_main.py
new file mode 100755
index 0000000000000000000000000000000000000000..0ee7ecfbb5643ca9361dcb9183acbda84a3abcb6
--- /dev/null
+++ b/scripts/node_main.py
@@ -0,0 +1,113 @@
+#!/usr/bin/env python
+import rospy
+import tic_tac_toe_common as ttt
+from std_msgs.msg import *
+from std_srvs.srv import *
+from socrates_workshop.srv import *
+
+NODE_NAME = "node_main"
+
+
+TOPIC_BOARD_STATE 		= "topic_board_state"
+TOPIC_PERFORM_ACTION 	= "topic_perform_robot_action"
+TOPIC_MINIMAX 			= "topic_minimax_service"
+
+TOPIC_ACTION_CALLBACK 	= "topic_gripper_callback"
+TOPIC_GRIPPER_ACTION 	= "topic_gripper_action"
+
+
+this = sys.modules[__name__]
+
+# Services
+this.action_service			= None
+
+# Service proxies
+this.board_service_proxy 	= None
+this.minimax_service_proxy 	= None
+
+this.gripper_action_publisher = None
+
+# Other variables
+this.gripper_moving 		= False
+
+
+"""
+Helper function to call the minimax service
+"""
+def callMinimax():
+	id_h = ttt.getUserId()
+	id_ai = ttt.getAiId()
+
+	resp = this.board_service_proxy(id_h,id_ai)
+	current_state = resp.board
+
+	depth = 10
+	resp = this.minimax_service_proxy(current_state, depth, id_ai, id_h)
+
+	return resp.action
+
+
+"""
+Callback function for the gripper movement
+"""
+def callbackGripperActionExecuted(msg):
+	success = msg.data
+
+	# The gripper stopped moving
+	this.gripper_moving = False
+	
+
+"""
+Invoked each time service on TOPIC_PERFORM_ACTION is called
+
+"""
+def actionCallback(msg):
+
+	# If gripper is still performing the previous action 
+	# we do nothing
+	if this.gripper_moving:
+		pass
+
+	else:
+		# We set the gripper as moving
+		this.gripper_moving = True
+
+		# We find the correct action to perform
+		action = callMinimax()
+
+		# The action id (between 1 and 9) is published
+		# for the gripper node
+		this.gripper_action_publisher.publish(action)
+
+	return EmptyResponse()
+
+    
+def init_this_node():
+
+	rospy.init_node(NODE_NAME, anonymous=True)
+	
+	# Service that provides the action execution
+	topic = ttt.concatTopicName(TOPIC_PERFORM_ACTION)
+	this.action_service = rospy.Service(topic, Empty, actionCallback)
+
+	# Board service to query the state of the board
+	topic = ttt.concatTopicName(TOPIC_BOARD_STATE)
+	this.board_service_proxy = rospy.ServiceProxy(topic, Board)
+
+	# Minimax service
+	topic = ttt.concatTopicName(TOPIC_MINIMAX)
+	this.minimax_service_proxy = rospy.ServiceProxy(topic, MiniMax)
+
+	# We will publish on the gripper topic the action to execute (actions have ids 1 to 9)
+	topic = ttt.concatTopicName(TOPIC_GRIPPER_ACTION)
+	this.gripper_action_publisher = rospy.Publisher(topic, Int16, queue_size=10)
+
+
+	# Subscriber on the gripper callback invoked each time the gipper concludes an action
+	topic = ttt.concatTopicName(TOPIC_ACTION_CALLBACK)
+	this.gripper_subscriber = rospy.Subscriber(topic, Bool, callbackGripperActionExecuted)
+
+	rospy.spin()
+
+if __name__ == '__main__':
+	init_this_node()
diff --git a/scripts/node_minimax.py b/scripts/node_minimax.py
new file mode 100755
index 0000000000000000000000000000000000000000..49b8aa5c64e8bfae92b7348100b17046d1e0121c
--- /dev/null
+++ b/scripts/node_minimax.py
@@ -0,0 +1,91 @@
+#!/usr/bin/env python
+import rospy
+import tic_tac_toe_common as ttt
+
+from socrates_workshop.srv import *
+
+Inf = +999999
+
+NODE_NAME = 'minimax_server'
+
+
+TOPIC_MINIMAX = "topic_minimax_service"
+
+
+
+def h1(s, player, indeces):
+	return all([s[i] == player for i in indeces])
+
+def h2(s,p):
+	return h1(s,p,[0,1,2]) or h1(s,p,[3,4,5]) or h1(s,p,[6,7,8]) or h1(s,p,[0,3,6]) or h1(s,p,[1,4,7]) or h1(s,p,[2,5,8]) or h1(s,p,[0,4,8]) or h1(s,p,[2,4,6])
+
+
+def getOpponent(player, p1, p2):
+	if player == p1:
+		return p2
+	if player == p2:
+		return p1
+	return 0
+
+def getHeuristicValue(s, player, p1, p2):
+	opp = getOpponent(player, p1, p2)
+	return 10*h2(s, player) + sum(1 for x in range(len(s)) if s[x] == 0) - 10 * h2(s, opp)
+
+
+def isTerminal(s, player, p1, p2):
+	opp = getOpponent(player, p1, p2)
+	return all([cell != 0 for cell in s]) or h2(s, player) or h2(s, opp)
+
+def possibleActions(s, player):
+	return [x+1 for x in range(len(s)) if s[x] == 0]
+
+
+def executeAction(s, action, player):
+	s[action-1] = player
+	return s
+
+def minimax(state, player, p1, p2, depth):
+	selectedAction = None
+	opp = getOpponent(player, p1, p2)
+
+	if isTerminal(state, player, p1, p2) or depth == 0:
+		h = getHeuristicValue(state, p1, p1, p2)
+		return [h, selectedAction]
+
+	if player == p1:
+		alpha = -Inf
+		for action in possibleActions(state, player):
+			s1 = executeAction([x for x in state], action, player)
+			childScore = minimax(s1, opp, p1, p2, depth - 1)[0]
+			if childScore > alpha:
+				alpha = childScore
+				selectedAction = action
+	else:
+		alpha = Inf
+		for action in possibleActions(state, player):
+			s1 = executeAction([x for x in state], action, player)
+			childScore = minimax(s1, opp, p1, p2, depth - 1)[0]
+			if childScore < alpha:
+				alpha = childScore
+				selectedAction = action
+
+	return [alpha, selectedAction]
+
+def handleComputeMiniMax(req):
+	cells = [x for x in req.board]
+	depth = req.max_depth
+	p1 = req.id_player
+	p2 = req.id_opponent
+
+	alpha, selectedAction = minimax(cells, p1, p1, p2, depth)
+
+	return MiniMaxResponse(selectedAction)
+
+def minimaxServer():
+	rospy.init_node(NODE_NAME)
+
+	s = rospy.Service(ttt.concatTopicName(TOPIC_MINIMAX), MiniMax, handleComputeMiniMax)
+	rospy.spin()
+
+if __name__ == "__main__":
+	minimaxServer()
diff --git a/scripts/tic_tac_toe.py b/scripts/tic_tac_toe.py
new file mode 100755
index 0000000000000000000000000000000000000000..82b486ab0798e2ef385c59e6cdc21f2a9994bde0
--- /dev/null
+++ b/scripts/tic_tac_toe.py
@@ -0,0 +1,138 @@
+#!/usr/bin/env python
+
+import rospy
+import os
+import tic_tac_toe_common as ttt
+
+from socrates_workshop.srv import *
+from std_msgs.msg import Bool, Int16
+from std_srvs.srv import Empty
+
+
+
+TOPIC_BOARD_STATE = "topic_board_state"
+TOPIC_PERFORM_ACTION = "topic_perform_robot_action"
+
+TOPIC_GRIPPER_ACTION = "topic_gripper_action"
+TOPIC_ACTION_CALLBACK = "topic_gripper_callback"
+
+clearTerminal = lambda: os.system('clear')
+
+this = sys.modules[__name__]
+
+this.callback_publisher = None
+this.robot_action_proxy = None
+
+this.refreshing = False
+this.board = [0,0,0,0,0,0,0,0,0]
+this.last_move = 0
+
+def h1(s, player, indeces):
+	return all([s[i] == player for i in indeces])
+
+def h2(s,p):
+	return h1(s,p,[0,1,2]) or h1(s,p,[3,4,5]) or h1(s,p,[6,7,8]) or h1(s,p,[0,3,6]) or h1(s,p,[1,4,7]) or h1(s,p,[2,5,8]) or h1(s,p,[0,4,8]) or h1(s,p,[2,4,6])
+
+def gameFinished():
+
+	id_human = ttt.getUserId()
+	id_ai = ttt.getAiId()
+	indeces = [0,1,2,3,4,5,6,7,8]
+
+	s = this.board
+	
+	if h2(s, id_human) or h2(s, id_ai) or all( [s[i] != 0 for i in indeces] ):
+		return True
+	else:
+		return False
+	
+
+def newGame():
+	this.board = [0,0,0,0,0,0,0,0,0]
+	this.last_move = 0
+	return this.board
+
+def getPiece(p):
+	if p == 0:
+		return ' '
+	elif p == 1:
+		return 'X'
+	else:
+		return 'O'
+
+
+def refreshView():
+	if not this.refreshing:
+		this.refreshing = True
+		s = this.board
+		clearTerminal()
+		print "let's play tic tac toe!!"
+		print " %s | %s | %s" % (getPiece(s[0]), getPiece(s[1]), getPiece(s[2])) 
+		print "-----------"
+		print " %s | %s | %s" % (getPiece(s[3]), getPiece(s[4]), getPiece(s[5])) 
+		print "-----------"
+		print " %s | %s | %s" % (getPiece(s[6]), getPiece(s[7]), getPiece(s[8])) 
+		print "Enter your desired piece position in range [1..9]"
+		this.refreshing = False
+
+
+def setPiece(player, position):
+	if this.board[position-1] != 0:
+		return False
+	this.board[position-1] = player
+	this.last_move = player
+	if gameFinished():
+		newGame()
+
+	refreshView()
+	return True
+
+def callbackBoardRequest(req):
+	return BoardResponse(this.board)
+
+def callbackOnGripperAction(msg):
+	action = msg.data
+	setPiece(ttt.getAiId(), action)
+	this.callback_publisher.publish(True)
+	
+
+def tic_tac_toe_node():
+	rospy.init_node("tic_tac_toe")
+
+
+	id_human = ttt.getUserId()
+
+	exit = False
+
+	topic = ttt.concatTopicName(TOPIC_BOARD_STATE)
+	s = rospy.Service(topic, Board, callbackBoardRequest)
+
+	topic = ttt.concatTopicName(TOPIC_GRIPPER_ACTION)
+	s = rospy.Subscriber(topic, Int16, callbackOnGripperAction)
+
+	topic = ttt.concatTopicName(TOPIC_ACTION_CALLBACK)
+	this.callback_publisher = rospy.Publisher(topic, Bool, queue_size=10)
+
+	topic = ttt.concatTopicName(TOPIC_PERFORM_ACTION)
+	this.robot_action_proxy = rospy.ServiceProxy(topic, Empty)
+
+
+	clearTerminal()
+	newGame()
+	while not rospy.is_shutdown() and not exit:
+		refreshView()
+		while this.last_move == id_human:
+			pass
+		user_input = input()
+
+		if user_input not in range(1, 10):
+			exit = True
+
+		if setPiece(id_human, user_input):
+			this.robot_action_proxy()
+
+	print exit
+		
+
+if __name__ == "__main__":
+	tic_tac_toe_node()
diff --git a/scripts/tic_tac_toe_common.py b/scripts/tic_tac_toe_common.py
new file mode 100644
index 0000000000000000000000000000000000000000..d00d7b6fe2b8215c925a460e70d67d05374671b8
--- /dev/null
+++ b/scripts/tic_tac_toe_common.py
@@ -0,0 +1,31 @@
+#!/usr/bin/env python
+
+import rospy
+
+from std_srvs.srv import Empty
+
+PARAM_APPLICATION_NAME = "application_name"
+
+
+PARAM_USER_ID = "param_human_player_id"
+PARAM_AI_ID = "param_ai_player_id"
+
+
+def getApplicationName():
+	return rospy.get_param(PARAM_APPLICATION_NAME)
+
+
+def concatTopicName(topicNameParam):
+	application_name  = getApplicationName()
+
+	topic_name = rospy.get_param(topicNameParam)
+	topic_name = application_name + "/" + topic_name
+
+	return topic_name
+
+def getUserId():
+	return rospy.get_param(PARAM_USER_ID)
+
+def getAiId():
+	return rospy.get_param(PARAM_AI_ID)
+
diff --git a/scripts/tic_tac_toe_common.pyc b/scripts/tic_tac_toe_common.pyc
new file mode 100644
index 0000000000000000000000000000000000000000..8972205a838900ad9964aa1da348081568d95798
Binary files /dev/null and b/scripts/tic_tac_toe_common.pyc differ
diff --git a/srv/Board.srv b/srv/Board.srv
new file mode 100644
index 0000000000000000000000000000000000000000..e28698101ccc759deee12d2c64c4fb2d3b07c1aa
--- /dev/null
+++ b/srv/Board.srv
@@ -0,0 +1,4 @@
+int32 id_human
+int32 id_ai
+---
+int32[] board
diff --git a/srv/IntInt.srv b/srv/IntInt.srv
new file mode 100644
index 0000000000000000000000000000000000000000..71badf76326020cf84e15257e43f3fb7063518ae
--- /dev/null
+++ b/srv/IntInt.srv
@@ -0,0 +1,3 @@
+int32 data
+---
+int32 data
diff --git a/srv/MiniMax.srv b/srv/MiniMax.srv
new file mode 100644
index 0000000000000000000000000000000000000000..1f63c70bff754bb2c120baa8067592d637b1e9c2
--- /dev/null
+++ b/srv/MiniMax.srv
@@ -0,0 +1,6 @@
+int32[] board
+int32 max_depth
+int32 id_player
+int32 id_opponent
+---
+int32 action