LightJason - AgentSpeak(L++)
TestCHanoiTowers.java
Go to the documentation of this file.
1 /*
2  * @cond LICENSE
3  * ######################################################################################
4  * # LGPL License #
5  * # #
6  * # This file is part of the LightJason AgentSpeak(L++) #
7  * # Copyright (c) 2015-19, LightJason (info@lightjason.org) #
8  * # This program is free software: you can redistribute it and/or modify #
9  * # it under the terms of the GNU Lesser General Public License as #
10  * # published by the Free Software Foundation, either version 3 of the #
11  * # License, or (at your option) any later version. #
12  * # #
13  * # This program is distributed in the hope that it will be useful, #
14  * # but WITHOUT ANY WARRANTY; without even the implied warranty of #
15  * # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the #
16  * # GNU Lesser General Public License for more details. #
17  * # #
18  * # You should have received a copy of the GNU Lesser General Public License #
19  * # along with this program. If not, see http://www.gnu.org/licenses/ #
20  * ######################################################################################
21  * @endcond
22  */
23 
24 package org.lightjason.agentspeak.agent;
25 
26 import org.junit.Before;
27 import org.junit.Test;
45 
46 import javax.annotation.Nonnegative;
47 import javax.annotation.Nonnull;
48 import java.io.FileInputStream;
49 import java.io.IOException;
50 import java.io.InputStream;
51 import java.text.MessageFormat;
52 import java.util.Collections;
53 import java.util.List;
54 import java.util.Map;
55 import java.util.Objects;
56 import java.util.Stack;
57 import java.util.concurrent.ConcurrentHashMap;
58 import java.util.concurrent.atomic.AtomicBoolean;
59 import java.util.logging.LogManager;
60 import java.util.stream.Collectors;
61 import java.util.stream.IntStream;
62 import java.util.stream.Stream;
63 
64 import static org.junit.Assert.assertTrue;
65 
66 
71 public final class TestCHanoiTowers extends IBaseTest
72 {
76  private Map<Integer, CAgent> m_agents;
80  private Long m_towernumber;
84  private Long m_slicenumber;
88  private Map<Integer, CTower> m_tower;
92  private AtomicBoolean m_running;
93 
94 
95  static
96  {
97  // disable logger
98  LogManager.getLogManager().reset();
99  }
100 
101 
107  @Before
108  public void initialize() throws Exception
109  {
110  this.setup(
111  1, 3, 3,
112  "src/test/resources/agent/hanoi.asl", Stream.of() );
113  }
114 
115 
121  @Test
122  public void play() throws InterruptedException
123  {
124  this.execute();
125  }
126 
127 
137  private void setup( final int p_agentnumber, final long p_towernumber, final long p_slicenumber,
138  final String p_asl, final Stream<IAction> p_action ) throws Exception
139  {
140  m_towernumber = p_towernumber;
141  m_slicenumber = p_slicenumber;
142  m_running = new AtomicBoolean( true );
143 
144  final Map<Integer, CTower> l_towermap = new ConcurrentHashMap<>();
145  IntStream.range( 0, m_towernumber.intValue() )
146  .forEach( i ->
147  {
148  final CTower l_tower = new CTower();
149  l_towermap.put( i, l_tower );
150  if ( i == 0 )
151  IntStream.range( 0, m_slicenumber.intValue() ).forEach( j -> l_tower.push( new CSlice( m_slicenumber.intValue() - j ) ) );
152  } );
153  m_tower = Collections.unmodifiableMap( l_towermap );
154 
155 
156  final Map<Integer, CAgent> l_agentmap = new ConcurrentHashMap<>();
157  try
158  (
159  final InputStream l_asl = new FileInputStream( p_asl )
160  )
161  {
162  final CGenerator l_generator = new CGenerator( l_asl, p_action );
163  IntStream.range( 0, p_agentnumber )
164  .forEach( i -> l_agentmap.put( i, l_generator.generatesingle( i ) ) );
165  }
166  catch ( final IOException l_exception )
167  {
168  l_exception.printStackTrace();
169  assertTrue( "asl could not be read", true );
170  }
171  m_agents = Collections.unmodifiableMap( l_agentmap );
172  }
173 
174 
175 
179  private void execute()
180  {
181  while ( m_running.get() )
182  {
183  if ( PRINTENABLE )
184  System.out.println( MessageFormat.format( "\ntower configuration: {0}", m_tower ) );
185  m_agents.values()
186  .parallelStream()
187  .forEach( j ->
188  {
189  try
190  {
191  j.call();
192  }
193  catch ( final Exception l_exception )
194  {
195  l_exception.printStackTrace();
196  }
197  } );
198  }
199  }
200 
201 
205  private class CAgent extends IBaseAgent<CAgent>
206  {
210  private static final long serialVersionUID = 9183183177551189228L;
214  private final int m_id;
215 
222  CAgent( final IAgentConfiguration<CAgent> p_configuration, final int p_id )
223  {
224  super( p_configuration );
225  m_id = p_id;
226  }
227 
233  final int id()
234  {
235  return m_id;
236  }
237  }
238 
239 
246  private final class CGenerator extends IBaseAgentGenerator<CAgent>
247  {
248 
256  CGenerator( final InputStream p_stream, final Stream<IAction> p_action ) throws Exception
257  {
258  super(
259  p_stream,
260  Stream.concat(
261  Stream.concat(
262  Stream.of(
263  new CTowerPush( 0.33 ),
264  new CTowerPop(),
265  new CTowerSize(),
266  new CStop()
267  ),
268  Stream.concat(
269  p_action,
270  PRINTENABLE ? Stream.of() : Stream.of( new CEmptyPrint() )
271  )
272  ),
274  ).collect( Collectors.toSet() ),
275  Collections.emptySet(),
276  new IVariableBuilder()
277  {
278  @Override
279  public final Stream<IVariable<?>> apply( final IAgent<?> p_agent, final IInstantiable p_instantiable
280  )
281  {
282  return Stream.of(
283  new CConstant<>( "MyID", p_agent.<CAgent>raw().id() ),
284  new CConstant<>( "TowerCount", TestCHanoiTowers.this.m_towernumber ),
285  new CConstant<>( "TowerMaxIndex", TestCHanoiTowers.this.m_towernumber - 1 ),
286  new CConstant<>( "SliceCount", TestCHanoiTowers.this.m_slicenumber )
287  );
288  }
289  }
290  );
291  }
292 
293  @Override
294  @SuppressWarnings( "unchecked" )
295  public final CAgent generatesingle( final Object... p_data )
296  {
297  return new CAgent( m_configuration, (int) p_data[0] );
298  }
299  }
300 
304  private static final class CEmptyPrint extends IBaseAction
305  {
309  private static final long serialVersionUID = 3623170719805419082L;
310 
311  @Nonnull
312  @Override
313  public final IPath name()
314  {
315  return CPath.from( "generic/print" );
316  }
317 
318  @Nonnegative
319  @Override
320  public final int minimalArgumentNumber()
321  {
322  return 0;
323  }
324 
325  @Nonnull
326  @Override
327  public final IFuzzyValue<Boolean> execute( final boolean p_parallel, @Nonnull final IContext p_context,
328  @Nonnull final List<ITerm> p_argument, @Nonnull final List<ITerm> p_return )
329  {
330  return CFuzzyValue.from( true );
331  }
332  }
333 
337  private final class CStop extends IBaseAction
338  {
342  private static final long serialVersionUID = 1356103671899402899L;
343 
344  @Nonnull
345  @Override
346  public final IPath name()
347  {
348  return CPath.from( "stop" );
349  }
350 
351  @Nonnegative
352  @Override
353  public final int minimalArgumentNumber()
354  {
355  return 0;
356  }
357 
358  @Nonnull
359  @Override
360  public final IFuzzyValue<Boolean> execute( final boolean p_parallel, @Nonnull final IContext p_context,
361  @Nonnull final List<ITerm> p_argument, @Nonnull final List<ITerm> p_return
362  )
363  {
364  m_running.set( false );
365  return CFuzzyValue.from( true );
366  }
367  }
368 
369 
373  private final class CTowerSize extends IBaseAction
374  {
378  private static final long serialVersionUID = -621010269747370196L;
379 
380  @Nonnull
381  @Override
382  public final IPath name()
383  {
384  return CPath.from( "tower/size" );
385  }
386 
387  @Nonnegative
388  @Override
389  public final int minimalArgumentNumber()
390  {
391  return 1;
392  }
393 
394  @Nonnull
395  @Override
396  public final IFuzzyValue<Boolean> execute( final boolean p_parallel, @Nonnull final IContext p_context,
397  @Nonnull final List<ITerm> p_argument, @Nonnull final List<ITerm> p_return )
398  {
399  final CTower l_tower = m_tower.get( p_argument.get( 0 ).<Number>raw().intValue() );
400  if ( Objects.isNull( l_tower ) )
401  return CFuzzyValue.from( false );
402 
403  p_return.add( CRawTerm.from( l_tower.size() ) );
404  return CFuzzyValue.from( true );
405  }
406  }
407 
408 
412  private final class CTowerPush extends IBaseAction
413  {
417  private static final long serialVersionUID = -3816901920109893840L;
421  private final double m_failprobability;
422 
428  CTowerPush( final double p_failprobability )
429  {
430  m_failprobability = p_failprobability;
431  }
432 
433  @Nonnull
434  @Override
435  public final IPath name()
436  {
437  return CPath.from( "tower/push" );
438  }
439 
440  @Nonnegative
441  @Override
442  public final int minimalArgumentNumber()
443  {
444  return 2;
445  }
446 
447  @Nonnull
448  @Override
449  public final IFuzzyValue<Boolean> execute( final boolean p_parallel, @Nonnull final IContext p_context,
450  @Nonnull final List<ITerm> p_argument, @Nonnull final List<ITerm> p_return )
451  {
452  final CTower l_tower = m_tower.get( p_argument.get( 0 ).<Number>raw().intValue() );
453  if ( ( Objects.isNull( l_tower ) ) || ( Math.random() < m_failprobability ) )
454  return CFuzzyValue.from( false );
455 
456  try
457  {
458  l_tower.push( p_argument.get( 1 ).<CSlice>raw() );
459  return CFuzzyValue.from( true );
460  }
461  catch ( final IllegalStateException l_exception )
462  {
463  return CFuzzyValue.from( false );
464  }
465  }
466  }
467 
471  private final class CTowerPop extends IBaseAction
472  {
476  private static final long serialVersionUID = 7757699013244193313L;
477 
478  @Nonnull
479  @Override
480  public final IPath name()
481  {
482  return CPath.from( "tower/pop" );
483  }
484 
485  @Nonnegative
486  @Override
487  public final int minimalArgumentNumber()
488  {
489  return 1;
490  }
491 
492  @Nonnull
493  @Override
494  public final IFuzzyValue<Boolean> execute( final boolean p_parallel, @Nonnull final IContext p_context,
495  @Nonnull final List<ITerm> p_argument, @Nonnull final List<ITerm> p_return )
496  {
497  final CTower l_tower = m_tower.get( p_argument.get( 0 ).<Number>raw().intValue() );
498  if ( Objects.isNull( l_tower ) )
499  return CFuzzyValue.from( false );
500 
501  try
502  {
503  p_return.add( CRawTerm.from( l_tower.pop() ) );
504  return CFuzzyValue.from( true );
505  }
506  catch ( final IllegalStateException l_exception )
507  {
508  return CFuzzyValue.from( false );
509  }
510  }
511  }
512 
513 
517  private static final class CSlice
518  {
522  private final int m_size;
523 
529  CSlice( final int p_size )
530  {
531  m_size = p_size;
532  }
533 
534  @Override
535  public String toString()
536  {
537  return MessageFormat.format( "slice {0}", m_size );
538  }
539 
545  final int size()
546  {
547  return m_size;
548  }
549  }
550 
554  private static final class CTower extends Stack<CSlice>
555  {
559  private static final transient long serialVersionUID = 1361367629042813689L;
560 
561  @Override
562  public final synchronized CSlice push( final CSlice p_item )
563  {
564  if ( ( this.size() > 0 ) && ( this.peek().size() < p_item.size() ) )
565  throw new IllegalStateException();
566 
567  return super.push( p_item );
568  }
569 
570  @Override
571  public final synchronized CSlice pop()
572  {
573  if ( this.isEmpty() )
574  throw new IllegalStateException();
575 
576  return super.pop();
577  }
578 
579  @Override
580  public final synchronized CSlice peek()
581  {
582  return super.peek();
583  }
584 
585  @Override
586  public final synchronized boolean empty()
587  {
588  return super.empty();
589  }
590 
591  @Override
592  public final synchronized int search( final Object p_object )
593  {
594  return super.search( p_object );
595  }
596  }
597 
598 }
void setup(final int p_agentnumber, final long p_towernumber, final long p_slicenumber, final String p_asl, final Stream< IAction > p_action)
initialize call
final IPath name()
returns the name with path of the action
default implementation of an action
base test class with helpers
Definition: IBaseTest.java:33
final synchronized int search(final Object p_object)
CAgent(final IAgentConfiguration< CAgent > p_configuration, final int p_id)
ctor
final int minimalArgumentNumber()
minimum number of arguments
static< N > IFuzzyValue< N > from( @Nonnull final N p_value)
factory
interface for (instantiable) plans and logical-rules
abstract test for playing towers of hanoi If a file agentprintin.conf exists on the main directory al...
static IPath from( @Nonnull final String p_string)
factor method to build path
Definition: CPath.java:166
class to create a path structure
Definition: CPath.java:53
final int minimalArgumentNumber()
minimum number of arguments
final IFuzzyValue< Boolean > execute(final boolean p_parallel, @Nonnull final IContext p_context, @Nonnull final List< ITerm > p_argument, @Nonnull final List< ITerm > p_return)
defines a plan-body operation
final IFuzzyValue< Boolean > execute(final boolean p_parallel, @Nonnull final IContext p_context, @Nonnull final List< ITerm > p_argument, @Nonnull final List< ITerm > p_return)
defines a plan-body operation
execution context with local data
Definition: IContext.java:42
external action interface
Definition: IAction.java:38
final IFuzzyValue< Boolean > execute(final boolean p_parallel, @Nonnull final IContext p_context, @Nonnull final List< ITerm > p_argument, @Nonnull final List< ITerm > p_return)
defines a plan-body operation
CGenerator(final InputStream p_stream, final Stream< IAction > p_action)
ctor
static final boolean PRINTENABLE
enable printing of test-data
Definition: IBaseTest.java:38
final int minimalArgumentNumber()
minimum number of arguments
static Stream< IAction > actionsFromPackage( @Nullable final String... p_package)
get all classes within an Java package as action
final int minimalArgumentNumber()
minimum number of arguments
final double m_failprobability
probability for action failing
final IPath name()
returns the name with path of the action
result for an immutable fuzzy value
final IFuzzyValue< Boolean > execute(final boolean p_parallel, @Nonnull final IContext p_context, @Nonnull final List< ITerm > p_argument, @Nonnull final List< ITerm > p_return)
defines a plan-body operation
interface for a variable builder which is called on each plan / rule execution
final int minimalArgumentNumber()
minimum number of arguments
static< N > CRawTerm< N > from(final N p_value)
factory for a raw term
Definition: CRawTerm.java:104
final IPath name()
returns the name with path of the action
final IPath name()
returns the name with path of the action
final IFuzzyValue< Boolean > execute(final boolean p_parallel, @Nonnull final IContext p_context, @Nonnull final List< ITerm > p_argument, @Nonnull final List< ITerm > p_return)
defines a plan-body operation
AtomicBoolean m_running
running flag (agent can disable execution)
final IPath name()
returns the name with path of the action
term structure for simple datatypes
Definition: CRawTerm.java:45
final synchronized CSlice push(final CSlice p_item)